getSystemService()的工作原理是什么?

27
乍一看下面的代码中,mLocationManager 对象应该在 onCreate(...) 结束后超出作用域,预期的行为是 onLocationChanged 没有被调用或只被调用几次,直到对象被垃圾回收。然而,getSystemService 返回的对象似乎是单例,在 MainActivity 的作用域之外存在(因为它是一个系统服务 :))
通过进行堆转储并使用 Eclipse Memory Analyzer 进行分析,发现 ContextImpl 保留了对 LocationManager 实例的引用。在内存转储中,有两个对 LocationManager 对象的引用,而在代码中显然只有一个,这意味着另一个引用在其他地方被创建。
我的问题是:
有人能否完整描述调用以下实现时究竟发生了什么:
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;
    }
}

更新1

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);时会发生什么。


我认为只要您不调用LocationManager.removeUpdates()LocationManager将保留对LocationListener的引用,而且您的LocationListener将引用您的Activity - nicopico
关于作用域的同样事情也适用于在“onCreate(...)”方法内创建的LocationListener对象。一旦该方法完成,它就会超出范围,除非从其他地方引用它(在这种情况下是LocationManager对象)。此外,如果LocationManager对象没有从其他地方引用,它们两者都将在某个时候被垃圾回收。我还测试了为LocationListener创建静态内部类(以测试您的假设),行为类似。 - Vasile Jureschi
有没有人能提供一个完整的描述,解释在调用实现时确切发生了什么 -- 当你阅读源代码时,你学到了什么? - CommonsWare
@CommonsWare 请查看问题的更新1。 - Vasile Jureschi
非常有趣 - 如果您已经查看了代码/邮件列表,请发布答案并回复我的评论 :) - Mr_and_Mrs_D
4个回答

56

看看我的讨论是否有意义...

Android服务内部解剖

正如一位读者建议的那样,我正在尝试在此处复制一些文章内容。

你是否曾经想过应用程序如何获取系统服务的句柄,例如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    }

基本上,我们正在获取对本地服务管理器的控制权。这个asInterface函数实际上是隐藏在两个宏中DECLARE_META_INTERFACE(ServiceManager)IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");中,分别在IserviceManager.h和IServiceManager.cpp中定义。
让我们深入研究/frameworks/base/include/binder/IInterface.h中定义的这两个宏。 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文件中这两个宏替换为适当的替换参数,它们将如下所示:

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 文件。在这个函数中,我们传递我们所寻找的服务。

远程存根(remote stub)上 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对象的引用时,与其他数据类型不同,它不会在客户端的地址空间中复制,而是通过Binder驱动程序中的特殊技术称为对象映射共享给客户端的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代码(它是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遍历并返回我们正在寻找的服务。

干得好。添加源链接并解释一些要点,例如1. Java中的服务是否返回单例,2. 传递的上下文是否存储在某个地方,这将使答案更加完美。 - Mr_and_Mrs_D

6
我阅读了ServiceManager的代码,但仍然无法理解调用ServiceManager.getService(LOCATION_SERVICE)会发生什么。
好的,下面是getService()的源代码:ServiceManager.java
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上你不会得到更详细的答案,因为它变得非常低级别。你可能想在一个拥有Google雇员的Android操作系统邮件列表等地方提出问题。

我实际上对底层细节很感兴趣,所以我应该前往Android操作系统邮件列表 :) - Vasile Jureschi

2

Method getSystemService

public abstract Object getSystemService(String name);

实现在https://android.googlesource.com/platform/frameworks/base/+/android-5.0.2_r1/core/java/android/app/ContextImpl.java

@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 实现了懒加载模式。


2
地理位置管理器(Location Manager)与大多数系统服务/管理器一样,在启动过程的早期阶段创建。
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);
}

其他的你已经知道了,我想。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接