android插件化在9.0上插件activity的theme失效問題(VirtualApk)
在使用VirtualApk的時(shí)候,發(fā)現(xiàn)在android 9.0上揽碘,插件中的Activity配置的theme失效
這個(gè)問題和Android系統(tǒng)代碼修改有關(guān)念恍,我們看下9.0前后設(shè)置theme的變化在哪里。
看到ActivityThread中
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//...省略代碼
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//...省略代碼
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, window, r.configCallback);
//...省略代碼
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
}
在performLaunchActivity
中進(jìn)行了Activity的創(chuàng)建和theme的設(shè)置。而這個(gè)theme是從參數(shù)ActivityClientRecord r
獲取翠订,看到performLaunchActivity
被調(diào)用的地方
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
//...省略代碼
Activity a = performLaunchActivity(r, customIntent);
}
繼續(xù)找到
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, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
在ActivityThread的Handler中調(diào)用的handleLaunchActivity
。正是如此鼓鲁,給了我們hook修改的機(jī)會(huì)蕴轨,看到VirtualApk的處理VAInstrumentation
中
@Override
public boolean handleMessage(Message msg) {
if (msg.what == LAUNCH_ACTIVITY) {
// ActivityClientRecord r
Object r = msg.obj;
try {
Reflector reflector = Reflector.with(r);
Intent intent = reflector.field("intent").get();
intent.setExtrasClassLoader(mPluginManager.getHostContext().getClassLoader());
ActivityInfo activityInfo = reflector.field("activityInfo").get();
if (PluginUtil.isIntentFromPlugin(intent)) {
int theme = PluginUtil.getTheme(mPluginManager.getHostContext(), intent);
if (theme != 0) {
Log.i(TAG, "resolve theme, current theme:" + activityInfo.theme + " after :0x" + Integer.toHexString(theme));
activityInfo.theme = theme;
}
}
} catch (Exception e) {
Log.w(TAG, e);
}
Virtual 給ActivityThread中的Handler增加了自己的callback,也就是在系統(tǒng)處理LAUNCH_ACTIVITY
消息時(shí)骇吭,virtualApk會(huì)先處理橙弱,獲取到對(duì)應(yīng)的ActivityClientRecord
,然后修改activityInfo
中的theme
為插件的theme燥狰。
那為什么在9.0后就不行了呢棘脐,我們看下9.0這部分的源碼
呵,好家伙龙致,根本就沒有LAUNCH_ACTIVITY
這個(gè)定義了蛀缝,所以hook失效,根本就沒有設(shè)置插件的theme
那系統(tǒng)是怎么調(diào)用的handleLaunchActivity
呢目代?
我們找到LaunchActivityItem
public class LaunchActivityItem extends ClientTransactionItem {
private Intent mIntent;
private int mIdent;
private ActivityInfo mInfo;
private Configuration mCurConfig;
private Configuration mOverrideConfig;
private CompatibilityInfo mCompatInfo;
private String mReferrer;
private IVoiceInteractor mVoiceInteractor;
private int mProcState;
private Bundle mState;
private PersistableBundle mPersistentState;
private List<ResultInfo> mPendingResults;
private List<ReferrerIntent> mPendingNewIntents;
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
client.updateProcessState(mProcState, false);
client.updatePendingConfiguration(mCurConfig);
}
@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);
}
這個(gè)execute
又是在哪執(zhí)行的呢屈梁?找到ActivityStackSupervisor
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
我們找到LaunchActivityItem
創(chuàng)建的地方,而mService.getLifecycleManager().scheduleTransaction(clientTransaction);
是如何執(zhí)行的呢
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
if (!(client instanceof Binder)) {
// If client is not an instance of Binder - it's a remote call and at this point it is
// safe to recycle the object. All objects used for local calls will be recycled after
// the transaction is executed on client in ActivityThread.
transaction.recycle();
}
}
其實(shí)就是執(zhí)行了 transaction的client的schedule()
方法榛了。繼續(xù)看到
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
這里個(gè)client是什么在讶,會(huì)到創(chuàng)建的地方看到
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
咱們的IApplicationThread嘛∷螅看到他的scheduleTransaction
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
繼續(xù)看到 ActivityThread
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
這下是不是很清晰了构哺,就是把 ClientTransaction 通過Handler發(fā)送給ActivityThread來處理
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;
看到如何execute
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
log("End resolving transaction");
}
看到executeCallbacks
@VisibleForTesting
public void executeCallbacks(ClientTransaction transaction) {
//...省略代碼
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
item.execute(mTransactionHandler, token, mPendingActions);
//...省略代碼
}
}
這下清楚了把,把添加的callbacks execute下战坤。我們?cè)诨仡櫹略O(shè)置的地方
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, mService.isNextTransitionForward(),
profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
設(shè)置了LaunchActivityItem曙强。而execute執(zhí)行的就是handleLaunchActivity
@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);
}
到這里整個(gè)流程就穿起來了。 所以知道為什么VirtualApk在9.0上為什么設(shè)置的theme沒有效果途茫,因?yàn)橄到y(tǒng)啟動(dòng)的調(diào)用方式已經(jīng)發(fā)生了改變碟嘴。
那現(xiàn)在我們?nèi)绾稳バ薷哪亍M砜吹紿andler處理的地方
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;
我們可以獲取到 ClientTransaction囊卜。 然后再反射獲取到 mActivityCallbacks臀防。判斷如果是LaunchActivityItem眠菇。 繼續(xù)反射獲取到ActivityInfo。這里附上完整的修改代碼
@Override
public boolean handleMessage(Message msg) {
if (msg.what == LAUNCH_ACTIVITY) {
// ActivityClientRecord r
Object r = msg.obj;
try {
Reflector reflector = Reflector.with(r);
Intent intent = reflector.field("intent").get();
intent.setExtrasClassLoader(mPluginManager.getHostContext().getClassLoader());
ActivityInfo activityInfo = reflector.field("activityInfo").get();
if (PluginUtil.isIntentFromPlugin(intent)) {
int theme = PluginUtil.getTheme(mPluginManager.getHostContext(), intent);
if (theme != 0) {
Log.i(TAG, "resolve theme, current theme:" + activityInfo.theme + " after :0x" + Integer.toHexString(theme));
activityInfo.theme = theme;
}
}
} catch (Exception e) {
Log.w(TAG, e);
}
} else if (msg.what == 159) {
//r實(shí)際為clienttransaction
Object r = msg.obj;
try {
Class clientClazz = r.getClass();
Field fCallbacks = clientClazz.getDeclaredField("mActivityCallbacks");
fCallbacks.setAccessible(true);
//得到transactionz中的callbacks,為一個(gè)list,獲取其中元素為L(zhǎng)aunchActivityItem
List<?> lists = (List) fCallbacks.get(r);
for (int i = 0; i < lists.size(); i++) {
Object item = lists.get(i);
Class itemClazz = item.getClass();
Log.w(TAG, "class--->" + itemClazz.getName());
if (!(itemClazz.getSimpleName().equals("LaunchActivityItem"))) {
return false;
}
//獲取成員 mIntent
Log.w(TAG, "=======get " + itemClazz.getName());
Field mIntent = itemClazz.getDeclaredField("mIntent");
mIntent.setAccessible(true);
Intent intent = (Intent) mIntent.get(item);
Log.w(TAG, "=======get intent " + intent);
//ActivityInfo mInfo
Field activityInfoField = itemClazz.getDeclaredField("mInfo");
activityInfoField.setAccessible(true);
ActivityInfo activityInfo = (ActivityInfo) activityInfoField.get(item);
Log.w(TAG, "=======get ActivityInfo " + activityInfoField);
intent.setExtrasClassLoader(mPluginManager.getHostContext().getClassLoader());
if (PluginUtil.isIntentFromPlugin(intent)) {
//獲取插件主題
int theme = PluginUtil.getTheme(mPluginManager.getHostContext(), intent);
if (theme != 0) {
Log.i(TAG, "resolve theme, current theme:" + activityInfo.theme + " after :0x" + Integer.toHexString(theme));
activityInfo.theme = theme;
}
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return false;
}