赞
踩
对于应用程序编程来说,aidl只是一种可选项,绝大部分的应用程序,其实只是关注于图形界面与交互,所以大部分情况下只是在写Activity,用到Service的可能性并不大。即使是使用到了Service,我们也并非必须要使用aidl。我们从前面也看到了,最方便的Service,是使用简单的UnboundedService,通过Intent来驱动。如果只是针对于本地化进程,特别是一些希望通过Binder来引入灵活性但又不想将内容功能共享出来的情况,我们也可以只使用Local Binder来完成。如果我们希望使用跨进程通讯,但又不需要自动化的线程池运行环境,我们也可以使用在主线程里执行Messenger。所以现在绝大部分应用程序,甚至一些功能比较复杂的Android应用程序,也不一定会用到AIDL。
但这些,对于Android系统层实现来说,却正好相反。由于Android系统是基于跨进程交互的“沙盒”模型建立的,任意两个进程间进行交互,都有需要使用Binder。如果是Java编写的代码,则出于减小代码重复的角度考虑,就会使用AIDL。所以我们在Android源代码里可以看到大量的AIDL,而应用程序使用的像Intent、Messenger这些基础对象,都是通过AIDL来实现的一种更高层次的抽象而已。
首先我们可以来看看Intent与Activity的内部实现机制。作为Android应用层最强大最灵活的跨进程通信方式,Intent本质上就是一个Parcelable类,是通过Parcelable接口创建的,可在多个进程之间进行传输的消息:
Intent实现了Parcelable接口,在传输一个Intent对象时,我们便可以使用Parcelable协议,但Intent里包含的信息写入到一个Parcel对象的buffer里,然后再传递给另一个进程处理。在Intent处理里,大部分信息都是使用的基本数据类型,比如mAction、mType、mPackage、mComponent都是String。对于比较特殊的Uri类型的mData,因为Uri这种类型的类也是复杂构造的类,于是Uri也被会实现Parcelable接口。而另一个复杂类型mExtras,因为我们在现实中可能通过mExtras传递任意复杂的数据对象,于是mExtras是一个继承自Bundle类的字典型数据结构。于是,我们得到的Intent的构成便是一个简单的Parcelable实现:
Intent的源代码位于frameworks/base/core/java/android/content/Intent.java。我们会看到这一代码实现的Parcelable比我们范例里的要复杂。这跟实际情况相符,我们现实中使用的aidl接口实现与Parcelable接口实现,都会比我们例子里的要复杂,因为Parcelable接口与aidl接口只是解决跨进程传输问题,相当于是提供给跨进程访问的Public属性或方法,但我们每个对象除了有Public属性,还会有Private属性,只在当前进程内有效的,为当前对象提供一些辅助属性与操作方法,所以除了aidl与Parcelable,这些基于IBinder的对象还会有其他部分的实现。
在创建了Intent之后,大体上会有三种Intent的发送方式,startActivity()|startActivityForResult()来启动一个Activity,startService()|bindService()来启动一个Service,以及sendBroadcast()来发送广播消息。而在Android内部实现上,Intent的发送,大致都如下图所示:
Intent的发送,分别有可能通过Context的startActivity()、startService()、sendBroadcast()三个出口进行发送。Context由Framework实现的ContextImpl来提供具体的发送功能,在ContextImpl类里会经过不同的特殊处理,比如在startActivity()之上会再套接一层execStartActivity()方法来驱动Instrumentation测试框架,但最终都会通过ActivityManagerNative类来访问到一个处理Intent请求的gDefault对象。正如我们看到的gDefault,实际上是Singleton<IActivityManager>生成的进程唯一的IActivityManager对象。于是,最终,所有的Intent,都会通过IActivityManager来走入Activity、Service与Broadcast三个不同的处理方法。
如果是按照aidl的标准写法,此时我们理论上应该会在IAcitvityManager.java的同一级目录里找到一个IActivityManager.aidl文件。但很不幸,我们找不到这么一个文件,跟我们前面见到的aidl实现似乎很不一样。所有需要使用到AIDL实现的地方,总需要某种机制可以得到IBinder引用,而像ActivityManager,还有稍后会介绍的一个ServiceManager,都会是尝试去获取一个IBinder引用的,这时便有了个“鸡与蛋”的问题,为了简化逻辑,于是这一层便是绕开AIDL,直接实现IActivityManager接口类。
仔细看一下的话,其实IActivityManager.java与通过aidl自动生成的文件很类似,基本构成都是一样:
- public interface IActivityManagerextends IInterface { 1
- public int startActivity(IApplicationThread caller,
- Intent intent, String resolvedType, Uri[] grantedUriPermissions,
- int grantedMode, IBinder resultTo, String resultWho,int requestCode,
- boolean onlyIfNeeded, boolean debug) throws RemoteException; 2
- public boolean finishActivity(IBinder token,int code, Intent data)
- throws RemoteException;
- public int broadcastIntent(IApplicationThread caller, Intent intent,
- String resolvedType, IIntentReceiver resultTo, int resultCode,
- String resultData, Bundle map, String requiredPermission,
- boolean serialized, boolean sticky) throws RemoteException;
- public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType) throws RemoteException;
- public int bindService(IApplicationThread caller, IBinder token,
- Intent service, String resolvedType,
- IServiceConnection connection, int flags)throws RemoteException;
- ...
- String descriptor = "android.app.IActivityManager"; 3
- int START_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
- int HANDLE_APPLICATION_ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
- int START_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
- int UNHANDLED_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
- int OPEN_CONTENT_URI_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4; 4
- ...
- }
但是,由于IActivityManager.java不是由aidl工具自动生成的,于是不会自生成的Stub和Proxy对象,这些对象都须由实现这一接口类的部分实现,提供发送与接收两端的Binder处理的接口方法。我们可以在源代码里行搜索,发现实现IActivityManager接口类的居然又回到ActivityManagerNative.java,是由这一文件里的ActivityManagerProxy类来实现Proxy端功能。这是Android的一个缺陷,有时代码会不必要地“回溯”。所以从代码角度分析,最后我们得到的会是Remote Service的Proxy端代码:
- package android.app; 1
- import android.content.ComponentName;
- ...
- public abstract class ActivityManagerNative extends Binder implements IActivityManager 2
- {
-
- static public IActivityManager asInterface(IBinder obj) 3
- {
- if(obj == null) {
- return null;
- }
- IActivityManager in =
- (IActivityManager)obj.queryLocalInterface(descriptor);
- if(in != null) {
- return in;
- }
-
- return new ActivityManagerProxy(obj); 4
- }
-
-
- static public IActivityManager getDefault() 5
- {
- if(gDefault != null) {
- return gDefault;
- }
- IBinder b = ServiceManager.getService("activity");
- gDefault = asInterface(b); 6
- return gDefault;
- }
-
- static public boolean isSystemReady() { 7
- if(!sSystemReady) {
- sSystemReady = getDefault().testIsSystemReady();
- }
- return sSystemReady;
- }
- static boolean sSystemReady =false;
-
- publicActivityManagerNative()
- {
- attachInterface(this, descriptor); 8
- }
-
- public boolean onTransact(int code, Parcel data,Parcel reply,int flags)
- throws RemoteException { 9
- switch (code) {
- case START_ACTIVITY_TRANSACTION: 10
- ...
- case START_ACTIVITY_AND_WAIT_TRANSACTION:
- ...
- case START_ACTIVITY_WITH_CONFIG_TRANSACTION:
- ...
- case START_ACTIVITY_INTENT_SENDER_TRANSACTION:
- ...
- case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:
- ...
- case FINISH_ACTIVITY_TRANSACTION:
- ...
- return super.onTransact(code, data, reply, flags); 11
- }
-
- public IBinderasBinder() 12
- {
- return this;
- }
-
- private staticIActivityManager gDefault;
- }
-
- class ActivityManagerProxy implements IActivityManager 13
- {
- publicActivityManagerProxy(IBinder remote)
- {
- mRemote = remote;
- }
-
- public IBinderasBinder() 14
- {
- return mRemote;
- }
-
- public int startActivity(IApplicationThread caller, Intent intent,
- String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
- IBinder resultTo, String resultWho,
- int requestCode, boolean onlyIfNeeded,
- boolean debug) throws RemoteException { 15
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(caller != null ? caller.asBinder() :null);
- intent.writeToParcel(data, 0);
- data.writeString(resolvedType);
- data.writeTypedArray(grantedUriPermissions, 0);
- data.writeInt(grantedMode);
- data.writeStrongBinder(resultTo);
- data.writeString(resultWho);
- data.writeInt(requestCode);
- data.writeInt(onlyIfNeeded ? 1 : 0);
- data.writeInt(debug ? 1 : 0);
- mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
- reply.readException();
- int result = reply.readInt();
- reply.recycle();
- data.recycle();
- return result;
- }
- public int broadcastIntent(IApplicationThread caller,
- Intent intent, String resolvedType, IIntentReceiver resultTo,
- int resultCode, String resultData, Bundle map,
- String requiredPermission, boolean serialized,
- boolean sticky) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(caller != null ? caller.asBinder() :null);
- intent.writeToParcel(data, 0);
- data.writeString(resolvedType);
- data.writeStrongBinder(resultTo != null ? resultTo.asBinder() :null);
- data.writeInt(resultCode);
- data.writeString(resultData);
- data.writeBundle(map);
- data.writeString(requiredPermission);
- data.writeInt(serialized ? 1 : 0);
- data.writeInt(sticky ? 1 : 0);
- mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
- reply.readException();
- int res = reply.readInt();
- reply.recycle();
- data.recycle();
- return res;
- }
- ...
- private IBinder mRemote;
- }
所以,从代码层面来看,除了因为bindService()传输上的“鸡与蛋”问题,我们的ActivityManager本身与普通的aidl编程没有本质区别,只是通过一层getDefault()方法来绕开bindService()的使用。但是因为IActivityManager接口本身需要支持bindService()机制,所以对实现IActivityManager的Service端的代码来说,就没有Service的生存周期这回事了。
基于这样分析,最后,我们上面Proxy端的执行逻辑,实际上在内部实现是这样进行交互的:
通过ActivityManagerNative的getDefault()方法,我们最终得到的gDefault会是一个ActivityManagerProxy对象,然后我们所有的调用,会通过ActivityManagerProxy里对于各个方法的封装,再将具体的命令通过Binder发送到IActivityManager的Service实现部分。
于是对于IActivityManager这一接口类,剩下的工作便是看看它是如何被响应处理的。
对于IActivityManager的Service的实现部分,因为整个Stub接口都已经在抽象类ActivityManagerNative里完成了,所以也跟aidl会有不一样之处,我们不需要创建一个Stub对象,然后再在这个Stub对象里提供具体的方法实现,而是只需要根据onTransact()解析出来的方法提供具体实现。一般的Remote Service,Stub对象是通过onBind()回调方法触发创建的,会返回一个IBinder的引用到客户端。对于IActivityManager来说没有这样的触发点,它反倒是会远程调用到这一回调方法,所以这里并不需要实现这部分代码,而是保持循环,提供这种onBind()触发能力。
IActivityManager的Stub端,是会运行在SystemServer进程空间里,由frameworks/base/services/java/com/android/server/am/ActivityManagerService.java实现的。从前面的代码可以看出,其实ActivityManagerNative类已经将Binder接收端的代码封装好了,此时,我们所需要的,只是写一个ActivityManagerNative的实现类(因为ActivityManagerNative是一个抽象类)。
我们可以再来看看ActivityManagerService.java的实现:
- public finalclass ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { 1
- ...
- final Handler mHandler= newHandler() { 2
- ...
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SHOW_ERROR_MSG: {
- HashMap data = (HashMap)msg.obj;
- synchronized(ActivityManagerService.this) {
- ProcessRecord proc =(ProcessRecord)data.get("app");
- if (proc != null &&proc.crashDialog != null) {
- Slog.e(TAG, "App already has crash dialog: " + proc);
- return;
- }
- AppErrorResult res =(AppErrorResult) data.get("result");
- if (mShowDialogs &&!mSleeping && !mShuttingDown) {
- Dialog d = newAppErrorDialog(mContext, res, proc);
- d.show();
- proc.crashDialog = d;
- } else {
- res.set(0);
- }
- }
- ensureBootCompleted();
- } break;
- ...
- }
- };
-
- @Override
- public boolean onTransact(int code, Parcel data,Parcel reply,int flags) 3
- throws RemoteException {
- if(code == SYSPROPS_TRANSACTION) {
- ...
- }
- try {
- return super.onTransact(code, data, reply, flags);
- } catch (RuntimeException e) {
- if(!(e instanceof SecurityException)) {
- Slog.e(TAG, "Activity Manager Crash", e);
- }
- throw e;
- }
- }
-
- static classPermissionControllerextends IPermissionController.Stub { 4
- ActivityManagerService mActivityManagerService;
- PermissionController(ActivityManagerService activityManagerService) {
- mActivityManagerService =activityManagerService;
- }
-
- public boolean checkPermission(String permission,int pid, int uid) {
- return mActivityManagerService.checkPermission(permission, pid,
- uid) == PackageManager.PERMISSION_GRANTED;
- }
- }
-
- private class ServiceRestarterimplements Runnable { 5
- private ServiceRecord mService;
-
- void setService(ServiceRecord service) {
- mService = service;
- }
-
- public void run() {
- synchronized(ActivityManagerService.this) {
- performServiceRestartLocked(mService);
- }
- }
- }
-
- public finalint startActivity(IApplicationThread caller, 6
- Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode,int startFlags,
- StringprofileFile, ParcelFileDescriptor profileFd, Bundle options) {
- enforceNotIsolatedCaller("startActivity");
- int userId = 0;
- if(intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
- userId = mCurrentUserId;
- } else {
- if(Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
- userId = 0;
- } else {
- userId =Binder.getOrigCallingUser();
- }
- }
- return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
- null, null, options, userId);
- }
-
- public intbindService(IApplicationThread caller, IBinder token, 7
- Intent service, String resolvedType,
- IServiceConnection connection, int flags,int userId) {
- enforceNotIsolatedCaller("bindService");
- if(service != null && service.hasFileDescriptors() == true) {
- throw new IllegalArgumentException("Filedescriptors passed in Intent");
- }
-
- checkValidCaller(Binder.getCallingUid(), userId);
-
- synchronized(this) {
- final ProcessRecord callerApp = getRecordForAppLocked(caller);
- if(callerApp == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller
- + " (pid=" +Binder.getCallingPid()
- + ") when binding service " + service);
- }
-
- ActivityRecord activity = null;
- if(token != null) {
- activity =mMainStack.isInStackLocked(token);
- if (activity == null) {
- Slog.w(TAG, "Binding with unknown activity: " + token);
- return 0;
- }
- }
-
- int clientLabel = 0;
- PendingIntent clientIntent = null;
-
- if(callerApp.info.uid == Process.SYSTEM_UID) {
- try {
- clientIntent =(PendingIntent)service.getParcelableExtra(
- Intent.EXTRA_CLIENT_INTENT);
- } catch (RuntimeException e) {
- }
- if (clientIntent != null) {
- clientLabel =service.getIntExtra(Intent.EXTRA_CLIENT_LABEL,0);
- if (clientLabel != 0) {
- service =service.cloneFilter();
- }
- }
- }
-
- ServiceLookupResult res =
- retrieveServiceLocked(service,resolvedType,
- Binder.getCallingPid(),Binder.getCallingUid(), userId);
- if(res == null) {
- return 0;
- }
- if(res.record == null) {
- return -1;
- }
- if(isSingleton(res.record.processName, res.record.appInfo)) {
- userId = 0;
- res =retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(),
- Binder.getCallingUid(),0);
- }
- ServiceRecord s = res.record;
-
- final long origId = Binder.clearCallingIdentity();
-
- if(unscheduleServiceRestartLocked(s)) {
- if (DEBUG_SERVICE) Slog.v(TAG,"BIND SERVICE WHILE RESTART PENDING:"
- + s);
- }
-
- AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
- ConnectionRecord c = new ConnectionRecord(b, activity,
- connection, flags,clientLabel, clientIntent);
-
- IBinder binder = connection.asBinder();
- ArrayList<ConnectionRecord> clist = s.connections.get(binder);
- if(clist == null) {
- clist = new ArrayList<ConnectionRecord>();
- s.connections.put(binder,clist);
- }
- clist.add(c);
- b.connections.add(c);
- if(activity != null) {
- if (activity.connections ==null) {
- activity.connections = newHashSet<ConnectionRecord>();
- }
- activity.connections.add(c);
- }
- b.client.connections.add(c);
- if((c.flags&Context.BIND_ABOVE_CLIENT) !=0) {
- b.client.hasAboveClient = true;
- }
- clist = mServiceConnections.get(binder);
- if(clist == null) {
- clist = newArrayList<ConnectionRecord>();
- mServiceConnections.put(binder,clist);
- }
- clist.add(c);
-
- if((flags&Context.BIND_AUTO_CREATE) !=0) {
- s.lastActivity =SystemClock.uptimeMillis();
- if (!bringUpServiceLocked(s,service.getFlags(),false)) {
- return 0;
- }
- }
-
- if(s.app != null) {
- // This could have made the service more important.
- updateOomAdjLocked(s.app);
- }
-
- if(DEBUG_SERVICE) Slog.v(TAG, "Bind" + s + "with " + b
- + ": received=" +b.intent.received
- + " apps=" +b.intent.apps.size()
- + " doRebind=" +b.intent.doRebind);
-
- if(s.app != null && b.intent.received) {
- try {
- c.conn.connected(s.name,b.intent.binder);
- } catch (Exception e) {
- Slog.w(TAG, "Failure sending service " + s.shortName
- + " to connection " + c.conn.asBinder()
- + " (in " +c.binding.client.processName +")", e);
- }
-
- if (b.intent.apps.size() ==1 &&b.intent.doRebind) {
- requestServiceBindingLocked(s, b.intent, true);
- }
- } else if (!b.intent.requested) {
- requestServiceBindingLocked(s,b.intent, false);
- }
-
- Binder.restoreCallingIdentity(origId);
- }
-
- return 1;
- }
-
- public finalint broadcastIntent(IApplicationThreadcaller, 8
- Intent intent, String resolvedType, IIntentReceiver resultTo,
- int resultCode, String resultData, Bundle map,
- String requiredPermission, boolean serialized,boolean sticky, int userId) {
- enforceNotIsolatedCaller("broadcastIntent");
- synchronized(this) {
- intent = verifyBroadcastLocked(intent);
-
- final ProcessRecord callerApp = getRecordForAppLocked(caller);
- final int callingPid = Binder.getCallingPid();
- final int callingUid = Binder.getCallingUid();
- final long origId = Binder.clearCallingIdentity();
- int res = broadcastIntentLocked(callerApp,
- callerApp != null ?callerApp.info.packageName :null,
- intent, resolvedType,resultTo,
- resultCode, resultData,map, requiredPermission, serialized, sticky,
- callingPid, callingUid,userId);
- Binder.restoreCallingIdentity(origId);
- return res;
- }
- }
-
- private finalintcomputeOomAdjLocked(ProcessRecord app, int hiddenAdj,
- ProcessRecord TOP_APP, boolean recursed,boolean doingAll) { 9
- ...
- return app.curRawAdj;
- }
-
- final voidperformAppGcLocked(ProcessRecord app) { 10
- try {
- app.lastRequestedGc = SystemClock.uptimeMillis();
- if(app.thread != null) {
- if (app.reportLowMemory) {
- app.reportLowMemory = false;
- app.thread.scheduleLowMemory();
- } else {
- app.thread.processInBackground();
- }
- }
- } catch (Exception e) {
- // whatever.
- }
- }
- }
ActivityManagerService.java实现的代码很长,而且并非独立工作,实际上它只是frameworks/base/services/java/com/android/server/am这个包的调用入口。因为IActivityManager这个接口类可以说是整个Android系统的“调度器”,涉及消息分发、进程管理。虽然这样的把这样大量功能揉合到一起的设计思路并不是很优雅,也不够低耦合,但从整个系统构建来看,这样的设计便很好地贯彻了简单高效的设计思路。从编程角度来看,事实上,ActivityManagerService类只不过是ActivityManagerNative接口的具体实现,并不难理解。从应用程序角度,它会直接通过进程内预置的ActivityManagerProxy对象(通过ContextImpl对象来找到)向IActivityManager的Binder接收端发命令,如果我们系统里任何一个进程或是线程创建一个ActivityManagerService对象,则所有基于IActivityManager接口进行RPC调用的地方,都将使用这一ActivityManagerService对象响应其执行请求。从前面对于Android的进程模型的分析我们也可以看到,完成这样功能的进程会是一个叫SystemServer的系统进程。于是,所有的分析得到的结果,便是如下这样的执行模型:
当系统里拥有一个ActivityManagerService的实例,则任何系统组成部分、或是应用程序,都可以使用bindService()取回合适的Binder,然后再通过这一Binder通信管道完成后续的通讯。在ActivityManagerService实例存在之后,我们后续的操作就可以都通过aidl的方式来进行了。这种使用bindService()的方式,我们在系统里偶尔用到,但并非最常用的一种。
为什么?因为这种方式很低效,每次调用前需要通过bindService()来驱动Service的有效bounded生命周期。这样的应用情境也存在,比如蓝牙、VPN等功能,系统只是偶尔要使用,使用时通过bindService()来初始化Service的上下文环境,不再用时便可以通过unbindService()取消对Service的引用,从而可以可以按需分配地使用系统提供的各种功能。但对于系统里的绝大部分功能来说,它的生存周期是一直存在的,在系统运行过程里,需要一直给不同执行部分提供其功能。这样的Service不需要生命周期的控制,在系统运行起来后就会一直在系统内存在,全局提供系统内功能的共享。这样的Service,我们一般可以称之为SystemService,它们不再使用bindService()来驱动,而直接通过一个叫ServiceManager的功能部件来实现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。