由淺入深 學習 Android Binder(三)- java binder深究(從java到native)
概述
前文講到bindService流程,其中多次碰到用binder實現的IPC,有以下幾個:
- client程式 通過IPC 通知AMS程式去bindService
- AMS程式 通過IPC 通知server程式去bindService
- server程式 通過IPC 通知AMS程式bindService結果
- AMS程式 通過IPC 告訴client程式bindService結果
本文就選擇”client通知AMS程式“的過程繼續作深入,來探究下java層的binder究竟是什麼。(附上前文流程圖)
ContextImpl.bindServiceCommon()
client程式 通知IPC 去bindService,最終會走到ContextImpl. bindServiceCommon().
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
我們只需要關注其中一行程式碼即可。
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
接著看下ActivityManager.getService()的邏輯:
ActivityManager.getService()
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
程式碼看到這,就可以確定是使用binder來實現的IPC了。ActivityManager.getService()實際返回的是IActivityManager。
又因為原始碼中只有ActivityManagerService實現了IActivityManager.Stub,因此,此處可以確定返回的是ActivityManagerService物件。
此處繼續深入,看下這個IActivityManager物件究竟是從哪裡獲取到的。
於是我們看下ServiceManager.getService()邏輯。
ServiceManager.getService()
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
這裡的邏輯是,先去快取中獲取,如果快取中沒有就返回rawGetService()。
既然是深究,那麼此處快取的邏輯也可以暫且不用看了。
直接進入到rawGetService().
ServiceManager.rawGetService()
private static IBinder rawGetService(String name) throws RemoteException {
——————————————————省略
final IBinder binder = getIServiceManager().getService(name);
——————————————————省略
return binder;
}
直接進入到ServiceManager.rawGetService()。
ServiceManager.rawGetService()
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
到這,可以看到返回的其實是ServiceManagerNative.asInterface()的返回值。
對AIDL有所瞭解就知道,asInterface()的內容大概如下:
- 這個方法屬於aidl介面的內部類 Stub
- 在同一程式中,就會直接返回Stub,如果在另一個程式中呼叫,就會返回將這個ibinder封裝好的Proxy物件。
對aidl不瞭解的可以看下前面的文章:由淺入深 學習 Android Binder(一)- AIDL
於是,雖然沒有看ServiceManagerNative的原始碼,但是其邏輯已經很清晰了。
我們只需要關注IBinder的來源就可以了,也就是BinderInternal.getContextObject()。
BinderInternal.getContextObject()
/**
* Return the global "context object" of the system. This is usually
* an implementation of IServiceManager, which you can use to find
* other services.
*/
public static final native IBinder getContextObject();
至此,可以發現IBinder物件其實是從native層獲取到的。
我們繼續看下JNI的程式碼。
android_util_Binder.android_os_BinderInternal_getContextObject()
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
這裡先通過ProcessState獲取到了一個native 層的IBinder強引用。
然後將這個native層的IBinder強引用傳入javaObjectForIBinder()方法,最終封裝成java層的IBinder然後返回。
此處先不深究ProcessState的邏輯,整個native層的binder有自己的一整套的邏輯,後面的文章會繼續探索。
我們可以先稍微看下javaObjectForIBinder()的大概邏輯。
android_util_Binder.javaObjectForIBinder()
// If the argument is a JavaBBinder, return the Java object that was used to create it.
// Otherwise return a BinderProxy for the IBinder. If a previous call was passed the
// same IBinder, and the original BinderProxy is still alive, return the same BinderProxy.
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
// It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
// For the rest of the function we will hold this lock, to serialize
// looking/creation/destruction of Java proxies for native Binder proxies.
AutoMutex _l(gProxyLock);
BinderProxyNativeData* nativeData = gNativeDataCache;
if (nativeData == nullptr) {
nativeData = new BinderProxyNativeData();
}
// gNativeDataCache is now logically empty.
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
if (env->ExceptionCheck()) {
// In the exception case, getInstance still took ownership of nativeData.
gNativeDataCache = nullptr;
return NULL;
}
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
if (actualNativeData == nativeData) {
// New BinderProxy; we still have exclusive access.
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
gNativeDataCache = nullptr;
++gNumProxies;
if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies);
gProxiesWarned = gNumProxies;
}
} else {
// nativeData wasn't used. Reuse it the next time.
gNativeDataCache = nativeData;
}
return object;
}
class JavaBBinder : public BBinder
{
public:
——————————————————省略
jobject object() const
{
return mObject;
}
——————————————————省略
private:
JavaVM* const mVM;
jobject const mObject; // GlobalRef to Java Binder
};
這個方法中未知的細節很多,但是大致邏輯其實很簡單,對具體細節沒興趣的讀者直接看註釋就可以。
這個方法會返回兩種java物件:
-
JavaBBinder.mObject
如果發現本地已經有了JavaBBinder,就返回JavaBBinder.mObject。這個object其實是java層的Binder。 -
BinderProxy
如果發現本地沒有BinderProxy,就會呼叫java層的方法建立一個BinderProxy並返回。(BinderProxy是java層的android.os.BinderProxy)
至於這些物件在分別代表什麼,討論起來需要很大的篇幅。筆者後面的文章會繼續探索。
至此,我們已經大概瞭解了java 層的binder。
這個binder物件有可能是Binder,也有可能是BinderProxy。它與native的邏輯息息相關。
總結
本文從bindService 其中的一個IPC出發,一步步深究到native層。
旨在能給讀者一個新的思路去理解binder,也是從java到native層分析的一個過渡。
繼續探索
這篇文章後肯定還有很多疑問,比如:
- JavaBBinder和BinderProxy具體是啥?
- 到底什麼場景用哪個物件?
- native層主要做了啥?
對這些問題有興趣的讀者可以自行觀看原始碼,或者 歡迎繼續關注筆者後續文章。
相關文章
- Binder in JavaJava
- 理解 Android Binder 機制(三):Java層AndroidJava
- Binder學習總結_native(1)
- Binder學習(二)Binder機制解析
- Binder學習(三)通過AIDL分析Binder通訊流程AI
- Binder Java層分析Java
- Android Binder機制淺析Android
- Android IPC機制(三):淺談Binder的使用Android
- Binder學習(一)Android中的程式Android
- [Android進階]Binder學習(初始篇)Android
- 由淺入深完全理解Java動態代理Java
- Java 反射由淺入深 | 進階必備Java反射
- android Binder機制深入淺出Android
- Android aidl Binder框架淺析AndroidAI框架
- 由淺入深學習JavaScript Debug技巧JavaScript
- Binder池淺談分析
- Android Binder之旅Android
- android binder ipcAndroid
- Java學習從入門到精通Java
- 由淺入深學python(一)Python
- 前端如何理解正則-由淺入深的學習前端
- promise由淺入深Promise
- MongoDB由淺入深MongoDB
- javascript由淺入深JavaScript
- AI實戰 | 由淺入深,手把手帶你實現Java轉型學習助手AIJava
- Binder Java層的實現原理分析Java
- Android-Binder(一)Android
- Android Binder IPC分析Android
- JavaScript Promise由淺入深JavaScriptPromise
- MySQL索引由淺入深MySql索引
- Java學習路線從入門到入土Java
- Java學習從入門到精通[原創]Java
- Java學習從入門到精通(3)(轉)Java
- Java學習從入門到精通(2)(轉)Java
- 真正的Java學習從入門到精通Java
- 由淺入深學C# 視訊教程C#
- Java學習從入門到精通的學習建議Java
- 31 天,從淺到深輕鬆學習 KotlinKotlin