2013-02-28 14 views
22

Thoạt nhìn trong mã bên dưới các đối tượng mLocationManager nên đi ra khỏi phạm vi sau khi hoàn thành onCreate(...) và hành vi mong đợi là onLocationChanged không bao giờ được gọi hoặc gọi một vài lần cho đến khi đối tượng bị thu gom rác. Tuy nhiên đối tượng quay trở lại bởi getSystemService dường như là singleton sống bên ngoài phạm vi của MainActivity (một cách thích hợp vì nó là một dịch vụ hệ thống :))Làm thế nào để getSystemService() hoạt động chính xác?

Sau khi lấy một đống và đi qua nó với bộ phân tích bộ nhớ Eclipse có vẻ như ContextImpl giữ một tham chiếu đến một cá thể LocationManager. Trong bãi chứa bộ nhớ có hai tham chiếu đến một đối tượng LocationManager trong khi trong mã có rõ ràng chỉ có một, có nghĩa là một tài liệu tham khảo khác được tạo ra ở một nơi khác.

Câu hỏi của tôi là:

Liệu ai đó có một mô tả đầy đủ về những gì là chính xác xảy ra khi gọi thực hiện:

public abstract Object getSystemService(String name); 

là đối tượng quay trở lại một singleton uể oải tạo và ở đâu chính xác là tài liệu tham khảo đã tạo/lưu giữ?

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

Các LocationManager được tạo ra như 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; 
} 

nhưng tôi gặp khó khăn khi tìm hiểu những gì xảy ra khi gọi ServiceManager.getService(LOCATION_SERVICE); thậm chí sau khi đọc mã ServiceManager.

+0

Tôi nghĩ 'LocationManager' giữ tham chiếu đến' LocationListener' của bạn miễn là bạn không gọi 'LocationManager.removeUpdates() 'và' LocationListener' của bạn có tham chiếu đến 'Hoạt động' – nicopico

+0

Điều tương tự về phạm vi nên áp dụng cho đối tượng LocationListener được tạo bên trong phương thức 'onCreate (...)'. Ngay sau khi phương thức kết thúc, nó sẽ nằm ngoài phạm vi trừ khi có một tham chiếu đến nó từ một nơi khác (trong trường hợp này là đối tượng LocationManager). Hơn nữa nếu đối tượng LocationManager không được tham chiếu từ một nơi nào khác, cả hai đối tượng này đều đã bị thu gom rác tại một số điểm. Tôi cũng đã thử nghiệm tạo một lớp bên trong tĩnh cho LocationListener (để kiểm tra giả thuyết của bạn) và hành vi tương tự. –

+0

"Người nào đó có mô tả đầy đủ về những gì chính xác xảy ra khi gọi triển khai" - khi bạn đọc mã nguồn, bạn đã học được gì? – CommonsWare

Trả lời

43

Xem nếu cuộc thảo luận của tôi có ý nghĩa ...

dissection of android service internal

Theo đề nghị của một trong những độc giả Tôi cố gắng để sao chép một số phần của ghi-up ở đây.

Bạn đã bao giờ tự hỏi làm thế nào một ứng dụng có thể xử lý các dịch vụ hệ thống như POWER MANAGER hoặc ACTIVITY MANAGER hoặc LOCATION MANAGER và một số ứng dụng khác như thế này. Để biết rằng tôi đào sâu vào mã nguồn của Android và tìm hiểu cách thực hiện điều này trong nội bộ. Vì vậy, hãy để tôi bắt đầu từ mã java của ứng dụng.

Ở phía ứng dụng, chúng tôi phải gọi hàm getService và chuyển ID của dịch vụ hệ thống (nói POWER_SERVICE) để xử lý dịch vụ.

Đây là mã cho getService quy định tại /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 } 

Giả sử chúng ta không có các dịch vụ trong bộ nhớ cache. Do đó, chúng tôi cần tập trung vào dòng 55 return getIServiceManager().getService(name);

