Binder : android 平臺的一種IPC機制,在kernel中封裝消息規則,在用戶空間提供接口對消息規則進一步封裝,以達到IPC通信的目的。
Android 平臺中的基本組件,Activity,Service,BroadcastReceiver,ContentProvider,都是基於Binder進行IPC通訊。
下面以ContentProvider爲例進行說明Binder的通信機制。
Androdid平臺一個App可以訪問另外一個App中的數據庫:
- AMS: ActivityManagerService
- App2: 實現數據庫服務的應用
- App1: 訪問數據庫的應用
- Binder驅動:Binder驅動層支持
- IContentProvider:數據庫服務跨進程訪問接口
數據庫跨進程訪問基本流程:
- App2啓動之後,會將數據庫的IContentProvider接口publish到AMS,即BpBinder
- App1從AMS中得到數據庫的IContentProvider接口,將其封裝,保存在本地,即BpBinder
- 得到接口之後,就可以通過IContentProvider接口訪問App2中的數據,,不必經過AMS
Step 1:App2啓動並將數據庫publish到AMS
- 應用啓動,install provider:
private void handleBindApplication(AppBindData data) {
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
}
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
if (DEBUG_PROVIDER) {
StringBuilder buf = new StringBuilder(128);
buf.append("Pub ");
buf.append(cpi.authority);
buf.append(": ");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
}
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}
- 將ContentProvider publish到 AMS
public void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeTypedList(providers);
mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
Step 2:App1從AMS中得到數據庫的IContentProvider接口
- 獲取數據庫接口一般通過如下語句:
ContentResolver resolver = context.getContentResolver();
resolver.query(...);
- ContentResolver 的實現位於ContextImpl.java ApplicationContentResolver
private static final class ApplicationContentResolver extends ContentResolver {
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
}
- query 流程中會通過 acquiryProvider 得到 IContentProvider 接口:
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name, int userId, boolean stable) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(name);
data.writeInt(userId);
data.writeInt(stable ? 1 : 0);
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
ContentProviderHolder cph = null;
if (res != 0) {
cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
}
data.recycle();
reply.recycle();
return cph;
}
Step 3:得到接口之後,通過IContentProvider接口訪問App2中的數據庫數據
上面大致說了一下IPC通信的基本流程,具體通過Binder傳遞Binder對象下面進一步說明。
1、服務端Binder對象
服務端的Binder對象,這裏是ContentProvider都是繼承自Binder,對java層來說。
class Transport extends ContentProviderNative
abstract public class ContentProviderNative extends Binder implements IContentProvider
可以看到這個ContentProvider中的Transport就是一個Binder。
既然是一個Binder,需要了解一下這個Binder對象的初始化過程:
public class Binder implements IBinder{
public Binder() {
init();//這是一個native方法
}
private native final void init();
}
native實現
static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder();
jbh->incStrong((void*)android_os_Binder_init);
env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
}
這裏的 JavaBBinderHolder 在進行進程間通信的時候或調用get方法,得到一個BBinder:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
mBinder = b;
ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
}
return b;
}
class JavaBBinder : public BBinder
也就是說,我們說的java層的Binder都有一個Native對應的BBinder。
Binder作爲服務端,除非died,否則應該一直等待client發來消息,那麼這個Binder是如何實現等待呢?
這就涉及到App啓動過程中線程池的開啓,App都是zygote進行fork出來的,在初始化的時候會開啓線程池:
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
do {
result = getAndExecuteCommand();
} while (result != -ECONNREFUSED && result != -EBADF);
}
status_t IPCThreadState::getAndExecuteCommand()
{
result = talkWithDriver();
result = executeCommand(cmd);
}
talkWithDriver會利用系統調用ioctl告訴kernel BC_ENTER_LOOPER,就是說我服務端準備好了。
當收到client的消息之後,就調用onTransact,也就是 JavaBBinder的onTransact
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
}
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
res = onTransact(code, data, reply, flags);
}
就調用到Binder的 onTransact,解析命令,執行對應的函數。
2、Client BpBinder 對象
待續。。。