我们看 AMS声明:
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
可以看到AMS继承了 IActivityManager.Stub 这类,在代码中是搜索不到这个类的定义的,搜索 IActivityManager可以看到其是在一个 IActivityManager.aidl 文件中声明的接口。
interface IActivityManager {
// Since these transactions are also called from native code, these must be kept in sync with
// the ones in frameworks/native/libs/binder/include/binder/IActivityManager.h
// =============== Beginning of transactions used on native side as well ======================
ParcelFileDescriptor openContentUri(in String uriString);
void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
String callingPackage);
void unregisterUidObserver(in IUidObserver observer);
boolean isUidActive(int uid, String callingPackage);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
void handleApplicationCrash(in IBinder app,
in ApplicationErrorReport.ParcelableCrashInfo crashInfo);
int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
int flags, in ProfilerInfo profilerInfo, in Bundle options);
可以看到这里只是声明了 IActivityManager接口,以及接口里的一些函数,并没有函数的实现,也没有 IActivityManager.Stub的声明。
实际上,这个 aidl 在代码运行的时候也没有用处,aidl 文件存在的意义在于它可以指导编译过程帮助我们实现有一定特定套路的适合 Binder 通信的 Java 代码的实现。
像 IActivityManager.Stub这个类实际就是编译阶段根据 IActivityManager.aidl 生成 IActivityManager.java 这个Java文件的时候自动生成的一个辅助Binder通信的类。当我们编译完成代码后,生成的 IActivityManager.java文件会在源码的out目录下:
test@1:~/source/out$ find . -name IActivityManager.java
./target/common/obj/JAVA_LIBRARIES/framework-full_check_intermediates/core/java/android/app/IActivityManager.java
./target/common/obj/JAVA_LIBRARIES/framework-full_intermediates/core/java/android/app/IActivityManager.java
./target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/core/java/android/app/IActivityManager.java
^C
这个文件最终会被编译到对应的 dex文件中去。我们看看这个文件:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: frameworks/base/core/java/android/app/IActivityManager.aidl
*/
package android.app;
/**
* System private API for talking with the activity manager service. This
* provides calls from the application back to the activity manager.
*
* {@hide}
*/
public interface IActivityManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.app.IActivityManager
{
private static final java.lang.String DESCRIPTOR = "android.app.IActivityManager";
文件开头的注释很清晰了:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: frameworks/base/core/java/android/app/IActivityManager.aidl
*/
接下来我们发现 IActivityManager 被声明成一个 interface,且继承了 android.os.IInterface 这个接口。
public interface IInterface
{
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
*/
public IBinder asBinder();
}
IInterface 只有一个接口函数需要实现,就是 asBinder函数,这里暂不深究。
我们看看Stub是个什么东西:
public static abstract class Stub extends android.os.Binder implements android.app.IActivityManager {
IActivityManager.Stub继承了 android.os.Binder 且实现了 IActivityManager 接口,IActivityManager.aidl中声明的接口,都会在 Stub中实现,稍后我们再看接口函数的实现。
由于 ActivityManagerService extends IActivityManager.Stub,所以 AMS对象也是会继承Binder,同时需要实现 IActivityManager 里面的所有接口函数。
我们还是从怎么使用AMS开始分析,首先是 getService,上一篇已经分析过:
mCallingUid = ActivityManager.getService().getLaunchedFromUid(activityToken);
getService返回的是一个 IActivityManager的实例对象:
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton IActivityManagerSingleton =
new Singleton() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
public static final String ACTIVITY_SERVICE = "activity";
上一篇我们详细分析过,ServiceManager.getService返回的对象有两种可能:
我们看到,getService获取到返回值后,接着会调用 IActivityManager.Stub.asInterface(b)取得返回值,这个返回值才能被使用。看下 asInterface:
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.app.IActivityManager
{
private static final java.lang.String DESCRIPTOR = "android.app.IActivityManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an android.app.IActivityManager interface,
* generating a proxy if needed.
*/
public static android.app.IActivityManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.app.IActivityManager))) {
return ((android.app.IActivityManager)iin);
}
return new android.app.IActivityManager.Stub.Proxy(obj);
}
asInterface中的关键点在于,使用 getService的返回值执行 queryLocalInterface 是否能得到一个 IActivityManager的实例。由于getService的返回值存在两种情况,一种是同一进程调用,返回的 new ActivityManagerService() 对象,一种返回的是new BinderProxy()对象。我们先从第一种分析:
由于 ActivityManagerService extends IActivityManager.Stub,所以 new ActivityManagerService()时, Stub的构造函数会在 AMS的构造函数之前执行,可以看到构造函数中调用了 this.attachInterface(this, DESCRIPTOR),这个函数是继承自Binder的:
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
所以 new AMS完成后,其父类Binder的成员 mOwner就是 new AMS对象本身,mDescriptor就是 "activity";后续使用 AMS对象 queryLocalInterface时,这个函数也是继承自 Binder:
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
从这里,我们可以知道使用 AMS对象 queryLocalInterface返回的就是 AMS对象自己;如果接下来使用这个对象调用 IActivityManager的接口函数,实际就会直接跳转到 AMS 内部对这些接口函数的实现,不会需要通过 binder通信了。也就是说:
使用同一进程中的Service服务时,Service的函数调用会直接调用,不再需要通过 binder 通信。
再来说当Service运行所在进程与使用Service服务的进程不是同一个进程的情况,此时 getService返回的是 BinderProxy对象,在 Stub.asInterface中同样会调用 queryLocalInterface函数,我们查看 BinderProxy类对这个函数的实现:
public IInterface queryLocalInterface(String descriptor) {
return null;
}
可以看到其是直接返回 null 的,也就是说,asInterface会返回一个 new android.app.IActivityManager.Stub.Proxy(obj),然后再提供 IActivityManager 接口提供的服务,其中 obj是BinderProxy对象。那么我们看看 IActivityManager.Stub.Proxy:
private static class Proxy implements android.app.IActivityManager
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.ParcelFileDescriptor openContentUri(java.lang.String uriString) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.ParcelFileDescriptor _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(uriString);
mRemote.transact(Stub.TRANSACTION_openContentUri, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.os.ParcelFileDescriptor.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
可以看到 IActivityManager.Stub.Proxy 实现了 IActivityManager接口,并直接实现了 IActivityManager 的接口函数。当通过 new android.app.IActivityManager.Stub.Proxy(obj) 这个对象使用 IActivityManager的接口服务时,会直接调用到 IActivityManager.Stub.Proxy中实现的接口函数,以此来间接使用 AMS提供的服务。比如调用到 IActivityManager.Stub.Proxy.openContentUri 函数,由于这个 Proxy实际是另外一个进程中运行的 AMS的一个代理,所以使用其服务时需要通过 Binder通信完成:
这里的 Stub.TRANSACTION_openContentUri的值是自动生成的,对应着 openContentUri函数的标号,需要一同通过 binder 通信传递到对端去,对端根据这个标号才能决定要执行的是 AMS实现的 openContentUri函数。
接下来我们分析下这个 binder通信是如何调用到Service端的对应实现函数的,reply就不再分析了,基本就是一套流程。
关键的调用是 mRemote.transact,由于 new android.app.IActivityManager.Stub.Proxy(obj) 时,obj是BinderProxy对象,所以这里 mRemote就是BinderProxy对象,所以这里就会调用 BinderProxy.transact函数:
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
...
return transactNative(code, data, reply, flags);
}
接下来调用 BinderProxy.transactNative函数:
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
最终的实现会调用到 android_os_BinderProxy_transact:
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
IBinder* target = getBPNativeData(env, obj)->mObject.get();
status_t err = target->transact(code, *data, reply, flags);
}
在接下来的流程我们都在前面两篇详细分析过了,接下来的调用链就是:
其中 binder_thread_write 会通过binder_transaction函数创建一个 binder_transaction的对象 和一个 biner_work对象,这两个对象是相互关联的。其中 binder_transaction的 binder buffer是从 target proc中申请的,且被填写了数据,t->code = tr->code,其值是: Stub.TRANSACTION_openContentUri,t->work.type = BINDER_WORK_TRANSACTION; 写完数据就会在 binder_thread_read函数中等待对端进程写回 reply,并给当前 binder thread 的 todo list插入一个 binder_work,并唤醒当前 binder_thread
接下来就要来到对端,即AMS所在进程 system_servver。请求的执行是在 system_server 的其中一个 binder 线程,由于肯定会被一个空闲的binder 线程来处理,所以我们可以先找到一个空闲的 binder 线程,看看它的状态,如下调用栈是一个空闲的binder线程的调用栈:
"Binder:1515_1" prio=5 tid=8 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x135c0678 self=0x753ac15800
| sysTid=1579 nice=0 cgrp=default sched=0/0 handle=0x752ac4b4f0
| state=S schedstat=( 0 0 0 ) utm=61 stm=23 core=5 HZ=100
| stack=0x752ab51000-0x752ab53000 stackSize=1005KB
| held mutexes=
kernel: __switch_to+0x88/0x94
kernel: binder_thread_read+0x328/0xe60
kernel: binder_ioctl_write_read+0x18c/0x2d0
kernel: binder_ioctl+0x1c0/0x5fc
kernel: do_vfs_ioctl+0x48c/0x564
kernel: SyS_ioctl+0x60/0x88
kernel: __sys_trace_return+0x0/0x4
native: #00 pc 0000000000068e00 /system/lib64/libc.so (__ioctl+4)
native: #01 pc 00000000000243a8 /system/lib64/libc.so (ioctl+132)
native: #02 pc 0000000000061af0 /system/lib64/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+256)
native: #03 pc 0000000000061c60 /system/lib64/libbinder.so (_ZN7android14IPCThreadState20getAndExecuteCommandEv+24)
native: #04 pc 00000000000623c8 /system/lib64/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb+60)
native: #05 pc 0000000000082d38 /system/lib64/libbinder.so (???)
native: #06 pc 00000000000116ec /system/lib64/libutils.so (_ZN7android6Thread11_threadLoopEPv+280)
native: #07 pc 00000000000c2154 /system/lib64/libandroid_runtime.so (_ZN7android14AndroidRuntime15javaThreadShellEPv+136)
native: #08 pc 00000000000666cc /system/lib64/libc.so (_ZL15__pthread_startPv+36)
native: #09 pc 000000000001f1e4 /system/lib64/libc.so (__start_thread+68)
可以看到空闲的binder线程是在 binder_thread_read函数中 wait着的。所以一个空闲的线程就是从 binder_thread_read 获取到 binder work之后,就会开始工作:
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
// read buffer 先写入一个 BR_NOOP 命令
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
}
ret = binder_wait_for_work(thread, wait_for_proc_work);
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
list = &thread->todo; OR list = &proc->todo;
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w = NULL;
struct list_head *list = NULL;
struct binder_transaction *t = NULL;
struct binder_thread *t_from;
w = binder_dequeue_work_head_ilocked(list);
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
binder_inner_proc_unlock(proc);
t = container_of(w, struct binder_transaction, work);
} break;
if (t->buffer->target_node) { // 本次走这里
struct binder_node *target_node = t->buffer->target_node;
struct binder_priority node_prio;
// 对应 JavaBBinder->mRefs
tr.target.ptr = target_node->ptr;
// 对应 JavaBBinder
tr.cookie = target_node->cookie;
node_prio.sched_policy = target_node->sched_policy;
node_prio.prio = target_node->min_priority;
binder_transaction_priority(current, t, node_prio,
target_node->inherit_rt);
cmd = BR_TRANSACTION;
} else {
tr.target.ptr = 0;
tr.cookie = 0;
cmd = BR_REPLY;
}
tr.code = t->code; // Stub.TRANSACTION_openContentUri
tr.flags = t->flags;
tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (binder_uintptr_t)
((uintptr_t)t->buffer->data +
binder_alloc_get_user_buffer_offset(&proc->alloc));
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
// read buffer 写入 BR_TRANSACTION 命令
put_user(cmd, (uint32_t __user *)ptr)
ptr += sizeof(uint32_t);
// 将 tr copy到 read buffer
copy_to_user(ptr, &tr, sizeof(tr))
ptr += sizeof(tr);
t->buffer->allow_user_free = 1;
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
binder_inner_proc_lock(thread->proc);
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;
binder_inner_proc_unlock(thread->proc);
} else {
binder_free_transaction(t);
}
...
}
此时 tr->code = Stub.TRANSACTION_openContentUri,从 binder_thread_read 返回后,会依次返回到如下函数:
可以看到,其实就是上面空闲的binder线程的调用栈一层层返回。注意,返回到getAndExecuteCommand 函数中后,接下来会执行executeCommand:
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
cmd = mIn.readInt32(); // cmd 是 BR_TRANSACTION
result = executeCommand(cmd);
...
return result;
}
接下来在 executeCommand函数中执行 BR_TRANSACTION动作:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
mLastTransactionBinderFlags = tr.flags;
Parcel reply;
status_t error;
// 是在 binder_thread_read 中赋值的
// tr.target.ptr = target_node->ptr = JavaBBinder->mRefs 或者 DrmgmrSvc->mRefs
// tr.cookie = target_node->cookie = JavaBBinder 或者 DrmManagerService
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
// safely acquire a strong reference before doing anything else with it.
if (reinterpret_cast(
tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
reinterpret_cast(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
...
return result;
}
可以看到已经开始传递 tr.code了,其值是 Stub.TRANSACTION_openContentUri。这里的重点是把 tr.cookie转换成 BBinder,并调用其 transact函数,:
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
其又会调用BBinder对象自己的 onTransact 函数,比如,如果BBinder对象是 DrmManagerService,由于其继承自 BnDrmManagerService,所以会执行 BnDrmManagerService::onTransact():
status_t BnDrmManagerService::onTransact(
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
case ADD_UNIQUEID:
{
CHECK_INTERFACE(IDrmManagerService, data, reply);
int uniqueId = addUniqueId(data.readInt32());
reply->writeInt32(uniqueId);
return DRM_NO_ERROR;
}
....
由于 AMS是通过 Java端的 ServiceManager.addService注册的,所以这里 tr.cookie实际是 JavaBBinder,那就会执行 JavaBBinderd的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(&data), reinterpret_cast(reply), flags);
...
}
可以看到关键的点是调用了一个 Java函数 gBinderOffsets.mExecTransact,其参数 mObject就是 JavaBBinder()->mObject,在添加 AMS时,new JavaBBinder的构造参数就是 AMS对象,所以这个 mObject就是 AMS对象。看看 这个Java函数:
const char* const kBinderPathName = "android/os/Binder";
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
其实就是 Binder.execTransact,所以接下来就是执行 AMS对象mObject的父类函数 Binder.execTransact:
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
...
res = onTransact(code, data, reply, flags);
..
}
按理说接下来就是执行Binder.onTransct函数了,但是别忘了当前的对象是 AMS对象 mObject,我们需要先看下AMS类或者其父类有没有重写 onTransact函数。
再回忆下 AMS类的继关系:
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
ActivityManagerService 继承了 IActivityManager.Stub,而 IActivityManager.Stub 继承了Binder且重写了 onTransact函数:
public interface IActivityManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.app.IActivityManager
{
private static final java.lang.String DESCRIPTOR = "android.app.IActivityManager";
public static android.app.IActivityManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.app.IActivityManager))) {
return ((android.app.IActivityManager)iin);
}
return new android.app.IActivityManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_openContentUri:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
android.os.ParcelFileDescriptor _result = this.openContentUri(_arg0);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
...
}
所以接下来要执行的就是 AMS对象 mObject 的父类函数 IActivityManager.Stub.onTransact:
由于此时 code是 TRANSACTION_openContentUri,所以会通过执行 this.openContentUri(_arg0); 函数获取 result,然后再写入 reply并返回。而 this是 AMS对象,所以此时就会调用 AMS自己实现的 openContentUri 函数:
public ParcelFileDescriptor openContentUri(String uriString) throws RemoteException {
enforceNotIsolatedCaller("openContentUri");
final int userId = UserHandle.getCallingUserId();
final Uri uri = Uri.parse(uriString);
String name = uri.getAuthority();
...
}
至此,从 Java层通过 aidl 进行的 Binder通信流程分析完成。
从我们的分析过程可以看到,aidl 实际只是一个辅助实现 Binder通信的接口语言。其存在的价值在于指导编译出规律一致的,符合binder通信标准的Java Binder通信接口程序。实际在最终的代码执行中并没有用到 aidl 文件,使用的是经过其指导产生的 IActivityManager.java文件。我们也可以完全不用 aidl,而是自己手写 IActivityManager.java的实现。只是使用 AIDL 更方便,和节省时间。
TODO:待续。。。
(本周手指疼。。。感觉敲键盘快肿了又。。。)