Cuộc gọi này thực sự được xử lý cho người quản lý dịch vụ và yêu cầu nó trả về tham chiếu về dịch vụ có tên mà chúng tôi đã chuyển làm thông số.

Bây giờ chúng ta hãy xem cách hàm getIServiceManager() trả về một xử lý cho ServiceManager.

Đây là mã của getIserviceManager() từ /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 } 

Các ServicemanagerNative.asInterface() trông giống như sau:

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

Vì vậy, về cơ bản chúng tôi đang nhận được một xử lý cho người quản lý bản địa.

Hàm asInterface này thực sự được chôn bên trong hai macro DECLARE_META_INTERFACE(ServiceManager)IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); được xác định trong IserviceManager.h và IServiceManager.cpp tương ứng.

Cho phép nghiên cứu kỹ hai macro được xác định trong/khung/base/include/binder/IInterface.h

Các DECLARE_META_INTERFACE(ServiceManager) vĩ mô được định nghĩa là

// ---------------------------------------------------------------------- 
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"); đã được định nghĩa như sau:

#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() { } 

Vì vậy, nếu chúng ta thay thế mở rộng hai macro này trong IServiceManager.h & IServiceManager.cpp tệp với thông số thay thế phù hợp, chúng trông giống như sau:

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(); 
…...... 
…..... 
…... 
….. 

Và trong 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 { } 

Vì vậy, nếu bạn nhìn thấy dòng 12 trong đó cho thấy nếu Service Manager khởi động và chạy (và nó nên vì người quản lý dịch vụ bắt đầu trong quá trình init trong Android khởi động lên) nó trả về tham chiếu đến nó thông qua hàm queryLocalinterface và nó đi lên tất cả các cách tới giao diện 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 } 

từ ServiceManagerNative.java. Trong chức năng này, chúng tôi chuyển dịch vụ mà chúng tôi đang tìm kiếm.

Và chức năng onTransact cho GET_SERVICE_TRANSACTION trên cuống từ xa trông giống như sau:

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

…………………. 
…………………. 
………………… 

Nó trả về tham chiếu đến các dịch vụ cần thiết thông qua chức năng getService. Các getService chức năng từ /frameworks/base/libs/binder/IServiceManager.cpp trông giống như sau:

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 } 

Vì vậy, nó thực sự kiểm tra nếu Dịch vụ có sẵn và sau đó trả về một tham chiếu đến nó. Ở đây tôi muốn thêm rằng khi chúng ta trả về một tham chiếu đến một đối tượng IBinder, không giống như các kiểu dữ liệu khác, nó không được sao chép trong không gian địa chỉ của máy khách, nhưng nó thực sự là cùng một tham chiếu của đối tượng IBinder được chia sẻ cho máy khách thông qua kỹ thuật đặc biệt được gọi là ánh xạ đối tượng trong trình điều khiển Binder.

Để thêm chi tiết khác vào cuộc thảo luận, hãy để tôi đi sâu hơn một chút vào đó.

Chức năng checkService trông giống như sau:

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

    } 

Vì vậy, nó thực sự gọi một dịch vụ từ xa và vượt qua mã CHECK_SERVICE_TRANSACTION (một giá trị enum của 2) với nó.

Dịch vụ từ xa này thực sự được triển khai trong khung/cơ sở/cmds/servicemanager/service_manager.c và dịch vụ onTransact của nó trông giống như sau.

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 đó, chúng tôi sẽ gọi hàm có tên do_find_service sẽ tham chiếu đến dịch vụ và trả lại dịch vụ.

Các do_find_service từ cùng một tập tin trông như sau:

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 trông như sau:

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; 

} 

Vì nó trở nên rõ ràng rằng nó đi qua qua svclist và trả về các dịch vụ chúng tôi là tìm kiếm.

+0

