标签:
这篇博客是上篇的延续,在阅读之前先阅读第一部分:第一部分
我们在启动插件的activity时,通过替换component成功欺骗AMS获得了启动一个activity所必须的一些资源。不过,我们还没有把获取的那些资源都转移到插件的activity之下。这一节就是解决这个问题。
所有的答案都是分析源码之后得到的,所以我们还和之前一样继续分析源码,看下AMS是怎么把资源关联到一个activity上的,这样我们才有可能转移这些资源到插件的activity之下。
在上一篇博文中我们分析到了startActivityLocked函数。在这个函数里面,我们在获得启动一个activity的信息,和要启动的activity信息之后,我们转到了startActivityUncheckedLocked函数:
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
boolean doResume, Bundle options, TaskRecord inTask) {
...
//用来判断是否需要重新创建一个新的任务栈来启动这个activity
//在我们这里例子里面 我们newTask会一直是false
boolean newTask = false;
boolean keepCurTransition = false;
...
// Should this be considered a new task?
if (r.resultTo == null && inTask == null && !addingToTask
&& (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
...
} else if (sourceRecord != null) {
} else ....
....
//调用ActivityStack的成员函数
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
...
return ActivityManager.START_SUCCESS;
}
之后调用的是startActivityLocked方法:
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
...
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// All activities in task are finishing.
continue;
}
if (task == r.task) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
if (!startIt) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+ task, new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
r.putInHistory();
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
r.userId, r.info.configChanges, task.voiceSession != null,
r.mLaunchTaskBehind);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
startIt = false;
}
}
}
...
//把要启动的activity压入活动栈中
task.addActivityToTop(r);
task.setFrontOfTask();
...
//我们显然是要让activity显示 所以这里一定会执行
if (doResume) {
mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}
}
这个函数做的事情很简单,就是把要启动的activity压到活动栈的栈顶,这里又证实了我们之前的猜想:
接下来我们继续转到StackSupervisor中去查看resumeTopActivitiesLocked
看下是否是最前面的一个任务活动栈(很好理解,因为你不可能一次只开一个应用,你可能在使用手机时打开QQ,微信,微博,他们都各自对应很多个活动栈),是的话就准备响应他
stack.resumeTopActivityLocked:
最后都转发到了resumeTopActivityInnerLocked
查看下:
final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
...
// We need to start pausing the current activity so the top one
// can be resumed...
boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
//调用start[
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
}
...
return true;
}
在确认一切无误之后调用startPausingLocked方法
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
boolean dontWait) {
...
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
try {
...
//prev.app.thread返回一个IApplicationThread
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
...
}
} else {
...
}
...
}
prev.app.thread返回一个IApplicationThread,它通知Ui线程可以终止当前正在响应的activity了,我要开启新的activity了!
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
在本例中就是:
为了验证我们的猜想,还是继续阅读源码:
Handler中的处理代码:
IBinder被保存在Message的obj中,之后调用handlePauseActivity函数:
//mActivities是一个map,通过IBinder映射activity client record!
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
之后的操作:
回到AMS中:
@Override
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
//通过这个IBinder找到任务栈
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
//开始准备启动新的activity了
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
NEXT:
//ActivityStack.java
final void activityPausedLocked(IBinder token, boolean timeout) {
if (DEBUG_PAUSE) Slog.v(
TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
//正常停止了就要移出检测停止activity超时的消息
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
//完成停止activity
completePauseLocked(true);
} else {
EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
}
}
}
由于篇幅限制,我们只分析到这里,之后,AMS就准备真正启动activity了:
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
...
ProfilerInfo profilerInfo = profileFile != null
? new ProfilerInfo(profileFile, profileFd, mService.mSamplingInterval,
mService.mAutoStopProfiler) : null;
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
//回调到Ui 第二个参数就是之前分析的IBinder
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
r.icicle, r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
...
return true;
}
这里回调ui线程开始真正启动一个activity
ActivityThread.java
还是和之前一样,把AMS返回的资源封装到ActivityClientRecord之后,发送message,并把资源存储在Message的obj中。
之后进入H的处理函数:
它的handleMessage函数
这里有个小知识,在handler调用handleMessage,会调用dispathMessage用来分发Message,我们从下面的源码可以看出,如果我们的message自己有callback,那么就调用Message自己的callback,否则看下handler本身的mCallback,如果mCallback不为空,那么就调用mCallback的handleMessage,并且如果返回true则直接结束,否则调用我们重载的handleMessage函数。
那么思路来了,我们首先hook H这个类的的mCallbak域,替换成我们自己的callback,当检测到处理的消息是针对StubActivity时,我们获得原来的启动插件的Intent,然后替换下component(和原来逆向的过程)
主要代码:
/**
* Created by chan on 16/4/8.
*/
public class HookApplication extends Application {
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
try {
//获得ActivityManagerNative
Class<?> serviceManagerClz = Class.forName("android.app.ActivityManagerNative", false, getClassLoader());
//获得ActivityManagerNative.getDefault静态方法
Method getDefaultMethod = serviceManagerClz.getDeclaredMethod("getDefault");
//获得原始的IActivityManager对象
Object rawIActivityManagerInterface = getDefaultMethod.invoke(null);
//我们自己的Hook的对象
Object hookIActivityManagerInterface = Proxy.newProxyInstance(
getClassLoader(),
new Class[]{Class.forName("android.app.IActivityManager", false, getClassLoader())},
new AMSHook(rawIActivityManagerInterface)
);
//反射ActivityManagerNative的gDefault域
Field gDefaultField = serviceManagerClz.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefaultObject = gDefaultField.get(null);
//他的类型是Singleton
Class<?> singletonClz = Class.forName("android.util.Singleton", false, getClassLoader());
//把他的mInstance域替换掉 成为我们自己的Hook对象
Field mInstanceField = singletonClz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
mInstanceField.set(gDefaultObject, hookIActivityManagerInterface);
Class<?> activityThreadClz = Class.forName("android.app.ActivityThread", false, getClassLoader());
Method method = activityThreadClz.getDeclaredMethod("currentActivityThread");
Object activityThreadObject = method.invoke(null);
Field mHField = activityThreadClz.getDeclaredField("mH");
mHField.setAccessible(true);
Object mHObject = mHField.get(activityThreadObject);
Field handlerCallbackField = Handler.class.getDeclaredField("mCallback");
for(Field f : Handler.class.getDeclaredFields()) {
Log.d("chan_debug", f.getName());
}
handlerCallbackField.setAccessible(true);
Object callbackObject = handlerCallbackField.get(mHObject);
Object hookHObject = new MessageHook(callbackObject, getClassLoader());
handlerCallbackField.set(mHObject, hookHObject);
} catch (ClassNotFoundException | IllegalAccessException |
NoSuchMethodException | InvocationTargetException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
package com.chan.hook.handle;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import com.chan.hook.StubActivity;
import com.chan.hook.util.Constant;
import java.lang.reflect.Field;
/**
* Created by chan on 16/4/14.
*/
public class MessageHook implements Handler.Callback {
private Handler.Callback m_base;
private static final int LAUNCH_ACTIVITY = 100;
private Field m_intentField;
public MessageHook(Object base, ClassLoader classLoader) throws ClassNotFoundException, NoSuchFieldException {
m_base = (Handler.Callback) base;
//获取ActivityClientRecord的class
Class<?> activityClientRecordClz = Class.forName("android.app.ActivityThread$ActivityClientRecord", false, classLoader);
//获得它的intent
m_intentField = activityClientRecordClz.getDeclaredField("intent");
m_intentField.setAccessible(true);
}
@Override
public boolean handleMessage(Message msg) {
//检测到时启动一个activity
if (msg.what == LAUNCH_ACTIVITY) {
try {
//msg.obj是android.app.ActivityThread$ActivityClientRecord对象,请参考前面的源码解析
Intent intent = (Intent) m_intentField.get(msg.obj);
ComponentName componentName = intent.getComponent();
//检测到是启动StubActivity
if(componentName != null &&
componentName.getClassName().equals(StubActivity.class.getCanonicalName())) {
//获得之前启动插件的intent
Intent raw = intent.getParcelableExtra(Constant.EXTRA_RAW_INTENT);
//替换成插件的component
intent.setComponent(raw.getComponent());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//之后的操作还是和原来一样
return m_base != null && m_base.handleMessage(msg);
}
}
package com.chan.hook.am;
import android.content.ComponentName;
import android.content.Intent;
import com.chan.hook.StubActivity;
import com.chan.hook.util.Constant;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Created by chan on 16/4/13.
*/
public class AMSHook implements InvocationHandler {
private Object m_base;
public AMSHook(Object base) {
m_base = base;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//拦截startActivity方法
if ("startActivity".equals(method.getName())) {
//查找原始的intent对象
Intent raw = null;
final int size = (args == null ? 0 : args.length);
int i = 0;
for (; i < size; ++i) {
if (args[i] instanceof Intent) {
raw = (Intent) args[i];
break;
}
}
//看下是否是启动插件中的activity
if (raw.getBooleanExtra(Constant.EXTRA_INVOKE_PLUGIN, false)) {
//获得原始的ComponentName
ComponentName componentName = raw.getComponent();
//创建一个新的Intent
Intent intent = new Intent();
//把Component替换为StubActivity的 这样就不会被系统检测到 启动一个没有在AndroidManifest.xml
//中声明的activity
intent.setComponent(new ComponentName(componentName.getPackageName(),
StubActivity.class.getCanonicalName()));
//保存原始的intent
intent.putExtra(Constant.EXTRA_RAW_INTENT, raw);
//替换为新的Intent
args[i] = intent;
}
}
//还是按往常一样调用各种函数
return method.invoke(m_base, args);
}
}
package com.chan.hook.util;
/**
* Created by chan on 16/4/13.
*/
public interface Constant {
String EXTRA_INVOKE_PLUGIN = "com.chan.hook.util.invoke_plugin";
String EXTRA_RAW_INTENT = "com.chan.hook.util.raw_intent";
}
package com.chan.hook.util;
import android.app.Activity;
import android.content.Intent;
/**
* Created by chan on 16/4/14.
*/
public class Utils {
public static void invokePluginActivity(Activity activity, Class<?> who) {
Intent intent = new Intent(activity, who);
intent.putExtra(Constant.EXTRA_INVOKE_PLUGIN, true);
activity.startActivity(intent);
}
}
效果:
这里解释下我们是如何hookAMS的,考虑之前我们分析如何hook一个系统服务的例子:例子,当我们启动一个activity的时候,会调用:
我们可以看下:
而这个gDefault呢是一个Singleton对象:
而他的具体实现在:
可见只要我们hook mInstance就行,而它被实例化IActivityManager对象,之后我们只需拦截其中的IActivityManager对象的startActivity方法,检测是否是标识启动一个插件activity,然后替换其中的component。
//看下是否是启动插件中的activity
if (raw.getBooleanExtra(Constant.EXTRA_INVOKE_PLUGIN, false)) {
//获得原始的ComponentName
ComponentName componentName = raw.getComponent();
//创建一个新的Intent
Intent intent = new Intent();
//把Component替换为StubActivity的 这样就不会被系统检测到 启动一个没有在AndroidManifest.xml
//中声明的activity
intent.setComponent(new ComponentName(componentName.getPackageName(),
StubActivity.class.getCanonicalName()));
//保存原始的intent
intent.putExtra(Constant.EXTRA_RAW_INTENT, raw);
//替换为新的Intent
args[i] = intent;
}
android插件开发-就是你了!启动吧!插件的activity(二)
标签:
原文地址:http://blog.csdn.net/u013022222/article/details/51148832