如何应对Andriod面试官 -> 如何 Hook Activity 的启动流程?

前言


image.png

本章继续讲解 AMS 相关的知识点,如何 Hook Activity 的启动流程;

attach


我们这样直接从 attach 入口讲起

private void attach(boolean system, long startSeq) {
    // 省略部分代码
    // AMS
    final IActivityManager mgr = ActivityManager.getService();
    try {
        // 这里直接调用到了 AMS 的 attachApplication 方法;
        mgr.attachApplication(mAppThread, startSeq);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    } 
}

attach 中直接调用到了 AMS 的 attachApplication 方法,我们进入这个方法看下:

public final void attachApplication(IApplicationThread thread, long startSeq) {
    if (thread == null) {
        throw new SecurityException("Invalid application interface");
    }
    synchronized (this) {
        // 获取调用端的 pid
        int callingPid = Binder.getCallingPid();
        // 获取调用端的 uid
        final int callingUid = Binder.getCallingUid();
        // 把 pid/uid 设置成 AMS 的
        final long origId = Binder.clearCallingIdentity();
        // 
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        // 恢复为 app 的
        Binder.restoreCallingIdentity(origId);
    }
}

这里有一个比较关键的点就是:把 binder 的 id 设置成 AMS 的,这样做是为了权限验证;Binder.clearCallingIdentity() 最终调用到 IPCThreadState.cpp 中的同名方法,我们进入这个 cpp 文件的同名方法看下:


int64_t IPCThreadState::clearCallingIdentity() { 
    int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid; 
    clearCaller(); 
    return token; 
}

这里调用了 clearCaller 函数,我们进入这个函数看下:

// 清空远程调用端的uid和pid,用当前本地进程的uid和pid替代
void IPCThreadState::clearCaller() { 
    mCallingPid = getpid(); 
    mCallingUid = getuid(); 
}

restoreCallingIdentity 也是调用的同名方法;

// 从token中解析出pid和uid,并赋值给相应变量,该方法正好是clearCallingIdentity的相反过程
void IPCThreadState::restoreCallingIdentity(int64_t token) { 
    mCallingUid = (int)(token>>32); 
    mCallingPid = (int)token; 
}

image.png

AndroidManifest.xml 中的 Activity 是在哪里注册的?


我们在启动一个 Activity 的时候,如果没有在 AndroidManifest 中进行注册的话,就会抛出一段异常,那么 AndroidManifest.xml 中的 Activity 是在哪里注册的呢?

我们直接进入启动 Activity 的代码中看下:

public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, String target,
    Intent intent, int requestCode, Bundle options) {
    // 省略部分代码
    
    // 调用 AMS 的 startActivity 方法并获取一个放回结果,然后检测这个结果
    int result = ActivityTaskManager.getService().startActivity(whoThread,
            who.getOpPackageName(), who.getAttributionTag(), intent,
            intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
            requestCode, 0, null, options);
    checkStartActivityResult(result, intent);
}

这里调用 AMS 的 startActivity 方法并获取一个返回结果,然后检测这个结果;

public static void checkStartActivityResult(int res, Object intent) {
    if (!ActivityManager.isStartResultFatalError(res)) {
        return;
    }

    switch (res) {
        case ActivityManager.START_INTENT_NOT_RESOLVED:
        case ActivityManager.START_CLASS_NOT_FOUND:
            if (intent instanceof Intent &&a
好的,以下是代码形式的电话线路图状态: ``` @startuml title Telephone State Diagram [*] --> Idle : Initial State Idle --> Dialing : Off Hook Event Dialing --> Connecting : Valid Number Event Dialing --> Disconnected : Invalid/Wrong Number Event Connecting --> TimeOut : Timeout Event Connecting --> Connected : Called Phone Answers Event Ringing --> Connected : Called Phone Answers Event Connected --> Idle : On Hook Event Connected --> Busy Tone : Line Busy Event Connected --> TimeOut : Timeout Event Connected --> Disconnected : Timeout Event Connected --> Ringing : Play Message Event @enduml ``` 解释一下: - 初始状态为空闲状态(`[*] --> Idle : Initial State`)。 - 当电话机摘机时,电话状态从空闲状态转入拨号状态(`Idle --> Dialing : Off Hook Event`)。 - 当拨号有效号码时,电话状态从拨号状态转入连接状态(`Dialing --> Connecting : Valid Number Event`)。 - 当拨号号码无效或错误时,电话状态从拨号状态转入未连接状态(`Dialing --> Disconnected : Invalid/Wrong Number Event`)。 - 当连接超时时,电话连接状态从连接状态转入超时状态(`Connecting --> TimeOut : Timeout Event`)。 - 当被拨打的电话接听时,电话连接状态从连接状态或响铃状态转入已连接状态(`Connecting --> Connected : Called Phone Answers Event` 或 `Ringing --> Connected : Called Phone Answers Event`)。 - 当已连接状态的电话机挂机时,电话状态从已连接状态转入空闲状态(`Connected --> Idle : On Hook Event`)。 - 当已连接状态的电话线路忙碌时,电话状态从已连接状态转入忙音状态(`Connected --> Busy Tone : Line Busy Event`)。 - 当已连接状态的电话连接超时时,电话状态从已连接状态转入未连接状态(`Connected --> TimeOut : Timeout Event`)。 - 当已连接状态的电话播放信息时,电话状态从已连接状态转入响铃状态(`Connected --> Ringing : Play Message Event`)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值