Как работает getSystemService ()?

на первый взгляд в коде ниже mLocationManager объект должен выйти из области видимости после onCreate(...) закончено, и ожидаемое поведение-это onLocationChanged никогда не вызывается или вызывается несколько раз, пока объект не будет собран мусор. Однако объект, возвращаемый getSystemService кажется, синглтон, который живет за пределами MainActivity (соответственно, так как это системная служба :))

после взятия дампа кучи и прохождения его с помощью анализатора памяти Eclipse кажется, что 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 создается как singleton

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.getService(LOCATION_SERVICE); даже после прочтения ServiceManager код.

4 ответов


посмотрите, имеет ли смысл мое обсуждение...

рассечение внутренней службы android

как предложил один из читателей, я пытаюсь скопировать некоторую часть записи здесь.

вы когда-нибудь задумывались, как приложение получает дескриптор системных служб, таких как POWER MANAGER или ACTIVITY MANAGER или LOCATION MANAGER и несколько других подобных. Чтобы узнать, что я покопался в исходном коде Android и выяснил, как это делается внутренне. Поэтому позвольте мне начать с java-кода стороны приложения.

на стороне приложения мы должны вызвать функцию getService и передайте идентификатор системной службы (скажем, POWER_SERVICE), чтобы получить дескриптор службы.

здесь код getService определено в / Framework/base/core/java/android/os / ServiceManager.java

    /**
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.

вот код getIserviceManager () из /Framework/base/core/java/android/os/ServiceManager.java

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 фактически похоронена внутри двух макросов DECLARE_META_INTERFACE(ServiceManager) и IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); определено в IserviceManager.h И IServiceManager.НКЛ соответственно.

позволяет углубиться в два макросов, определенных в / Framework/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), он возвращает ссылка на него через функцию 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.Ява. В этой функции мы передаем услугу, которую мы ищем.

и функция onTransact для GET_SERVICE_TRANSACTION на удаленном заглушке выглядит следующим образом:

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. Функция getService от /базы/базы/библиотеки/Биндер/IServiceManager.СРР выглядит следующим образом:

  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 (его значение перечисления 2).

эта удаленная служба фактически реализована в Framework/base/cmds/servicemanager / service_manager.с и его 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.

Ok, вот исходный код 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 () - это метод в том же классе(мы будем het для 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 (имя):

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".

это становится все труднее двигаться отсюда из-за сложной структуры классов и интерфейсов, которые имеют дело с низкоуровневыми вещами, как системы услуг. Но в основном все это делается в контексте.java, ContextImpl.Ява, Элемент ServiceManager.java и ServiceManagerNative.Ява. Также обратите внимание, что некоторые из них могут хранить локальные кэши или карты со ссылками на экземпляры службы (т. е. вы можете увидеть sCache.get(name) в окне ServiceManager.Java листинг выше), это где дополнительные ссылки могут исходить из.

Я не думаю, что вы получите более подробный ответ здесь, на StackOverflow, потому что он становится очень низким уровнем. Вы можете спросить где-то, как в списке рассылки ОС Android, в котором есть сотрудники google он.


диспетчер местоположений, так как большинство системных служб/менеджеров создается на ранней стадии процесса загрузки.

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);
}

остальное вам уже известно, я думать.


метод 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 реализует шаблон ленивой загрузки.