怎么讲
在开始这个主题之前,可能需要了解一些其它的知识,以便将这个问题讲明白,后面会以下面这个顺序开始。
- Lancher 是怎么启动的
- Launcher 做了什么
- Activity 怎么使用及需要校验什么
- Java动态代理
- Activity 是如何启动的
- 插件化是做什么
- Activity 插件化
Android 启动
Launcher 启动
Android 系统启动的最后一步是启动一个 Home 应用程序,这个应用程序用来显示系统中已经安装的应用程序,这个 Home 应用程序就是 Launcher。
Launcher 有下面几个大版本:
- Launcher.apk:android 2.1(Eclair) 版本以前。
- Launcher2.apk:android 2.2(Froyo) 推出,支持 GPU 硬件 3D 加速。
- Launcher3.apk:android 4.4(KitKat) 推出,大幅改版,桌面长按可呼出小工具,可配置,桌面个数无限。
SyetemServer 进程在启动的过程中会启动 ActivityManagerService,就是它将 Launcher 启动。
SyetemServer 进程的 run 函数里面会初始化并启动 ActivityManagerService
frameworks\base\services\java\com\android\server\SystemServer.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273private SystemServiceManager mSystemServiceManager;// TODO: remove all of these references by improving dependency resolution and boot phasesprivate PowerManagerService mPowerManagerService;private ActivityManagerService mActivityManagerService;private DisplayManagerService mDisplayManagerService;private PackageManagerService mPackageManagerService;private PackageManager mPackageManager;private ContentResolver mContentResolver;public static void main(String[] args) {new SystemServer().run();}public SystemServer() {// Check for factory test mode.mFactoryTestMode = FactoryTest.getMode();}private void run() {......// Create the system service manager.mSystemServiceManager = new SystemServiceManager(mSystemContext);// Start services.try {startBootstrapServices(); // 系统服务启动及初始化startCoreServices();startOtherServices(); // 启动 Home 程序 Launcher} catch (Throwable ex) {Slog.e("System", "******************************************");Slog.e("System", "************ Failure starting system services", ex);throw ex;}......}private void startBootstrapServices() {......// Activity manager runs the show.mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();mActivityManagerService.setSystemServiceManager(mSystemServiceManager);mActivityManagerService.setInstaller(installer);// Power manager needs to be started early because other services need it.// Native daemons may be watching for it to be registered so it must be ready// to handle incoming binder calls immediately (including being able to verify// the permissions for those calls).mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);......// The sensor service needs access to package manager service, app ops// service, and permissions service, therefore we start it after them.startSensorService();}private void startOtherServices() {......mActivityManagerService.systemReady(new Runnable() {public void run() {......}});......}ActivityManagerService 的 systemReady 函数内部
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
123456789101112131415161718192021222324252627282930313233343536public void systemReady(final Runnable goingCallback) {...// 最终会触发 startHomeActivityLocked 方法的调用...}String mTopAction = Intent.ACTION_MAIN;Intent getHomeIntent() {Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);intent.setComponent(mTopComponent);if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {intent.addCategory(Intent.CATEGORY_HOME);}return intent;}boolean startHomeActivityLocked(int userId, String reason) {......Intent intent = getHomeIntent();ActivityInfo aInfo =resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);if (aInfo != null) {intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));......if (app == null || app.instrumentationClass == null) {intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);mStackSupervisor.startHomeActivity(intent, aInfo, reason);}}return true;}匹配规则启动 Launcher
上面启动的应用程序有两个匹配规则:
Action = Intent.ACTION_MAIN
Category = Intent.CATEGORY_HOMEpackages\apps\Launcher3\AndroidManifest.xml
123456789101112131415161718<activityandroid:name="com.android.launcher3.Launcher"android:launchMode="singleTask"android:clearTaskOnLaunch="true"android:stateNotNeeded="true"android:theme="@style/Theme"android:windowSoftInputMode="adjustPan"android:screenOrientation="nosensor"android:resumeWhilePausing="true"android:taskAffinity=""android:enabled="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.HOME" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.MONKEY"/></intent-filter></activity>
Launcher 干什么
Launcher在启动过程中会请求 PackageManagerService 返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户可以通过点击这些快捷图标来启动相应的应用程序。
Launcher 模块中将加载系统 App 的逻辑放在了 LauncherModel 里面
packages\apps\Launcher3\src\com\android\launcher3\LauncherModel.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 AllAppsList mBgAllAppsList;private void loadAllApps() {// Clear the list of appsmBgAllAppsList.clear();for (UserHandleCompat user : profiles) {// Query for the set of appsfinal long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);if (DEBUG_LOADERS) {Log.d(TAG, "getActivityList took "+ (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);}// Fail if we don't have any apps// TODO: Fix this. Only fail for the current user.if (apps == null || apps.isEmpty()) {return;}// Create the ApplicationInfosfor (int i = 0; i < apps.size(); i++) {LauncherActivityInfoCompat app = apps.get(i);// This builds the icon bitmaps.mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));}final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);if (heuristic != null) {runAfterBindCompletes(new Runnable() {public void run() {heuristic.processUserApps(apps);}});}}// Post callback on main threadmHandler.post(new Runnable() {public void run() {final long bindTime = SystemClock.uptimeMillis();final Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.bindAllApplications(added);if (DEBUG_LOADERS) {Log.d(TAG, "bound " + added.size() + " apps in "+ (SystemClock.uptimeMillis() - bindTime) + "ms");}} else {Log.i(TAG, "not binding apps: no Launcher activity");}}});}
Activity 如何使用
常规配置如下
12345678<activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><activity android:name=".StubActivity"/>启动
123Intent intent = new Intent(MainActivity.this, StubActivity.class);startActivity(intent);startActivityForResult(intent, 0);
Java 动态代理
JDK 提供了动态代理方法,来让我们在插件化的时候很方便的实现各种代理功能。
Proxy.newProxyInstance
创建代理接口
InvocationHandler
代理方法调用
插件化做什么
一个简单的需求:宿主如何启动插件包中的服务或者UI
瓶颈
- 65536
- 功能模块的解耦和开发团队的分离是趋势,各个团队维护一个 App 的不同模块,那么就存在一个模块升级与 App 升级的问题
要做什么
代码加载
类的加载可以使用 ClassLoader
还需要解决:- 生命周期管理
- 类之间的依赖怎么处理
资源加载
使用 AssetManager 的 addAssetPath 来加载,但资源加载最重要的一个问题便是宿主与插件之间的资源调用及冲突问题终极目标
- 宿主只负责 App 启动及插件服务的加载,不处理业务逻辑
- 插件负责处理业务,通过服务器配置选择功能上线
- 插件化开发过程是自由的
插件化手段
插件化实际上是偷天换日,在插件化过程中我们找到那些相对不容易发生变化的变量。- 寻找 Hook 点
- 寻找 静态变量/单例
- 创建代理
Activity 的启动
继承关系
|
|
启动过程
流程图如下:
1. startActivity
frameworks\base\core\java\android\app\Activity.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 public void startActivity(Intent intent) {this.startActivity(intent, null);}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);}}public void startActivityForResult(Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);}public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {if (mParent == null) {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) {// If this start is requesting a result, we can avoid making// the activity visible until the result is received. Setting// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the// activity hidden during this time, to avoid flickering.// This can only be done when a result is requested because// that guarantees we will get information back when the// activity is finished, no matter what happens to it.mStartedActivity = true;}cancelInputsAndStartExitTransition(options);// TODO Consider clearing/flushing other event sources and events for child windows.} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {// Note we want to go through this method for compatibility with// existing applications that may have overridden it.mParent.startActivityFromChild(this, intent, requestCode);}}}
2. Instrumentation.execStartActivity
frameworks\base\core\java\android\app\Instrumentation.java
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {IApplicationThread whoThread = (IApplicationThread) contextThread;Uri referrer = target != null ? target.onProvideReferrer() : null;if (referrer != null) {intent.putExtra(Intent.EXTRA_REFERRER, referrer);}if (mActivityMonitors != null) {synchronized (mSync) {final int N = mActivityMonitors.size();for (int i=0; i<N; i++) {final ActivityMonitor am = mActivityMonitors.get(i);if (am.match(who, null, intent)) {am.mHits++;if (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}}try {intent.migrateExtraStreamToClipData();intent.prepareToLeaveProcess();int result = ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);// 检测 AMS 校验返回的结果checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;}public static void checkStartActivityResult(int res, Object intent) {if (res >= ActivityManager.START_SUCCESS) {return;}switch (res) {case ActivityManager.START_INTENT_NOT_RESOLVED:case ActivityManager.START_CLASS_NOT_FOUND:if (intent instanceof Intent && ((Intent)intent).getComponent() != null)throw new ActivityNotFoundException("Unable to find explicit activity class "+ ((Intent)intent).getComponent().toShortString()+ "; have you declared this activity in your AndroidManifest.xml?");throw new ActivityNotFoundException("No Activity found to handle " + intent);case ActivityManager.START_PERMISSION_DENIED:throw new SecurityException("Not allowed to start activity "+ intent);case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:throw new AndroidRuntimeException("FORWARD_RESULT_FLAG used while also requesting a result");case ActivityManager.START_NOT_ACTIVITY:throw new IllegalArgumentException("PendingIntent is not an activity");case ActivityManager.START_NOT_VOICE_COMPATIBLE:throw new SecurityException("Starting under voice control not allowed for: " + intent);case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY:// Fail silently for this case so we don't break current apps.// TODO(b/22929608): Instead of failing silently or throwing an exception,// we should properly position the activity in the stack (i.e. behind all current// user activity/task) and not change the positioning of stacks.Log.e(TAG,"Not allowed to start background user activity that shouldn't be displayed"+ " for all users. Failing silently...");break;default:throw new AndroidRuntimeException("Unknown error code "+ res + " when starting " + intent);}}
3. ActivityManagerNative.getDefault().startActivity
目前为止,所有操作实际是在当前应用进程中完成。
ActivityManagerNative getDefault() 返回的是一个 IActivityManager 它是一个 IBinder 对象,Android 中的跨进程通讯基本都是使用它。
getDefault 里面会通过 Binder 机制获取 AMS 系统服务
core\java\android\app\ActivityManagerNative.java
12345678910111213141516 static public IActivityManager getDefault() {return gDefault.get();}private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {protected IActivityManager create() {IBinder b = ServiceManager.getService("activity");if (false) {Log.v("ActivityManager", "default service binder = " + b);}IActivityManager am = asInterface(b);if (false) {Log.v("ActivityManager", "default service = " + am);}return am;}};
从它的名字可以看出来,它是 ActivityManagerService 在应用 APP 本地(Native)的通讯代理,Actvity 与 ActivityManagerService(AMS) 的所有通讯都是通过它。
core\java\android\app\IActivityManager.java
12345678910111213 /*** System private API for talking with the activity manager service. This* provides calls from the application back to the activity manager.** {@hide}*/public interface IActivityManager extends IInterface {...public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,ProfilerInfo profilerInfo, Bundle options) throws RemoteException;...}
4. ActivityManagerService.startActivity
services\core\java\com\android\server\am\ActivityManagerService.java
1234567891011121314151617181920 public final int startActivity(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle options) {return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,resultWho, requestCode, startFlags, profilerInfo, options,UserHandle.getCallingUserId());}public final int startActivityAsUser(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {enforceNotIsolatedCaller("startActivity");userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,false, ALLOW_FULL_ONLY, "startActivity", null);// TODO: Switch to user app stacks here.return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,profilerInfo, null, null, options, false, userId, null, null);}
5. ActivityStackSupervisor.startActivityMayWait
Activity 的生命周期及栈管理都是通过 ActivityStack 来完成,而 ActivityStackSupervisor 刚负责统筹所有的 ActvityStack 管理
- mHomeStack:Launcher 管理
- mFocusedStack:当前活动
- mLastFocusedStack:上一次活动
services\core\java\com\android\server\am\ActivityStackSupervisor.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 /** The stack containing the launcher app. Assumed to always be attached to* Display.DEFAULT_DISPLAY. */private ActivityStack mHomeStack;/** The stack currently receiving input or launching the next activity. */private ActivityStack mFocusedStack;/** If this is the same as mFocusedStack then the activity on the top of the focused stack has* been resumed. If stacks are changing position this will hold the old stack until the new* stack becomes resumed after which it will be set to mFocusedStack. */private ActivityStack mLastFocusedStack;final int startActivityMayWait(IApplicationThread caller, int callingUid,String callingPackage, Intent intent, String resolvedType,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int startFlags,ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,Bundle options, boolean ignoreTargetSecurity, int userId,IActivityContainer iContainer, TaskRecord inTask) {...// intent 参数处理...int res = startActivityLocked(caller, intent, resolvedType, aInfo,voiceSession, voiceInteractor, resultTo, resultWho,requestCode, callingPid, callingUid, callingPackage,realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,componentSpecified, null, container, inTask);...}final int startActivityLocked(IApplicationThread caller,Intent intent, String resolvedType, ActivityInfo aInfo,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode,int callingPid, int callingUid, String callingPackage,int realCallingPid, int realCallingUid, int startFlags, Bundle options,boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,ActivityContainer container, TaskRecord inTask) {......if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {// We couldn't find a class that can handle the given Intent.// That's the end of that!err = ActivityManager.START_INTENT_NOT_RESOLVED;}if (err == ActivityManager.START_SUCCESS && aInfo == null) {// We couldn't find the specific class specified in the Intent.// Also the end of the line.err = ActivityManager.START_CLASS_NOT_FOUND;}......err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,startFlags, true, options, inTask);}
如果启动的 Activity 在 AndroidManifest.xml 中没有注册,上面这里会有一个 ActivityManager.START_CLASS_NOT_FOUND 错误码判断返回,返回后可以在应用进程 App 端执行校验 checkStartActivityResult
6. ActivityStackSupervisor.realStartActivityLocked
|
|
7. ProcessRecord.thread
这个类保存了所有正在运行的 java 进程信息。
services\core\java\com\android\server\am\ProcessRecord.java
123 final class ProcessRecord {IApplicationThread thread;}
app.thread 实际上是一个 IApplicationThread 对象
core\java\android\app\IApplicationThread.java
12345678910111213 public interface IApplicationThread extends IInterface {...void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving,int configChanges, boolean dontReport) throws RemoteException;void scheduleStopActivity(IBinder token, boolean showWindow,int configChanges) throws RemoteException;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) throws RemoteException;}
这里 IApplicationThread 实际也是一个 IBinder 对象,从名字可以看出,它是 AMS 与 App 所在进程通讯的桥梁。
8. ApplicationThreadNative
这个里面有一个 ApplicationThreadProxy,它就是与 AMS 通讯的代理
core\java\android\app\ApplicationThreadNative.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 class ApplicationThreadProxy implements IApplicationThread {private final IBinder mRemote;public ApplicationThreadProxy(IBinder remote) {mRemote = remote;}public final IBinder asBinder() {return mRemote;}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) throws RemoteException {Parcel data = Parcel.obtain();data.writeInterfaceToken(IApplicationThread.descriptor);intent.writeToParcel(data, 0);data.writeStrongBinder(token);data.writeInt(ident);info.writeToParcel(data, 0);curConfig.writeToParcel(data, 0);if (overrideConfig != null) {data.writeInt(1);overrideConfig.writeToParcel(data, 0);} else {data.writeInt(0);}compatInfo.writeToParcel(data, 0);data.writeString(referrer);data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);data.writeInt(procState);data.writeBundle(state);data.writePersistableBundle(persistentState);data.writeTypedList(pendingResults);data.writeTypedList(pendingNewIntents);data.writeInt(notResumed ? 1 : 0);data.writeInt(isForward ? 1 : 0);if (profilerInfo != null) {data.writeInt(1);profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);} else {data.writeInt(0);}mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,IBinder.FLAG_ONEWAY);data.recycle();}}
然后,ApplicationThreadNative 会有一个对 ApplicationThreadProxy 的引用
9. ActivityThread.ApplicationThread.scheduleLaunchActivity
这里会通过 mH 这个 Handler,完成消息到主线程的转发
core\java\android\app\ActivityThread.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 // ActivityThread 成员变量 mAppThread 的方法调用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();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);sendMessage(H.LAUNCH_ACTIVITY, r);}// 最终调用到此时 完成消息 到 主线程的转发private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {if (DEBUG_MESSAGES) Slog.v(TAG, "SCHEDULE " + what + " " + mH.codeToString(what)+ ": " + arg1 + " / " + obj);Message msg = Message.obtain();msg.what = what;msg.obj = obj;msg.arg1 = arg1;msg.arg2 = arg2;if (async) {msg.setAsynchronous(true);}mH.sendMessage(msg);}// ActivityThread 成员变量 mH 的方法调用public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {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);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;}}private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {...Activity a = performLaunchActivity(r, customIntent);...}
10. performLaunchActivity
Activity被真实的创建
core\java\android\app\ActivityThread.java
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 // 真正创建 Activity 的地方private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");ActivityInfo aInfo = r.activityInfo;if (r.packageInfo == null) {r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);}ComponentName component = r.intent.getComponent();if (component == null) {component = r.intent.resolveActivity(mInitialApplication.getPackageManager());r.intent.setComponent(component);}if (r.activityInfo.targetActivity != null) {component = new ComponentName(r.activityInfo.packageName,r.activityInfo.targetActivity);}Activity activity = null;try {// 使用 ClassLoader new Activityjava.lang.ClassLoader cl = r.packageInfo.getClassLoader();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);}}// 创建 Application (如果还没有创建成功的话),后面就调用回调try {Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (localLOGV) Slog.v(TAG, "Performing launch of " + r);if (localLOGV) Slog.v(TAG, r + ": app=" + app+ ", appName=" + app.getPackageName()+ ", pkg=" + r.packageInfo.getPackageName()+ ", comp=" + r.intent.getComponent().toShortString()+ ", dir=" + r.packageInfo.getAppDir());if (activity != null) {Context appContext = createBaseContextForActivity(r, activity);CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor);if (customIntent != null) {activity.mIntent = customIntent;}r.lastNonConfigurationInstances = null;activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource();if (theme != 0) {activity.setTheme(theme);}activity.mCalled = false;if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onCreate()");}r.activity = activity;r.stopped = true;if (!r.activity.mFinished) {activity.performStart();r.stopped = false;}if (!r.activity.mFinished) {if (r.isPersistable()) {if (r.state != null || r.persistentState != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,r.persistentState);}} else if (r.state != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);}}if (!r.activity.mFinished) {activity.mCalled = false;if (r.isPersistable()) {mInstrumentation.callActivityOnPostCreate(activity, r.state,r.persistentState);} else {mInstrumentation.callActivityOnPostCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onPostCreate()");}}}r.paused = true;mActivities.put(r.token, r);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;}
Activity 插件化
上面流程是完整的 Activity 启动流程,简单一点逻辑如下:
由于 SystemServer 是系统进程,我们无法处理,所以需要在第一步及最后一步作插件化准备。
目的
启动一个在没有在 AndroidManifest.xml 中注册的 Activity。
我们要实现下面的代码启动 TargetActivity,因为 TargetActivity没有在xml中配置,所以这里应该会报错
使用 ProxyActivity 欺骗 AMS
由于 Activity 的调用逻辑很复杂,在进入 AMS 调用之间,我们 hook 的时机越早,出现问题的可能性越大,因为后续的调用越容易出问题。
App 进程在进入 SystemServer 进程的最后一步是在 ActivityManagerNative.getDefault()
这是一个静态变量,同时是单例
我们需要 hook 掉 IActivityManager.startActivity 方法,在里面把 TargetActivity 换成 ProxyActivity
123456789101112131415161718192021 static public IActivityManager getDefault() {return gDefault.get();}private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {protected IActivityManager create() {IBinder b = ServiceManager.getService("activity");if (false) {Log.v("ActivityManager", "default service binder = " + b);}IActivityManager am = asInterface(b);if (false) {Log.v("ActivityManager", "default service = " + am);}return am;}};// 需要 hook 的方法public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
这里要使用动态代理:
选择 hook 的方法 startActivity
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253class IActivityManagerHandler implements InvocationHandler {private static final String TAG = "IActivityManagerHandler";// 定义一个代理对象Object mProxy;// 保存真身public IActivityManagerHandler(Object body) {mProxy = body;}// 选择需要代理重写的方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if ("startActivity".equals(method.getName())) {Intent realIntent;int index = 0;// 找到 Intent 参数for (int i = 0; i < args.length; i++) {if (args[i] instanceof Intent) {index = i;break;}}realIntent = (Intent) args[index];// 创建新的 IntentIntent newIntent = new Intent();// ProxyActivity 的包名String stubPackage = "com.test.hook.app";// 这里我们把启动的 Activity临时替换为 ProxyActivityComponentName componentName = new ComponentName(stubPackage, ProxyActivity.class.getName());newIntent.setComponent(componentName);// 把我们原始要启动的 TargetActivity 先存起来newIntent.putExtra("REAL_INTENT", realIntent);// 替换掉Intent, 达到欺骗AMS的目的args[index] = newIntent;Log.d(TAG, "hook success");// hookreturn method.invoke(mProxy, args);}// 这里我们只处理 startActivity 方法,其它方法不动return method.invoke(mProxy, args);}}替换代理对象
123456789101112131415161718192021222324public static void hookActivityManagerNative() throws ClassNotFoundException,NoSuchMethodException, InvocationTargetException,IllegalAccessException, NoSuchFieldException {Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");gDefaultField.setAccessible(true);Object gDefault = gDefaultField.get(null);// gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的字段Class<?> singleton = Class.forName("android.util.Singleton");Field mInstanceField = singleton.getDeclaredField("mInstance");mInstanceField.setAccessible(true);// ActivityManagerNative 的 gDefault对象里面原始的 IActivityManager对象Object realIActivityManager = mInstanceField.get(gDefault);// 创建一个这个对象的代理对象, 然后替换这个字段, 让我们的代理对象帮忙干活Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class<?>[] { iActivityManagerInterface }, new IActivityManagerHandler(realIActivityManager));mInstanceField.set(gDefault, proxy);}
ProxyActivity -> TargetActivity
由于之前替换了 TargetActivity,所以需要在合适的时候换回来。
只有在 AMS 校验逻辑完成以后,流程进入 App 进程之后,这里可以选择 ActivityThread(静态变量) 的 Handler mH,它是一个 final 对象,根据 Handler 的工作原理,我只可以 hook 掉它的 Callback,我们自定义一个 Callback 处理自己的逻辑。
选择 hook 的方法 Callback
1234567891011121314151617181920212223242526272829303132333435363738394041424344class ActivityThreadHandlerCallback implements Handler.Callback {Handler mProxy;public ActivityThreadHandlerCallback(Handler body) {mProxy = body;}public boolean handleMessage(Message msg) {switch (msg.what) {// 只处理这个消息// ActivityThread里面 "LAUNCH_ACTIVITY" 这个字段的值是100case 100:handleLaunchActivity(msg);break;}mProxy.handleMessage(msg);return true;}private void handleLaunchActivity(Message msg) {// 这里简单起见,直接取出TargetActivity;Object obj = msg.obj;try {// 把替身恢复成真身Field intent = obj.getClass().getDeclaredField("intent");intent.setAccessible(true);Intent realIntent = (Intent) intent.get(obj);// 获取之前保存的intent对象Intent target = realIntent.getParcelableExtra("REAL_INTENT");realIntent.setComponent(target.getComponent());} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}替换代理
12345678910111213141516171819public static void hookActivityThreadHandler() throws Exception {// 先获取到当前的 ActivityThread 对象Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");currentActivityThreadField.setAccessible(true);Object currentActivityThread = currentActivityThreadField.get(null);// 由于 ActivityThread一个进程只有一个,我们获取这个对象的 mHField mHField = activityThreadClass.getDeclaredField("mH");mHField.setAccessible(true);Handler mH = (Handler) mHField.get(currentActivityThread);// 获取 mCallback 字段Field mCallBackField = Handler.class.getDeclaredField("mCallback");mCallBackField.setAccessible(true);mCallBackField.set(mH, new ActivityThreadHandlerCallback(mH));}
最终调用
|
|
以上只是借鉴于 Activity 的启动方式,顺便梳理一下如何使用 java 动态代理来完成 Activity 的简单插件化, 之所以说简单,是因为这里还有很多问题没有解决,最重要的是 插件包 与 宿主的分离 以及 ClassLoader 的加载,后面会作一个专题另外讲解。