文章目录
Android 插件化系列文章目录
前言
一、从源码角度分析加载资源流程
1、ActivityThread 入口
2、LaunchActivityItem
3、ActivityThread.performLaunchActivity
4、ContextImpl
二、Hook 点选择
三、资源冲突解决方案
四、博客资源
前言
在之前的博客 【Android 插件化】Hook 插件化框架 ( 插件包资源加载 ) 中 , 实现了从插件包中获取资源 ;
但是这种方法对代码的侵入性较大 , 使用这种方式开发 , 插件应用 和 宿主应用 , 都需要对 Resources 进行特别处理 , 如重写 Activity 和 Application 的 public Resources getResources() 方法 ;
最好是使用 Hook 方式加载资源文件 , 实现插件包代码 0 侵入 , 开发插件应用 与 开发普通应用 , 基本一致 ;
一、从源码角度分析加载资源流程
在插件包中的 Activity , 如果加载 R.layout.activity_main , 拿到的是 “宿主” 应用中的资源 , 无法拿到插件包中的资源 ;
1、ActivityThread 入口
在 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 ) 博客中 , 分析了 Activity 在主线程启动前的一些操作 ;
在 ActivityThread 中的 mH 处理 EXECUTE_TRANSACTION 信号时 , 其中 ClientTransaction 中有 LaunchActivityItem ;
public final class ActivityThread extends ClientTransactionHandler { final H mH = new H(); /** Reference to singleton {@link ActivityThread} */ private static volatile ActivityThread sCurrentActivityThread; class H extends Handler { public static final int EXECUTE_TRANSACTION = 159; public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case EXECUTE_TRANSACTION: final ClientTransaction transaction = (ClientTransaction) msg.obj; mTransactionExecutor.execute(transaction); if (isSystem()) { // Client transactions inside system process are recycled on the client side // instead of ClientLifecycleManager to avoid being cleared before this // message is handled. transaction.recycle(); } // TODO(lifecycler): Recycle locally scheduled transactions. break; } } } }
源码路径 : /frameworks/base/core/java/android/app/ActivityThread.java
2、LaunchActivityItem
LaunchActivityItem 中的 execute 方法中的 ClientTransactionHandler client 参数 就是 ActivityThread ;
public class LaunchActivityItem extends ClientTransactionItem { @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mIsForward, mProfilerInfo, client); client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } }
源码路径 : /frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
3、ActivityThread.performLaunchActivity
在 LaunchActivityItem 的 execute 方法中 , 调用 client.handleLaunchActivity 方法就是执行的 ActivityThread 的 handleLaunchActivity 方法 ;
在 ActivityThread 中的 handleLaunchActivity 方法中 , 调用了 performLaunchActivity 方法 ;
在 ActivityThread 中的 performLaunchActivity 方法中 , 调用
ContextImpl appContext = createBaseContextForActivity(r);
方法 , 创建了 ContextImpl 对象 ;
public final class ActivityThread extends ClientTransactionHandler { private ContextImpl createBaseContextForActivity(ActivityClientRecord r) { final int displayId; try { displayId = ActivityManager.getService().getActivityDisplayId(r.token); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } ContextImpl appContext = ContextImpl.createActivityContext( this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig); final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); // For debugging purposes, if the activity's package name contains the value of // the "debug.use-second-display" system property as a substring, then show // its content on a secondary display if there is one. String pkgName = SystemProperties.get("debug.second-display.pkg"); if (pkgName != null && !pkgName.isEmpty() && r.packageInfo.mPackageName.contains(pkgName)) { for (int id : dm.getDisplayIds()) { if (id != Display.DEFAULT_DISPLAY) { Display display = dm.getCompatibleDisplay(id, appContext.getResources()); appContext = (ContextImpl) appContext.createDisplayContext(display); break; } } } return appContext; } }
源码路径 : /frameworks/base/core/java/android/app/ActivityThread.java