android外掛化在9.0上外掛activity的theme失效問題

android外掛化在9。0上外掛activity的theme失效問題(VirtualApk)

在使用VirtualApk的時候,發現在android 9。0上,外掛中的Activity配置的theme失效

這個問題和Android系統程式碼修改有關,我們看下9。0前後設定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中進行了Activity的建立和theme的設定。而這個theme是從引數ActivityClientRecord r獲取,看到performLaunchActivity被呼叫的地方

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {//。。。省略程式碼

Activity a = performLaunchActivity(r, customIntent);}

繼續找到

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中呼叫的handleLaunchActivity。正是如此,給了我們hook修改的機會,看到VirtualApk的處理VAInstrumentation中

@Overridepublic 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,也就是在系統處理LAUNCH_ACTIVITY訊息時,virtualApk會先處理,獲取到對應的ActivityClientRecord,然後修改activityInfo中的theme為外掛的theme。

那為什麼在9。0後就不行了呢,我們看下9。0這部分的原始碼

呵,好傢伙,根本就沒有LAUNCH_ACTIVITY這個定義了,所以hook失效,根本就沒有設定外掛的theme

那系統是怎麼呼叫的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 mPendingResults;

private List 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);

}

這個execute又是在哪執行的呢?找到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建立的地方,而mService。getLifecycleManager()。scheduleTransaction(clientTransaction);是如何執行的呢

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();

}

}

其實就是執行了 transaction的client的schedule()方法。繼續看到

public void schedule() throws RemoteException {

mClient。scheduleTransaction(this);

}

這裡個client是什麼,會到建立的地方看到

final ClientTransaction clientTransaction = ClientTransaction。obtain(app。thread,

r。appToken);

咱們的IApplicationThread嘛。看到他的scheduleTransaction

@Override

public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {

ActivityThread。this。scheduleTransaction(transaction);

}

繼續看到 ActivityThread

void scheduleTransaction(ClientTransaction transaction) {

transaction。preExecute(this);

sendMessage(ActivityThread。H。EXECUTE_TRANSACTION, transaction);

}

這下是不是很清晰了,就是把 ClientTransaction 透過Handler傳送給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下。我們在回顧下設定的地方

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。而execute執行的就是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);

}

到這裡整個流程就穿起來了。 所以知道為什麼VirtualApk在9。0上為什麼設定的theme沒有效果,因為系統啟動的呼叫方式已經發生了改變。

那現在我們如何去修改呢。同理看到Handler處理的地方

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。 繼續反射獲取到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實際為clienttransaction

Object r = msg。obj;

try {

Class clientClazz = r。getClass();

Field fCallbacks = clientClazz。getDeclaredField(“mActivityCallbacks”);

fCallbacks。setAccessible(true);

//得到transactionz中的callbacks,為一個list,獲取其中元素為LaunchActivityItem

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;

}

TAG: ThemetransactionIntentClientPRIVATE