ソースコードベース: Android R
0. 序文
関連する知識ポイントを説明するには、まずフレーム図を整理し、次にフレーム図を作成してプロセスを分析します。
Java側でのバインダーの使い方は大きく分けて以下のようになります。
- Javaクライアント Javaサービス
- Javaクライアントネイティブサービス
Java側のサービスの登録はServiceManager.addService()を使用します。
ServiceManager.getService() を使用して Java 側のサービスを取得します
エントリは ServiceManager.java を通じて行われ、ファイルは Frameworks/base/core/java/android/os/ServiceManager.java にあります。
addService や getService を解析する前に、Binder が最終的にネイティブ側を呼び出すことを理解する必要があり、Java は JNI を経由する必要があるため、その前に JNI の登録プロセスを理解する必要があります。
1. バインダーJNI登録
zygote の起動プロセスを理解している学生は、zygote が起動時にまず仮想マシンを作成し、次に startReg() を通じてシステムに必要な JNI インターフェイスを登録することを知っているはずです。
frameworks/base/core/jni/AndroidRuntime.cpp
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
...
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
...
}
登録されたインターフェイスは次のように定義されます。
frameworks/base/core/jni/AndroidRuntime.cpp
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
...
REG_JNI(register_android_os_Binder),
...
配列は非常に長いので、ここにはあまり貼り付けませんが、バインダー関連の登録関数は次のとおりです。
REG_JNI(register_android_os_Binder),
最後に、関数 register_android_os_Binder() が呼び出されます。
frameworks/base/core/jni/android_util_Binder.cpp
int register_android_os_Binder(JNIEnv* env)
{
if (int_register_android_os_Binder(env) < 0)
return -1;
if (int_register_android_os_BinderInternal(env) < 0)
return -1;
if (int_register_android_os_BinderProxy(env) < 0)
return -1;
...
残りはあまり分析しません. 興味のある学生は、ソース コードのプロセスを詳細に表示するためにアクセスできます (もちろん、次の遭遇もついでに分析されます). ここで知っておく必要があるのは、Java 上のバインダー側はネイティブ操作が必要です JNI インターフェースはすべて zygote にあります 起動時に登録されます。
2.ServiceManager プロキシ
ServiceManager.addService()にしてもServiceManager.getService()にしても、最終的にはネイティブと通信する必要があり、ServiceManager のプロキシを取得する必要があります。つまり、関数getIServiceManager()は次のようになります。
frameworks/base/core/java/android/os/ServiceManager.java
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
主なポイントは次の 2 つです。
- BidnerInternal.getcontextObject()
- ServiceManagerNative.asInterface()
2.1 BinderInternal.getContextObject()
frameworks/base/core/java/com/android/internal/os/BinderInternal.java
public static final native IBinder getContextObject();
これには JNI インターフェイスを呼び出す必要があります。このインターフェイスの登録についてはセクション1で説明しています。詳細については、 int_register_android_os_BinderInternal()を参照してください。
frameworks/base/core/jin/android_util_Binder.cpp
static const JNINativeMethod gBinderInternalMethods[] = {
/* name, signature, funcPtr */
{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
...
}
};
static int int_register_android_os_BinderInternal(JNIEnv* env)
{
...
return RegisterMethodsOrDie(
env, kBinderInternalPathName,
gBinderInternalMethods, NELEM(gBinderInternalMethods));
}
gBinderInternalMethods 配列を登録することで知られる、インターフェイス android_os_BinderInternal_getContextObject() が最終的に呼び出されます。
frameworks/base/core/jin/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
ここではおなじみですが、取得するのはコンテキストが0のservicemanagerのBpBinderで、そのBpBinderをjavaObjectForIBinder()関数で JavaのBinderProxyオブジェクトに変換して返します。
2.1.1 javaObjectForIBinder()
frameworks/base/core/jin/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
...
BinderProxyNativeData* nativeData = new BinderProxyNativeData();
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
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.
return NULL;
}
...
return object;
}
ここで、 BinderProxy のgeInstance() は主に CallStaticObjectMethod() を通じて呼び出され、ここでのグローバル オブジェクトgBinderProxyOffsetsはint_register_android_os_BinderProxy()で指定されます。
frameworks/base/core/jin/android_util_Binder.cpp
static int int_register_android_os_BinderProxy(JNIEnv* env)
{
gErrorOffsets.mError = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Error"));
gErrorOffsets.mOutOfMemory =
MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/OutOfMemoryError"));
gErrorOffsets.mStackOverflow =
MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/StackOverflowError"));
jclass clazz = FindClassOrDie(env, kBinderProxyPathName);
gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance",
"(JJ)Landroid/os/BinderProxy;");
gBinderProxyOffsets.mSendDeathNotice =
GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
"(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V");
gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
clazz = FindClassOrDie(env, "java/lang/Class");
gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
return RegisterMethodsOrDie(
env, kBinderProxyPathName,
gBinderProxyMethods, NELEM(gBinderProxyMethods));
}
javaObjectForIBinder() は、 CallStaticObjectMethod() 関数を通じて BinderProxy の getInstance() インターフェイスを呼び出す必要があります。見てみましょう。
frameworks/base/core/java/android/os/BinderProxy.java
private static BinderProxy getInstance(long nativeData, long iBinder) {
BinderProxy result;
synchronized (sProxyMap) {
try {
result = sProxyMap.get(iBinder);
if (result != null) {
return result;
}
result = new BinderProxy(nativeData);
} catch (Throwable e) {
...
}
...
}
return result;
}
これまでのところ、 BidnerInternal.getcontextObject() が取得するのは、コンテキストが 0 の BinderProxy オブジェクトであることがわかります。
2.2 ServiceManagerNative.asInterface()
framworks/base/core/java/android/os/ServiceManagerNative.java
public static IServiceManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
// ServiceManager is never local
return new ServiceManagerProxy(obj);
}
BinderProxy オブジェクトを取得したら、asInterface を使用して ServiceManager の Java 側プロキシ ServiceManagerProxy を作成します。
framworks/base/core/java/android/os/ServiceManagerNative.java
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
mServiceManager = IServiceManager.Stub.asInterface(remote);
}
...
public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
throws RemoteException {
mServiceManager.addService(name, service, allowIsolated, dumpPriority);
}
...
private IBinder mRemote;
private IServiceManager mServiceManager;
}
mRemoteは BinderProxy オブジェクト、mServiceManagerはすべてのインターフェイスの入り口、ServiceManager の実際のプロキシです。分析は以下に続きます。
3.ServiceManager.addService()
セクション2を通じて、Java 側のバインダー通信は、クライアントがServiceManager.getService() を通じて取得したサーバー プロキシであるか、サーバー側がServiceManager.addService()を通じてServiceManager にサービスを登録する可能性があることがわかります。 。ただし、どのインターフェイスであっても、 Java 側の ServiceManager のコードBinderProxyを通じて操作されます。
このセクションでは addService() を分析します。
frameworks/base/core/java/android/os/ServiceManager.java
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
try {
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
getIServiceManager() は、上記のセクション 2.2 で返された ServiceManagerProxy オブジェクトです。上記のセクション 2.2 のコードに示されているように、 addService() は最後にmServiceManager.addService()を呼び出します。この mServiceManager は、上記のコンテキスト 0 の BinderProxyオブジェクトです。 IServiceManager を通じてパラメータとして取得されたプロキシ:
mServiceManager = IServiceManager.Stub.asInterface(remote);
分析を続けます。
通常、andorid は*.aidlファイルを対応するJavaファイルにコンパイルし、最終的な Java ソース コードはout/soong/.intermediates/の下にあります。詳細については、この記事シリーズの 7 番目の記事を参照してください: Java での CS
Aidl によってコンパイルされた JAVA ファイルは、最終的には Aidl*.srcjar にパッケージ化されることになりますが、特定のファイルを特定するにはどうすればよいでしょうか? これは、フレームワーク フォルダーまたはシステム フォルダー内の*.aidl.dファイルに依存する必要があります。
Aidl ファイルがフレームワークで定義されている場合は、フレームワークの対応するディレクトリに移動して、対応する *.aidl.d ファイルを見つけることができます。
この IServiceManager は、IServiceManager.aidl のコンパイルされたクラス名です。
@Override public void addService(java.lang.String name, android.os.IBinder service, boolean allowIsolated, int dumpPriority) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder(service);
...
boolean _status = mRemote.transact(Stub.TRANSACTION_addService, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addService(name, service, allowIsolated, dumpPriority);
return;
}
_reply.readException();
}
...
}
プロキシ コードは比較的単純です。
- インターフェイス writeStrongBinder(); を通じて、Parcel に追加するサービスを書き込みます。
- mRemote.transact() を通じて通信して、addService() の目的が達成されたかどうかを確認します。
- 上記が失敗した場合は、getDefaultImpl() 経由で addService() を試してください。
通常は 2 番目のステップが実行され、3 番目のステップのデフォルトの impl はインターフェースsetDefaultImpl()を通じて指定する必要があります。
セクション2.2によると、mRemote は ServiceManager の Java 側の BinderProxy オブジェクトです。
3.1 writeStrongBinder()
frameworks/base/core/java/android/os/Parcel.java
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
JNI インターフェイスは android_os_Parcel.cpp にあり、このインターフェイスも zygote の起動時にロードされます。ここではこれ以上の分析はありません。詳細については、AndroidRuntime.cpp の配列 gRegJNI 内のメンバー register_android_os_Parcel を参照してください。
最後に、JNI android_os_Parcel_writeStrongBinder() を呼び出します。
frameworks/base/core/jni/android_os_Parcel.cpp
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
コアの ibinderForJavaObject() を見てみましょう。
frameworks/base/core/jni/android_util_Binder.cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
// Instance of Binder?
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh->get(env, obj);
}
// Instance of BinderProxy?
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return getBPNativeData(env, obj)->mObject;
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
純粋なサービスは Binder タイプに属しているため、照合時には gBinderOffsets.mClass と照合され、この変数は登録時にも割り当てられます。詳細については、 int_register_android_os_Binder()を参照してください。
gBinderOffsets.mObject は、Binder.java の mObject オブジェクト (詳細については int_register_android_os_Binder 関数を参照)、つまり、Binder の構築時にネイティブから取得される BBinderHolder ポインターを取得します。
frameworks/base/core/java/android/os/Binder.java
public Binder(@Nullable String descriptor) {
mObject = getNativeBBinderHolder();
...
}
---->
frameworks/base/core/jni/android_util_Binder.cpp
static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder();
return (jlong) jbh;
}
ibinderForJavaObject()上記で取得したJavaBBinderHolderに加えて、最後にホルダーを通じて get() インターフェイスを呼び出し、サービスの BBinder を取得します。
frameworks/base/core/jni/android_util_Binder.cpp
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
...
}
return b;
}
JavaBBinder を見てください。
frameworks/base/core/jni/android_util_Binder.cpp
class JavaBBinder : public BBinder
{
...
}
したがって、writeStrongBinder() は最終的には、パーセルを transact() に書き込むためのネイティブの BBinder になります。
3.2 BinderProxy.transact()
詳細についてはセクション 5 を参照してください
3.3 JavaBBinder.onTransact()
クライアントが transact() 経由で通信する場合、BBinder は最終的に onTransact() をトリガーします。Java サービスの場合、最後のトリガーはJavaBBinder.onTransact()です。
frameworks/base/core/jni/android_util_Binder.cpp
status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
...
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
gBinderOffsets.mExecTransact は、Binder.java の execTransact() を呼び出す int_register_android_os_Binder() によっても割り当てられますが、ここでは詳しく説明せず、最後に stub.onTransact を呼び出します。
4.ServiceManager.getService()
addService と同様に、getService は最終的に IServiceManager に呼び出されます。
@Override public android.os.IBinder checkService(java.lang.String name) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.IBinder _result;
try {
...
boolean _status = mRemote.transact(Stub.TRANSACTION_checkService, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().checkService(name);
}
_reply.readException();
_result = _reply.readStrongBinder();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
addService() と同様に、ネイティブ側から送信されるバインダー情報を_reply.readStrongBinder()を通じて取得します。
4.1 readStrongBinder()
最終的には JNI android_os_Parcel.cpp に呼び出されます。
frameworks/base/core/jni/android_os_Parcel.cpp
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
セクション2.1が分析され、最後に javaObjectForIBinder() を通じて Java 側のサービスの BinderProxy オブジェクトが取得されます。
5. BinderProxy.transact()
frameworks/base/core/java/android/os/BinderProxy.java
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
....
try {
return transactNative(code, data, reply, flags);
} finally {
...
}
}
実際、ここでの核心は、transactNative を呼び出すことです。
frameworks/base/core/jni/android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
...
status_t err = target->transact(code, *data, reply, flags);
...
}
次のステップは BpBinder->transact です。詳細については、この記事シリーズの 3 番目の記事を参照してください: サービス登録
6. まとめ
最後に、フレームワーク図に従ってまとめてみましょう。
- Java クライアントは getService() を通じてサービスのプロキシを取得し、 getService() は最後にreadStrongBinder()を通じて BinderProxy オブジェクトを取得します 。
- Java クライアントは、transact を通じてサービスと通信し、ネイティブ インターフェイスtransactNative()を通じてBpBinder を呼び出します。
- Java サービスは addService() を通じて登録され、addService() はwriteStrongBinder()を通じてネイティブ インターフェイスを呼び出してJNI に登録します。
- Java サービスが登録されると、JNI 内に JavaBBinderHolder が作成されます。これは、ネイティブと通信するJavaBBinder をカプセル化し、JavaBBinder は BBinder を継承します。
- Java クライアント呼び出しは、最終的に Java サービスの onTransact() を呼び出し、Java 側の stub.onTransact() にコールバックします。