Android 外掛化分析(3)- Activity啟動流程
阿新 • • 發佈:2018-12-22
在真正分析外掛化技術前,我們必須瞭解一些必要的關於Android四大元件的相關知識。
以Activity為例,我們需要了解Activity啟動過程,才能有效的進行Hook實現外掛化。
以Android 8.1為例
我們啟動一個Activity通常會使用startActivity方法,但是在Activity內部最終都會呼叫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); ...... } else { ...... } }
在這個方法的內部實際是呼叫Instrumentation類的execStartActivity方法。
在這裡我們遇到了三個非常重要的類。
- Instrumentation : 隨著Activity內部會持有一個對Instrumentation的引用,
- ActivityThread : 主執行緒,在app啟動的時候建立的,代表了Android應用程式,裡面包含了Main函式
- ApplicationThread : App端在system程序的代理類(涉及到Binder機制)
接著會呼叫Instrumentation內部的execStartAcivitiesAsUser方法
public void execStartActivitiesAsUser(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options, int userId) { IApplicationThread whoThread = (IApplicationThread) contextThread; ...... try { ....... int result = ActivityManager.getService() .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes, token, options, userId); checkStartActivityResult(result, intents[0]); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } }
然後我們進入ActivityManager內部,getService實際返回的是一個單例物件,持有AMS在app端的遠端代理物件。
public static IActivityManager getService() { return IActivityManagerSingleton.get(); } private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { @Override protected IActivityManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } };
所以從這裡就從app程序進入到system程序。
AMS裡的程式碼很多,邏輯非常複雜,只要知道AMS會對傳遞過來的Intent進行檢查,如果需要啟動的Activity沒有在manifest裡申明,就會把錯誤碼返回給Instrumentation,從而Instrumentation就會丟擲經典的ActivityNofFoundException異常。
如果通過AMS的檢查,那麼會回撥ApplicationThread的scheduleLauncherActivity方法
@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) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
......
sendMessage(H.LAUNCH_ACTIVITY, r);
}
給H傳送了一個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);
就正式開始了Activity的啟動過程。
從以上的分析,我們是無法啟動一個沒有manifest註冊的Activity,但是外掛化技術卻可以繞過AMS的檢查達到這樣一個目的。