Подтвердить что ты не робот

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

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

После того, как вы взяли кучу кучи и пропустили его с помощью Eclipse Memory Analyzer, похоже, что ContextImpl хранит ссылку на экземпляр LocationManager. В дампе памяти были две ссылки на объект LocationManager, тогда как в коде есть только одно, что означает, что другая ссылка создается где-то в другом месте.

Мои вопросы:

Есть ли у кого-то полное описание того, что именно происходит при вызове реализации:

public abstract Object getSystemService(String name);

является ли объект возвращенным singleton lazily created и где именно ссылка создана/сохранена?

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

Update1

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.

4b9b3361

Ответ 1

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

вскрытие внутренней службы Android

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

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

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

Вот код для getService, определенный в /frameworks/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() из /frameworks/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.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, которая показывает, запущен и запущен Service Manager (и это должно произойти из-за того, что диспетчер сервисов запускается в процессе инициализации во время загрузки 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.java. В этой функции мы передаем сервис, который мы ищем.

И функция 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 из /frameworks/base/libs/binder/IServiceManager.cpp выглядит следующим образом:

  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, которая совместно используется клиентом через специальная техника, называемая отображением объектов в драйвере Binder.

Чтобы добавить более подробную информацию к обсуждению, позвольте мне углубиться в нее.

Функция 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).

Эта удаленная служба фактически реализована в рамках /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 и возвращает службу, которую мы ищем.

Ответ 2

но я не понимаю, что происходит при вызове ServiceManager.getService(LOCATION_SERVICE); даже после чтения кода ServiceManager.

Итак, вот исходный код 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 (имя) на следующем шаге):

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Надеюсь, что это поможет.