mLocationManager
オブジェクトの下のコードを一見すると、onCreate(...)
の終了後にスコープ外になるはずです。予想される動作は、onLocationChanged
が呼び出されたり呼び出されたりしないことです。オブジェクトがガベージコレクションされるまでの時間。ただし、getSystemService
によって返されるオブジェクトは、MainActivity
のスコープ外にあるシングルトンのようです(システムサービスであるため、適切に:))
ヒープダンプを取得してEclipse Memory Analyzerで処理した後、ContextImplがLocationManagerインスタンスへの参照を保持しているようです。メモリダンプでは、LocationManagerオブジェクトへの参照が2つありましたが、コードでは明らかに1つしかありません。つまり、別の参照が別の場所に作成されています。
私の質問は:
誰かが次の実装を呼び出すときに正確に何が起こっているかについての完全な説明がありますか?
_public abstract Object getSystemService(String name);
_
オブジェクトは遅延して作成されたシングルトンを返し、どこに参照が作成/保持されますか?
_package com.neusoft.bump.client.storage;
import Android.location.Location;
import Android.location.LocationListener;
import Android.location.LocationManager;
import Android.os.Bundle;
import Android.app.Activity;
import Android.content.Context;
import Android.util.Log;
import Android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("TAG", "STARTED");
LocationManager mLocationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
Log.v("TAG", "onLocationChanged");
Log.v("TAG", "Latitude: " + location.getLatitude()
+ "Longitude: " + location.getLongitude());
}
public void onStatusChanged(String provider, int status,
Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location
// updates
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
600, 0, locationListener);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
_
pdate1
LocationManager
はシングルトンとして作成されます
_private LocationManager getLocationManager() {
synchronized (sSync) {
if (sLocationManager == null) {
IBinder b = ServiceManager.getService(LOCATION_SERVICE);
ILocationManager service = ILocationManager.Stub.asInterface(b);
sLocationManager = new LocationManager(service);
}
}
return sLocationManager;
}
_
しかし、ServiceManager
コードを読んだ後でも、ServiceManager.getService(LOCATION_SERVICE);
を呼び出すとどうなるか理解できません。
私の議論が理にかなっているかどうかを確認してください...
読者の一人が示唆したように、私はここに記事の一部をコピーしようとしています。
アプリがPOWER MANAGERやACTIVITY MANAGERやLOCATION MANAGERなどのシステムサービスやこれらのような他のいくつかのシステムサービスをどのように取得するのか疑問に思ったことはありませんか。 Androidのソースコードを調べて、これが内部でどのように行われているかを確認しました。アプリケーション側のJavaコードから始めましょう。
アプリケーション側では、関数getService
を呼び出し、システムサービスのID(POWER_SERVICEなど)を渡して、サービスへのハンドルを取得する必要があります。
/frameworks/base/core/Java/Android/os/ServiceManager.Javaで定義されているgetService
のコードは次のとおりです
_ /**
44 * Returns a reference to a service with the given name.
45 *
46 * @param name the name of the service to get
47 * @return a reference to the service, or <code>null</code> if the service doesn't exist
48 */
49 public static IBinder getService(String name) {
50 try {
51 IBinder service = sCache.get(name);
52 if (service != null) {
53 return service;
54 } else {
55 return getIServiceManager().getService(name);
56 }
57 } catch (RemoteException e) {
58 Log.e(TAG, "error in getService", e);
59 }
60 return null;
61 }
_
キャッシュにサービスがないとします。したがって、55行に集中する必要がありますreturn getIServiceManager().getService(name);
この呼び出しは実際にサービスマネージャーへのハンドルを取得し、パラメーターとして渡した名前を持つサービスの参照を返すように要求します。
ここで、getIServiceManager()
関数がServiceManagerにハンドルを返す方法を見てみましょう。
/frameworks/base/core/Java/Android/os/ServiceManager.JavaのgetIserviceManager()のコードは次のとおりです
_private static IServiceManager getIServiceManager() {
34 if (sServiceManager != null) {
35 return sServiceManager;
36 }
37
38 // Find the service manager
39 sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
40 return sServiceManager;
41 }
_
ServicemanagerNative.asInterface()は次のようになります。
_/**
28 * Cast a Binder object into a service manager interface, generating
29 * a proxy if needed.
30 */
31 static public IServiceManager asInterface(IBinder obj)
32 {
33 if (obj == null) {
34 return null;
35 }
36 IServiceManager in =
37 (IServiceManager)obj.queryLocalInterface(descriptor);
38 if (in != null) {
39 return in;
40 }
41
42 return new ServiceManagerProxy(obj);
43 }
_
したがって、基本的にはネイティブのservicemanagerへのハンドルを取得しています。
このasInterface関数は、実際には、それぞれIserviceManager.hおよびIServiceManager.cppで定義されている2つのマクロDECLARE_META_INTERFACE(ServiceManager)
およびIMPLEMENT_META_INTERFACE(ServiceManager, "Android.os.IServiceManager");
の中に埋め込まれています。
/frameworks/base/include/binder/IInterface.hで定義されている2つのマクロを詳しく見てみましょう
DECLARE_META_INTERFACE(ServiceManager)
マクロは次のように定義されます
_// ----------------------------------------------------------------------
73
74#define DECLARE_META_INTERFACE(INTERFACE) \
75 static const Android::String16 descriptor; \
76 static Android::sp<I##INTERFACE> asInterface( \
77 const Android::sp<Android::IBinder>& obj); \
78 virtual const Android::String16& getInterfaceDescriptor() const; \
79 I##INTERFACE(); \
80 virtual ~I##INTERFACE(); \
_
また、IMPLEMENT_META_INTERFACE(ServiceManager, "Android.os.IServiceManager");
は次のように定義されています。
_#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
84 const Android::String16 I##INTERFACE::descriptor(NAME); \
85 const Android::String16& \
86 I##INTERFACE::getInterfaceDescriptor() const { \
87 return I##INTERFACE::descriptor; \
88 } \
89 Android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
90 const Android::sp<Android::IBinder>& obj) \
91 { \
92 Android::sp<I##INTERFACE> intr; \
93 if (obj != NULL) { \
94 intr = static_cast<I##INTERFACE*>( \
95 obj->queryLocalInterface( \
96 I##INTERFACE::descriptor).get()); \
97 if (intr == NULL) { \
98 intr = new Bp##INTERFACE(obj); \
99 } \
100 } \
101 return intr; \
102 } \
103 I##INTERFACE::I##INTERFACE() { } \
104 I##INTERFACE::~I##INTERFACE() { }
_
したがって、IServiceManager.hとIServiceManager.cppファイルのこれら2つのマクロを適切な置換パラメーターに置き換えて展開すると、次のようになります。
_class IServiceManager : public IInterface
{
public:
static const Android::String16 descriptor;
static Android::sp<IServiceManager> asInterface( const Android::sp<Android::IBinder>& obj);
virtual const Android::String16& getInterfaceDescriptor() const;
IServicemanager();
virtual ~IServiceManager();
…......
….....
…...
…..
_
そしてIServiceManager.cpp
_const Android::String16 IServiceManager::descriptor("Android.os.IServiceManager”);
const Android::String16&
IServiceManager::getInterfaceDescriptor() const {
return IServiceManager::descriptor;
}
Android::sp<IServiceManager> IServiceManager::asInterface(
const Android::sp<Android::IBinder>& obj)
{
Android::sp< IServiceManager> intr;
if (obj != NULL) {
intr = static_cast<IServiceManager*>(
obj->queryLocalInterface(
IServiceManager::descriptor).get());
if (intr == NULL) {
intr = new BpServiceManager(obj);
}
}
return intr;
}
IServiceManager::IServiceManager() { }
IServiceManager::~IIServiceManager { }
_
したがって、サービスマネージャーが起動して実行されているかどうかを示す12行目が表示された場合(サービスマネージャーがAndroid起動中に)initプロセスで起動したため)への参照が返されますqueryLocalinterface関数を使用すると、Javaインターフェースに到達します。
_public IBinder getService(String name) throws RemoteException {
116 Parcel data = Parcel.obtain();
117 Parcel reply = Parcel.obtain();
118 data.writeInterfaceToken(IServiceManager.descriptor);
119 data.writeString(name);
120 mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
121 IBinder binder = reply.readStrongBinder();
122 reply.recycle();
123 data.recycle();
124 return binder;
125 }
_
serviceManagerNative.Javaから。この関数では、探しているサービスを渡します。
また、リモートスタブのGET_SERVICE_TRANSACTIONのonTransact関数は次のようになります。
_public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
51 {
52 try {
53 switch (code) {
54 case IServiceManager.GET_SERVICE_TRANSACTION: {
55 data.enforceInterface(IServiceManager.descriptor);
56 String name = data.readString();
57 IBinder service = getService(name);
58 reply.writeStrongBinder(service);
59 return true;
60 }
61
62 case IServiceManager.CHECK_SERVICE_TRANSACTION: {
63 data.enforceInterface(IServiceManager.descriptor);
64 String name = data.readString();
65 IBinder service = checkService(name);
66 reply.writeStrongBinder(service);
67 return true;
68 }
69
//Rest has been discarded for brevity…………………..
………………….
………………….
…………………
_
関数getServiceを介して、必要なサービスへの参照を返します。 /frameworks/base/libs/binder/IServiceManager.cppのgetService関数は次のようになります。
_ virtual sp<IBinder> getService(const String16& name) const
134 {
135 unsigned n;
136 for (n = 0; n < 5; n++){
137 sp<IBinder> svc = checkService(name);
138 if (svc != NULL) return svc;
139 LOGI("Waiting for service %s...\n", String8(name).string());
140 sleep(1);
141 }
142 return NULL;
143 }
_
そのため、実際にはサービスが利用可能かどうかを確認し、サービスへの参照を返します。ここで、IBinderオブジェクトへの参照を返すときに、他のデータ型とは異なり、クライアントのアドレス空間にコピーされないことを追加したいと思いますが、実際には、クライアントを通じて共有されるIBinderオブジェクトの同じ参照です。バインダードライバーでオブジェクトマッピングと呼ばれる特別な手法。
ディスカッションに詳細を追加するために、もう少し詳しく説明します。
CheckService関数は次のようになります。
_virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
_
そのため、実際にはリモートサービスを呼び出して、CHECK_SERVICE_TRANSACTIONコード(enum値は2)を渡します。
このリモートサービスは、実際にはframeworks/base/cmds/servicemanager/service_manager.cに実装されており、onTransactは次のようになります。
_switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
ptr = do_find_service(bs, s, len);
if (!ptr)
break;
bio_put_ref(reply, ptr);
return 0;
_
したがって、サービスへの参照を取得してそれを返すdo_find_serviceという名前の関数を呼び出すことになります。
同じファイルのdo_find_serviceは次のようになります。
_void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
{
struct svcinfo *si;
si = find_svc(s, len);
// ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
if (si && si->ptr) {
return si->ptr;
} else {
return 0;
}
_
find_svcは次のようになります。
_struct svcinfo *find_svc(uint16_t *s16, unsigned len)
{
struct svcinfo *si;
for (si = svclist; si; si = si->next) {
if ((len == si->len) &&
!memcmp(s16, si->name, len * sizeof(uint16_t))) {
return si;
}
}
return 0;
}
_
Svclistを通過し、探しているサービスを返すことが明らかになったとき。
serviceManager.getService(LOCATION_SERVICE)を呼び出すとどうなるか理解できません。 ServiceManagerコードを読んだ後でも。
さて、これが ServiceManager.Java のgetService()のソースコードです。
_public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
_
ご覧のとおり、要求されたサービスがまだキャッシュされていない場合、これはgetIServiceManager().getService(name)
を呼び出します。 getIServiceManager()は同じクラスのメソッドです(次のステップでgetService(name)に移動します):
_private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
_
したがって、これは基本的に ServiceManagerNative.Java に送信し、ここでgetService(name)を探す必要があります。
_public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
_
これにより、「LOCATION_SERVICE」という名前のサービスを取得するためのトランザクションが開始されます。
システムサービスなどの低レベルのものを扱うクラスとインターフェースの複雑な構造のため、ここからの移動が難しくなっています。ただし、基本的にはすべてContext.Java、ContextImpl.Java、ServiceManager.Java、ServiceManagerNative.Javaで行われます。また、それらの一部はローカルキャッシュまたはサービスインスタンスへの参照を含むマップを保持する可能性があることにも注意してください(つまり、上記のServiceManager.JavaリストでsCache.get(name)
を確認できます)。ここで追加の参照が行われます。
StackOverflowでは非常に低レベルになるため、ここでより詳細な回答が得られるとは思いません。 Android OSメーリングリストにgoogle従業員が含まれているような場所で質問したい場合があります。
メソッドgetSystemService
public abstract Object getSystemService(String name);
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
SYSTEM_SERVICE_MAPは次のとおりです。
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
new HashMap<String, ServiceFetcher>();
そして、すべてのサービスは静的ブロックに登録されています
static {
次のように、registerServiceを呼び出します。
registerService(LOCATION_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(LOCATION_SERVICE);
return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
}});
または
registerService(INPUT_SERVICE, new StaticServiceFetcher() {
public Object createStaticService() {
return InputManager.getInstance();
}});
ServiceFetcherとStaticServiceFetcherは遅延読み込みパターンを実装します。
ほとんどのシステムサービス/マネージャーは、ブートプロセスの初期段階で作成されるため、ロケーションマネージャー。
app_processは、DalvikVMを起動するネイティブコンポーネントです。さらに、ZigoteInit(実際の作業を行うクラス)にSystemServerを起動するように指示します。ここに、LocationManagerの最初のインスタンスが作成され、参照がその中のServerThreadに保持されます。
/frameworks/base/services/Java/com/Android/server/SystemServer.Java
DevicePolicyManagerService devicePolicy = null;
StatusBarManagerService statusBar = null;
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
NotificationManagerService notification = null;
WallpaperManagerService wallpaper = null;
-> LocationManagerService location = null;
CountryDetectorService countryDetector = null;
TextServicesManagerService tsms = null;
LockSettingsService lockSettings = null;
DreamManagerService dreamy = null;
try {
Slog.i(TAG, "Location Manager");
location = new LocationManagerService(context);
ServiceManager.addService(Context.LOCATION_SERVICE, location);
} catch (Throwable e) {
reportWtf("starting Location Manager", e);
}
残りはすでに知っていると思います。