कर देखें कि कहीं मेरी चर्चा समझ में आता है ...
dissection of android service internal
पाठकों मैं यहाँ लेख के कुछ हिस्से को कॉपी करने की कोशिश कर रहा हूँ में से एक ने सुझाव दिया।
क्या आपने कभी सोचा है कि कैसे एक ऐप पावर मैनेजर या गतिविधि प्रबंधक या LOCATION प्रबंधक और कई अन्य जैसे सिस्टम सेवाओं को संभालता है। यह जानने के लिए कि मैंने एंड्रॉइड के स्रोत कोड में खोला और पाया कि यह आंतरिक रूप से कैसे किया जाता है। तो मुझे एप्लिकेशन पक्ष के जावा कोड से शुरू करने दें।
आवेदन पक्ष पर हमें getService
फ़ंक्शन को कॉल करना होगा और सेवा को संभालने के लिए सिस्टम सेवा (POWER_SERVICE कहें) की आईडी पास करनी होगी।
यहाँ /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 }
मान लीजिए हम कैश में सेवा नहीं है में परिभाषित getService
के लिए कोड है। इसलिए हमें लाइन 55 return getIServiceManager().getService(name);
यह कॉल वास्तव में सेवा प्रबंधक को एक संभाल लेता है और उसे उस सेवा का संदर्भ वापस करने के लिए कहता है जिसका नाम हमने पैरामीटर के रूप में पारित किया है।
अब देखते हैं कि 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() से getIserviceManager() के कोड है ऐसा दिखाई देता है
/**
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 में परिभाषित के अंदर दफन है।
/फ्रेमवर्क/आधार/शामिल/बाइंडर/IInterface में परिभाषित दो मैक्रोज़ में जाने दें।
#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 में इन दो मैक्रो का विस्तार बदल देते हैं: ज
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");
परिभाषित किया गया है उचित प्रतिस्थापन मानकों के साथ फ़ाइल को निम्न जैसा दिखता है:
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 है जो दिखाता है, तो सेवा प्रबंधक तैयार होकर चलने लगे देखते हैं (और यह होना चाहिए क्योंकि सेवा प्रबंधक एंड्रॉयड बूट अप के दौरान init प्रक्रिया में शुरू होता है) यह क्वेरी Localinterface समारोह के माध्यम से इसका संदर्भ देता है और यह जावा इंटरफेस के लिए सभी तरह से चला जाता है।
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 }
तो यह वास्तव में अगर सेवा उपलब्ध है और फिर इसे करने के लिए एक संदर्भ रिटर्न की जांच करता है। यहां मैं यह जोड़ना चाहता हूं कि जब हम किसी अन्य प्रकार के डेटा के विपरीत किसी आईबिंडर ऑब्जेक्ट का संदर्भ वापस लेते हैं, तो उसे क्लाइंट के एड्रेस स्पेस में कॉपी नहीं किया जाता है, लेकिन यह वास्तव में आईबींडर ऑब्जेक्ट का एक ही संदर्भ है जिसे क्लाइंट को क्लाइंट के साथ साझा किया जाता है बाइंडर ड्राइवर में ऑब्जेक्ट मैपिंग नामक विशेष तकनीक।
चर्चा में अधिक जानकारी जोड़ने के लिए, मुझे इसमें थोड़ा गहराई से जाने दें।
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 के अपने एक enum मान) गुजरती हैं।
यह रिमोट सेवा वास्तव में ढांचे/आधार/cmds/servicemanager/service_manager.c में लागू होती है और इसकी ऑनट्रैक्ट निम्न की तरह दिखती है।
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 के माध्यम से पार करता है और सेवा हम कर रहे हैं देता है के रूप में खोज रहे हैं
मुझे लगता है कि 'LocationManager' आपके' लोकेशन लिस्टर 'का संदर्भ रखता है जब तक आप' LocationManager.removeUpdates() 'नहीं कहते हैं, और आपके' स्थान लिस्टर 'के पास आपकी' गतिविधि ' – nicopico
का संदर्भ है 'onCreate (...)' विधि के अंदर बनाए गए स्थान लिस्टनर ऑब्जेक्ट पर दायरे को लागू करना चाहिए। जैसे ही विधि समाप्त हो जाती है, यह तब तक गुंजाइश से बाहर हो जाती है जब तक कि कहीं और इसका संदर्भ न हो (इस मामले में LocationManager ऑब्जेक्ट)। इसके अलावा यदि स्थान प्रबंधक ऑब्जेक्ट को कहीं और से संदर्भित नहीं किया गया था तो उनमें से दोनों कुछ बिंदु पर कचरा एकत्रित होता। मैंने स्थान लिस्टनर (अपनी परिकल्पना का परीक्षण करने के लिए) के लिए स्थिर आंतरिक कक्षा बनाने का भी परीक्षण किया और व्यवहार समान है। –
"क्या किसी के पास कार्यान्वयन को कॉल करते समय वास्तव में क्या हो रहा है इसका पूरा विवरण है" - जब आप स्रोत कोड पढ़ते हैं, तो आपने क्या सीखा? – CommonsWare