. Thêm các liên kết đến nguồn và giải thích vài điểm như 1. Dịch vụ có trả lại một singleton trong Java và 2. ngữ cảnh được lưu trữ ở đâu đó sẽ làm cho câu trả lời này trở thành tuyệt vời –

6

nhưng tôi gặp khó khăn khi hiểu điều gì xảy ra khi gọi ServiceManager.getService (LOCATION_SERVICE); ngay cả sau khi đọc mã ServiceManager.

Ok, vì vậy đây là mã nguồn của getService() trong 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; 
} 

Như chúng ta có thể thấy, nếu dịch vụ được yêu cầu không được lưu trữ nào, này gọi getIServiceManager().getService(name). getIServiceManager() là một phương pháp trong cùng một lớp (chúng tôi sẽ Het để getService (tên) trong bước tiếp theo):

private static IServiceManager getIServiceManager() { 
    if (sServiceManager != null) { 
     return sServiceManager; 
    } 

    // Find the service manager 
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); 
    return sServiceManager; 
} 

Vì vậy, đây cơ bản sai chúng ta tới ServiceManagerNative.java nơi chúng ta cần phải tìm kiếm getService (tên):

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

Bắt đầu giao dịch để truy xuất dịch vụ có tên "LOCATION_SERVICE".

Việc di chuyển khó hơn từ đây do cấu trúc phức tạp của các lớp và giao diện xử lý các nội dung cấp thấp, như dịch vụ hệ thống. Nhưng về cơ bản, tất cả được thực hiện trong Context.java, ContextImpl.java, ServiceManager.java và ServiceManagerNative.java. Cũng lưu ý rằng một số người trong số họ có thể lưu trữ cache hoặc bản đồ cục bộ với các tham chiếu đến các cá thể dịch vụ (tức là bạn có thể thấy sCache.get(name) trong danh sách ServiceManager.java ở trên), đây là nơi có thể tham khảo thêm.

Tôi không nghĩ rằng bạn sẽ nhận được câu trả lời chi tiết hơn ở đây trên StackOverflow, vì nó trở nên rất thấp. Bạn có thể muốn hỏi một nơi nào đó giống như trên danh sách gửi thư của hệ điều hành Android có nhân viên của Google trên đó.

+0

Tôi thực sự quan tâm đến chi tiết ở mức thấp nên tôi nên truy cập danh sách gửi thư của hệ điều hành Android :) –

2

Trình quản lý vị trí, vì hầu hết các dịch vụ/trình quản lý hệ thống được tạo trong giai đoạn đầu trong quá trình khởi động.

app_process là thành phần gốc khởi động DalvikVM, bổ sung, nó cho ZigoteInit (Lớp thực hiện công việc thực tế) để khởi chạy SystemServer. Nó ở đây, nơi mà cá thể đầu tiên của LocationManager được tạo và nơi tham chiếu được giữ trên ServerThread bên trong nó.

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

Phần còn lại đã biết cho bạn, tôi nghĩ vậy.

2

Phương pháp getSystemService

public abstract Object getSystemService(String name); 

được thực hiện trong 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); 
    } 

đâu SYSTEM_SERVICE_MAP là:

private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = 
      new HashMap<String, ServiceFetcher>(); 

và tất cả các dịch vụ được đăng ký trong khối tĩnh

static { 

với cuộc gọi đến registerService như thế này:

registerService(LOCATION_SERVICE, new ServiceFetcher() { 
       public Object createService(ContextImpl ctx) { 
        IBinder b = ServiceManager.getService(LOCATION_SERVICE); 
        return new LocationManager(ctx, ILocationManager.Stub.asInterface(b)); 
       }}); 

hoặc

registerService(INPUT_SERVICE, new StaticServiceFetcher() { 
       public Object createStaticService() { 
        return InputManager.getInstance(); 
       }}); 

ServiceFetcher và StaticServiceFetcher thực hiện mô hình tải lười biếng.

Hy vọng điều đó sẽ hữu ích.