原来一个 App 是这样启动起来的,一看就懂,剖析 Android 开发未来的出路在哪里
###启动流程分析
点击 Launcher 上的微信图标时,会调用 startActivitySafely 方法,intent 中携带微信的关键信息也就是我们在配置文件中配置的默认启动页信息,其实在微信安装的时候,Launcher 已经将启动信息记录下来了,图标只是一个快捷方式的入口。
startActivitySafely 的方法最终还是会调用 Activity 的 startActivity 方法
@Overridepublic?void?startActivity(Intent?intent,?@Nullable?Bundle?options)?{if?(options?!=?null)?{startActivityForResult(intent,?-1,?options);}?else?{//?Note?we?want?to?go?through?this?call?for?compatibility?with//?applications?that?may?have?overridden?the?method.startActivityForResult(intent,?-1);}}
而 startActivity 方法最终又会回到 startActivityForResult 方法,这里 startActivityForResult 的方法中 code 为-1,表示 startActivity 并不关心是否启动成功。startActivityForResult 部分方法如下所示:
public?void?startActivityForResult(@RequiresPermission?Intent?intent,?int?requestCode,@Nullable?Bundle?options)?{if?(mParent?==?null)?{options?=?transferSpringboardActivityOptions(options);Instrumentation.ActivityResult?ar?=mInstrumentation.execStartActivity(this,?mMainThread.getApplicationThread(),?mToken,?this,intent,?requestCode,?options);if?(ar?!=?null)?{mMainThread.sendActivityResult(mToken,?mEmbeddedID,?requestCode,?ar.getResultCode(),ar.getResultData());}if?(requestCode?>=?0)?{
startActivityForResult 方法中又会调用 mInstrumentation.execStartActivity 方法,我们看到其中有个参数是
mMainThread.getApplicationThread()
关于 ActivityThread 曾在 深入理解 Android 消息机制文章中提到过,ActivityThread 是在启动 APP 的时候创建的,ActivityThread 代表应用程序,而我们开发中常用的 Application 其实是 ActivityThread 的上下文,在开发中我们经常使用,但在 Android 系统中其实地位很低的。
Android 的 main 函数就在 ActivityThread 中
public?static?void?main(String[]?args)?{Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,?"ActivityThreadMain");SamplingProfilerIntegration.start();
//?CloseGuard?defaults?to?true?and?can?be?quite?spammy.??We//?disable?it?here,?but?selectively?enable?it?later?(via//?StrictMode)?on?debug?builds,?but?using?DropBox,?not?logs.CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
再回到上面方法
mMainThread.getApplicationThread()
得到的是一个 Binder 对象,代表 Launcher 所在的 App 的进程,mToken 实际也是一个 Binder 对象,代表 Launcher 所在的 Activity 通过 Instrumentation 传给 AMS,这样 AMS 就知道是谁发起的请求。
mInstrumentation.execStartActivity
instrumentation 在测试的时候经常用到,instrumentation 的官方文档:
http://developer.android.com/intl/zh-cn/reference/android/app/Instrumentation.html
这里不对 instrumentation 进行详细介绍了,我们主要接着看 mInstrumentation.execStartActivity 方法
public?Instrumentation.ActivityResult?execStartActivity(Context?who,?IBinder?contextThread,?IBinder?token,?Activity?target,?Intent?intent,?int?requestCode,?Bundle?options)?{IApplicationThread?whoThread?=?(IApplicationThread)contextThread;if(this.mActivityMonitors?!=?null)?{Object?e?=?this.mSync;synchronized(this.mSync)?{int?N?=?this.mActivityMonitors.size();
for(int?i?=?0;?i?<?N;?++i)?{Instrumentation.ActivityMonitor?am?=?(Instrumentation.ActivityM
onitor)this.mActivityMonitors.get(i);if(am.match(who,?(Activity)null,?intent))?{++am.mHits;if(am.isBlocking())?{return?requestCode?>=?0?am.getResult():null;}break;}}}}
try?{intent.setAllowFds(false);intent.migrateExtraStreamToClipData();int?var16?=?ActivityManagerNative.getDefault().startActivity(whoThread,?intent,?intent.resolveTypeIfNeeded(who.getContentResolver()),?token,?target?!=?null?target.mEmbeddedID:null,?requestCode,?0,?(String)null,?(ParcelFileDescriptor)null,?options);checkStartActivityResult(var16,?intent);}?catch?(RemoteException?var14)?{;}
return?null;}
其实这个类是一个 Binder 通信类,相当于 IPowerManager.java 就是实现了 IPowerManager.aidl,我们再来看看 getDefault 这个函数
public?static?IActivityManager?getDefault()?{return?(IActivityManager)gDefault.get();}
getDefault 方法得到一个 IActivityManager,它是一个实现了 IInterface 的接口,里面定义了四大组件的生命周期
public?static?IActivityManager?asInterface(IBinder?obj)?{if(obj?==?null)?{return?null;}?else?{IActivityManager?in?=?(IActivityManager)obj.queryLocalInterface("android.app.IActivityManager");return?(IActivityManager)(in?!=?null?in:new?ActivityManagerProxy(obj));}}
最终返回一个 ActivityManagerProxy 对象也就是 AMP,AMP 就是 AMS 的代理对象,说到代理其实就是代理模式,关于什么是代理模式以及动态代理和静态代理的使用可以持续关注我,后面会单独写篇文章进行介绍。
AMP 的 startActivity 方法
public?int?startActivity(IApplicationThread?caller,?Intent?intent,?String?resolvedType,?IBinder?resultTo,?String?resultWho,?int?requestCode,?int?startFlags,?String?profileFile,?ParcelFileDescriptor?profileFd,?Bundle?options)?throws?RemoteException?{Parcel?data?=?Parcel.obtain();Parcel?reply?=?Parcel.obtain();data.writeInterfaceToken("android.app.IActivityManager");data.writeStrongBinder(caller?!=?null?caller.asBinder():null);intent.writeToParcel(data,?0);data.writeString(resolvedType);data.writeStrongBinder(resultTo);data.writeString(resultWho);data.writeInt(requestCode);data.writeInt(startFlags);data.writeString(profileFile);if(profileFd?!=?null)?{data.writeInt(1);profileFd.writeToParcel(data,?1);}?else?{data.writeInt(0);}
主要就是将数据写入 AMS 进程,等待 AMS 的返回结果,这个过程是比较枯燥的,因为我们做插件化的时候只能对客户端 Hook,而不能对服务端操作,所以我们只能静静的看着。(温馨提示:如果文章到这儿你已经有点头晕了,那就对了,研究源码主要就是梳理整个流程,千万不要纠结源码细节,那样会无法自拔)。
AMS 处理 Launcher 的信息
评论