简单概括启动微信的流程就是:
1.Launcher通知AMS 要启动微信了,并且告诉AMS要启动的是哪个页面也就是首页是哪个页面
2.AMS收到消息告诉Launcher知道了,并且把要启动的页面记下来
3.Launcher进入Paused状态,告诉AMS,你去找微信吧
上述就是Launcher和AMS的交互过程
4.AMS检查微信是否已经启动了也就是是否在后台运行,如果是在后台运行就直接启动,如果不是,AMS会在新的进程中创建一个ActivityThread对象,并启动其中的main函数。
5.微信启动后告诉AMS,启动好了
6.AMS通过之前的记录找出微信的首页,告诉微信应该启动哪个页面
7.微信按照AMS通知的页面去启动就启动成功了。
上述阶段是微信和AMS的交互过程。那么接下来我们分析下具体过程
二 启动流程分析
1.点击Launcher上的微信图标时,会调用startActivitySafely方法,intent中携带微信的关键信息也就是我们在配置文件中配置的默认启动页信息,其实在微信安装的时候,Launcher已经将启动信息记录下来了,图标只是一个快捷方式的入口。
startActivitySafely的方法最终还是会调用Activity的startActivity方法
@Override
public 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消息机制黄林晴的博客_CSDN博客-写作技巧领域博主文章中提到过,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就知道是谁发起的请求。
2.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.ActivityMonitor)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,而不能对服务端操作,所以我们只能静静的看着。(温馨提示:如果文章到这儿你已经有点头晕了,那就对了,研究源码主要就是梳理整个流程,千万不要纠结源码细节,那样会无法自拔)。
3.AMS处理Launcher的信息
AMS告诉Launcher我知道了,那么AMS如何告诉Launcher呢?
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取
细节,那样会无法自拔)。
3.AMS处理Launcher的信息
AMS告诉Launcher我知道了,那么AMS如何告诉Launcher呢?
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
[外链图片转存中…(img-O1Nukeuw-1719087053301)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取