Activity的启动应该分为四个过程
-
向
AMS发起启动Activity请求 -
AMS接收后通过socket方式发送fork进程的参数给到Zygote进程 -
Zygote进程接收后fork出应用进程并返回进程的pid -
应用进程通过反射调用
ActivityThread中的main方法启动ActivityThread线程
图一.jpeg
相关类说明
-
Instrumentation:这个类就是完成对Application和Activity初始化和生命周期的工具类。每个Activity都持有Instrumentation对象的一个引用,但是整个进程只会存在一个Instrumentation对象,这个Instrumentation对象存放在ActivityThread中。 -
ActivityManager:此类提供有关活动,服务和包含过程的信息和交互。 -
IActivityManager:用于与ActivityManagerService交谈的系统专用API。 提供了从应用程序返回到活动管理器的调用。 -
ActivityThread:管理应用程序进程中主线程的执行,根据ActivityManager请求调度和执行Activitys、broadcasts和其他操作。 -
ApplicationThread:ActivityThread内部类,IApplicationThread.aidl的具体实现,提供给ActivityManager,ActivityManager通过它告知应用程序将要做的事。 - H:继承Handler,ActivityThread内部类,是应用程序进程中主线程的消息管理类。(是
hook的一个点) -
ActivityManagerService:负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作。 -
ActivityStarter:用于解释如何启动活动的控制器。此类收集用于确定如何将意图和标志转变为活动以及相关任务和堆栈的所有逻辑。 -
ActivityStack: 单个活动栈的状态和管理。 -
ActivityStackSupervisor:Activity栈管理。
LAUNCHER
上图是startActivity的启动流程,通常我们点击app启动的时候,会先执行如下方法
intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(className);
startActivityForResult方法
最终调用Instrumentation的execStartActivity来启动应用
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
//...
options = transferSpringboardActivityOptions(options);
//这里调用instrumentation的execStartActivity()方法
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
} else {
//...
}
}
execStartActivity()方法
如下 ActivityManager.getService().startActivity涉及到了与AMS通信,通过getService()获取到了远程对象引用(IActivityManager接口对象),这里是一个hook activity的关键点,如果我们想启动一个没有注册的activity,那我们可以hook掉IActivityManager接口对象通过动态代理的方式截取startActivity方法,从而将已注册的代理activity传入,这样就可以让AMS检查activity为注册文件中的activity。
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
//主要是这段代码,可以看出这里会获取Service,然后调用startActivity方法
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
最终通过ActivityStarter、ActivityStack等相关类后,走到startSpecificActivityLocked方法
startSpecificActivityLocked方法
先从图一启动activity,在startSpecificActivityLocked中会根据app的processName、uid来判断是否已存在(即是否处于running状态),若是则进入realStartActivityLocked(即图二 5),否则则进入startProcessLocked方法通过socket与Zygote进程通信,由Zygote进程fork应用进程,在从应用进程中启动ActivityThread线程即app主线程,从而进入图二流程
r.info.flags&ActivityInfo.FLAG_MULTIPROCESS这个是有何用图呢?
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
Zygote进程
Zygote进程又称受精卵进程,zygote进程由init通过fork而来,由app_process启动,Zygote进程最大意义是作为一个Socket的Server端,接收着各方的进程创建请求,Android中所有的应用进程的创建都是一个应用进程通过Binder请求SystemServer进程,SystemServer进程发送socket消息给Zygote进程,统一由Zygote进程创建出来的。典型的C/S架构。
进程的启动流程:Init进程-->Zygote进程-->SystemServer进程-->应用进程
进程知识点
init:是linux系统中用户空间的第一个进程。由于Android是基于linux内核的,所以init也是Android系统中用户空间的第一个进程,它的进程号是1。
SystemServer:是由Zygote通过Zygote.forkSystemServer函数fork出来的。
应用进程:是Zygote通过fork创建的子进程
zygote进程将ZygoteInit作为启动类,会执行它的main方法,先注册ZygoteSocket,然后调用runSelectLoop方法,runSelectLoop方法会调用方法在ZygoteSocket上监听请求,如果别的进程通过ZygoteSocket请求孵化进程,则孵化进程。
Zygote进程孵化出应用进程后,会通过反射调用ActivityThread中的main方法启动ActivityThread线程,main方法中会先开启Looper和消息队列,然后调用attach方法将应用进程绑定到AMS,然后进入loop循环,不断地读取消息队列里的消息,并分发消息。
ActivityThread
ui线程又称为主线程,应用程序的入口 当启动应用程序时会由ActivityMangerService孵化一个进程,并且实例化一个ActivityThread对象,该类为final类型,并不是一个线程类
从图一的activity启动流程最终由Zygote进程孵化出应用进程后,通过反射调用ActivityThread中的main方法启动ActivityThread线程从而进入图二流程,如下图
图二.jpeg
关键方法讲解
应用进程绑定
如果要说下面的 ActivityThread main()方法,我想我应该先简单介绍下应用进程绑定,不然你可能不知道为毛AMS远程调用ActivityThread中的scheduleLaunchActivity方法
首先通过ActivityThread main()方法通过thread.attach(false)绑定应用进程。涉及到了一次IPC过程,通过将ApplicationThread实例化的对象给AMS,AMS拿到后调用其scheduleLaunchActivity方法
ApplicationThread:AMS通过attachApplication将ApplicationThread对象绑定到AMS,而ApplicationThread作为Binder实现AMS对应用进程的通信和控制。
private void attach(boolean system) {
·····
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
·····
}
ActivityThread main()方法
AMS远程调用图二 6 scheduleLaunchActivity方法后,会发送LAUNCH_ACTIVITY消息,还记得在execStartActivity()方法中,我们说过我们可以通过hook IActivityManager接口对象实现动态代理从而截取startActivity方法,将已注册的代理activity传入,但是在ActivityThread中main会开启消息循环,这个时候会读取到我们传来LAUNCH_ACTIVITY消息,而消息中的activity仍是我们hook掉后替换的代理activity,所以我们还需要进行一次hook,将main方法中的handler对象替换成我们自定义的,然后获取到消息后,将代理activity替换成我们想启动的activity,从而完美绕过activity注册检测机制
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
attachApplicationLocked方法
该方法主要判断是否需要开启新进程
ActivityStackSupervisor.java
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFocusedStack(stack)) {
continue;
}
stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
final ActivityRecord top = stack.topRunningActivityLocked();
final int size = mTmpActivityList.size();
for (int i = 0; i < size; i++) {
final ActivityRecord activity = mTmpActivityList.get(i);
if (activity.app == null && app.uid == activity.info.applicationInfo.uid
&& processName.equals(activity.processName)) {
try {
//如果应用进程与activity进程名称相等则进入,从而调起ActivityThread中的scheduleLaunchActivity方法
if (realStartActivityLocked(activity, app,
top == activity /* andResume */, true /* checkConfig */)) {
didSomething = true;
}
} catch (RemoteException e) {
}
}
}
}
}
if (!didSomething) {
//如果应用进程与activity进程名称不相等则进入如下方法即图一流程第1.9步,
//然后由SystemServer进程与Zygote进程通过socket通信,开启新的进程
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
return didSomething;
}
realStartActivityLocked方法
进入realStartActivityLocked方法后,调用app.thread.scheduleLaunchActivity方法进入ThreadActivity中的scheduleLaunchActivity方法,开始发送LAUNCH_ACTIVITY消息
ActivityStackSupervisor.java
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
····
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
····
}
scheduleLaunchActivity方法
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
//更新runtime中的进程状态
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
//组装handler消息发送
sendMessage(H.LAUNCH_ACTIVITY, r);
}
ActivityThread中消息循环接收LAUNCH_ACTIVITY
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
getPackageInfo方法
该方法由getPackageInfoNoCheck方法内部调起,主要作用是获取Package信息,其中LoadedApk对象是APK文件在内存中的表示。 Apk文件的相关信息,诸如Apk文件的代码和资源,甚至代码里面的Activity,Service等组件的信息我们都可以通过此对象获取。
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (differentUser) {
// Caching not supported across users
ref = null;
} else if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
: "Loading resource-only package ") + aInfo.packageName
+ " (in " + (mBoundApplication != null
? mBoundApplication.processName : null)
+ ")");
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
if (mSystemThread && "android".equals(aInfo.packageName)) {
packageInfo.installSystemApplicationInfo(aInfo,
getSystemContext().mPackageInfo.getClassLoader());
}
if (differentUser) {
// Caching not supported across users
} else if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
}
}
return packageInfo;
}
}
performLaunchActivity方法
该方法由handleLaunchActivity方法内部调起,主要逻辑类加载器创建Activity的实例对象
相关方法
isPersistable()方法: 多了个PersistableBundle参数,作用在于当Activity从意外结束恢复时,传递结束前保存的Activity历史数据,从而恢复现场。
mInstrumentation.newActivity方法:调起loadClass从而加载对应的classloader
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
·····
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
//重点 将Activity类文件加载到内存中,创建Activity实例
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
if (r.isPersistable()) {
//调起activity onCreate方法
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
try {
//创建application对象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
}
·····
}
Hook 掉Activity
看到这里,不得不提下插件化的一些原理知识,在稍后章节也会做详细剖析。
通常我们在插件化的时候,需要写一些新的Activity,那这个时候你不可能说在主apk中也同时注册进去吧?这样显然不可行,那肯定需要绕过AMS这个检查机制,实现无需在AndroidManifest.xml中注册也能运行。
小编目前想到的三个hook点
- hook Instrumentation
重写Instrumentation中的execStartActivity方法,将已注册的代理activity传入
重写newActivity,在ActivityThread到handler启动Activity过程会调用newActivity,这个时候取出真正需要启动的activity - hook AMS和ActivityThread中的handler.callback
通过hook掉AMS中的IActivityManager接口,实现动态代理,截取startActivity方法,将已注册的代理activity传入
在hook掉ActivityThread中的handler,替换成自定义的handler,在自定义的handler中接收LAUNCH_ACTIVITY消息,将真正需要启动的activity传入 - hook PackageInfo
通过看上文提到的getPackageInfo方法,你会发现ActivityThread中消息循环接收LAUNCH_ACTIVITY时,会先去调用getPackageInfo方法获取Package信息,而Package信息有进行缓存,即保存在mPackages容器中,你可以通过hook 往mPackages容器中放入拟定的数据
除了hook外,你也可以在宿主项目中预先在注册文件中加入需要启动的插件activity,如:
<activity android:name="com.shengyuan.pulgin1.MainActivity2"/>
其实看完源码你就会发现hook activity并不复杂,下面针对第二个方法点列出关键代码
关键代码
第一步hook AMS中的IActivityManager
替换系统的IActivityManager,主要采取动态代理的技术构造IActivityManager
注意:在android8.0上字段名称变更了
public void hookIActivityManager() throws Exception {
Log.i(TAG, "start hookIActivityManager");
Class<?> activityManagerNativeClass;
Field gDefaultFile;
/**
* 核心
* 由于IActivityManagerSingleton是单例模式,可以拿到系统该单例对象并且修改该对象
* 只有系统单例的对象修改才有效果
*/
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1){
//反射获取类
activityManagerNativeClass = Class.forName("android.app.ActivityManager");
//获取类中的字段
gDefaultFile = activityManagerNativeClass.getDeclaredField("IActivityManagerSingleton");
}else {
//反射获取类
activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
//获取类中的字段
gDefaultFile = activityManagerNativeClass.getDeclaredField("gDefault");
}
//设置字段可访问
gDefaultFile.setAccessible(true);
//获取反射字段的值,静态方法,不需要传入对象,所以对象为null
Object gDefaultFileValue = gDefaultFile.get(null);
//获取gDefault.get()的值,主要在Singleton中
Class<?> singletonClass = Class.forName("android.util.Singleton");
Field mInstanceFile = singletonClass.getDeclaredField("mInstance");
mInstanceFile.setAccessible(true);
//非静态方法,需要传入对象,获取系统的IActivityManager
Object IActivityManager = mInstanceFile.get(gDefaultFileValue);
//获取IActivityManager接口
Class<?> IActivityManagerClass = Class.forName("android.app.IActivityManager");
//接下来需要创建钩子,替换系统的IActivityManager,主要采取动态代理的技术构造IActivityManager
ProxyIActivityManager proxyIActivityManager= new ProxyIActivityManager(IActivityManager);
Object proxy = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{IActivityManagerClass},
proxyIActivityManager);
//hook 就是为了替换IActivityManager的值,以下就是替换操作
mInstanceFile.set(gDefaultFileValue, proxy);
/////////到这里为止,已经实现了用代理Activity来替换未注册的Activity,通过PackageManagerService校验////////////
//接下来找到系统的ActivityThread 并且要找到单例对象,才可以修改该对象值
}
class ProxyIActivityManager implements InvocationHandler{
private Object iActivityManager;
public ProxyIActivityManager(Object iActivityManager){
this.iActivityManager = iActivityManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.i(TAG, "ProxyIActivityManager invoke:" + method.getName());
if (method.getName().contains("startActivity")){
int index = 0;
Intent realIntent = null;
for (int i = 0; i<args.length; i++){
if (args[i] instanceof Intent){
realIntent = (Intent) args[i];//真正的Intent,无法通过PackageManagerService检查
index = I;
break;
}
}
//代理Intent,可以通过PackageManagerService检查
Intent proxyIntent = new Intent(mContext, ProxyActivity.class);
proxyIntent.putExtra(REAL_INTENT, realIntent);
args[index] = proxyIntent;
}
return method.invoke(iActivityManager, args);
}
}
第二步hook ActivityThread中的H (即Handler对象)
public void hookActivityThreadHandler() throws Exception {
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
currentActivityThreadField.setAccessible(true);
Object currentActivityThreadValue = currentActivityThreadField.get(null);
Field mHandlerField = activityThreadClass.getDeclaredField("mH");
mHandlerField.setAccessible(true);
Handler handlerValue = (Handler) mHandlerField.get(currentActivityThreadValue);
Field mCallbackField = Handler.class.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
mCallbackField.set(handlerValue, new HandlerCallback(handlerValue));
}
class HandlerCallback implements Handler.Callback{
private Handler mHandler;
public HandlerCallback(Handler handlerValue){
mHandler = handlerValue;
}
@Override
public boolean handleMessage(Message msg) {
//LAUNCH_ACTIVITY 的what值是100
if (msg.what == 100){
//先处理自己的Handler消息,再处理ActivityThread中自身的handler消息
try {
Log.i(TAG,"LAUNCH_ACTIVITY");
Object activityClientRecord = msg.obj;//ActivityClientRecord
Field intentField = activityClientRecord.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
Intent proxyIntent = (Intent) intentField.get(activityClientRecord);
Intent realIntent = (Intent) proxyIntent.getParcelableExtra(REAL_INTENT);
if (realIntent != null){
//方法一,直接替换intent
//intentField.set(activityClientRecord, realIntent);
//方法二 替换component
proxyIntent.setComponent(realIntent.getComponent());
}
}catch (Exception e){
}
}
//处理ActivityThread中自身的handler消息
mHandler.handleMessage(msg);
return true;
}
}
给大家两个思考的问题
- ActivityThread究竟是线程吗?
- 一个应用进程有多少个ActivityThread?










网友评论