首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >从 am start 的 --user 参数说到 Android 多用户

从 am start 的 --user 参数说到 Android 多用户

作者头像
mzlogin
发布于 2020-04-16 10:12:49
发布于 2020-04-16 10:12:49
2.9K10
代码可运行
举报
文章被收录于专栏:闷骚的程序员闷骚的程序员
运行总次数:0
代码可运行

本文的讨论围绕一个 java.lang.SecurityException 展开,异常的关键词是权限 android.permission.INTERACT_ACROSS_USERS_FULL

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java.lang.SecurityException: Permission Denial: startActivity asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
    at android.os.Parcel.readException(Parcel.java:1425)
    at android.os.Parcel.readException(Parcel.java:1379)
    at android.app.ActivityManagerProxy.startActivityAsUser(ActivityManagerNative.java:1921)
    at com.android.commands.am.Am.runStart(Am.java:494)
    at com.android.commands.am.Am.run(Am.java:109)
    at com.android.commands.am.Am.main(Am.java:82)
    at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
    at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235)

先就我所了解的知识说一下此异常发生的背景。

背景

Android 系统里的多用户

Android 系统是基于 Linux 内核,而 Linux 内核中用于支持多用户机制的 uid 在 Android 中被用于标识 app-specific sandbox。android.os.Process 类的 myUid() 方法 的描述里的原话是:

Returns the identifier of this process’s uid. This is the kernel uid that the process is running under, which is the identity of its app-specific sandbox. It is different from myUserHandle() in that a uid identifies a specific app sandbox in a specific user.

所以注定 Android 如果要实现多用户不能直接使用 Linux 的 uid 机制了,需要另做一套机制。

在 Android API level 17 的 Features 列表里有一项是

Multiple user accounts (tablets only)

所以在 API level 17 以上的 Android 系统里其实已经内置了多用户的支持,只不过暂时只对平板启用(据说是因为多用户手机专利早已被 Symbian 雇员注册,不知真假。)。在实现上是新引入了 UserHandle 的概念,封装了 user id,在 android.os.Process 类的 myUserHandle() 方法 的描述里的原话是:

Returns this process’s user handle. This is the user the process is running under. It is distinct from myUid() in that a particular user will have multiple distinct apps running under it each with their own uid.

user id 与 uid

结论

  1. user id = uid / 100000
  2. 目前 Android 手机上所有 APP 的 user id 都为 0
  3. root 权限与 uid 是否为 0 有关,与 user id 无关

分析

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Representation of a user on the device.
 */
public final class UserHandle implements Parcelable {
    /**
     * @hide Range of uids allocated for a user.
     */
    public static final int PER_USER_RANGE = 100000;
    ......
    /**
     * @hide Enable multi-user related side effects. Set this to false if
     * there are problems with single user use-cases.
     */
    public static final boolean MU_ENABLED = true;
    ......
    /**
     * Returns the user id for a given uid.
     * @hide
     */
    public static final int getUserId(int uid) {
        if (MU_ENABLED) {
            return uid / PER_USER_RANGE;
        } else {
            return 0;
        }
    }
    ......
}

这个类定义在 frameworks/base/core/java/android/os/UserHandle.java 里。

上面这段代码能得出结论 1 里的公式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Tools for managing OS processes.
 */
public class Process {
    ......
    /**
     * Defines the root UID.
     * @hide
     */
    public static final int ROOT_UID = 0;
    ......
    /**
     * Defines the start of a range of UIDs (and GIDs), going from this
     * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
     * to applications.
     */
    public static final int FIRST_APPLICATION_UID = 10000;

    /**
     * Last of application-specific UIDs starting at
     * {@link #FIRST_APPLICATION_UID}.
     */
    public static final int LAST_APPLICATION_UID = 19999;
    ......        
}

这个类定义在 frameworks/base/core/java/android/os/Process.java 里。

FIRST_APPLICATION_UIDLAST_APPLICATION_UID 的值,结合结论 1 里的公式来看,所有 APP 运行时获取自身的 user id 都为 0;而运行时 uid 为 ROOT_UID (即 0)的 APP 获取自身的 user id 也为 0,所以 user id 是否为 0 与是否获取 root 权限并无关联。

异常发生的场景

该异常发生在 API level 17 以上的机型里,在 APP 或者 APP 调用的 Native 进程里使用 am start 来启动 Activity 时。

在 Java 代码中直接 startActivity 并不会触发此异常。

好了,背景交待完毕,下面按惯例先上结论及解决方案,以便急于解决文章开始提到的异常而不想探究原理的同学可以省时地带着结论心满意足地离去。

结论及解决方案

在 API level 17 以上的 Android 设备里,通过 am start 命令来启动 Activity 时会校验调用 am 命令的进程的 user id 与 am 进程从 –user 参数获取到的 user id(默认值为 UserHandle.USER_CURRENT,即 -2)是否相等, 如果想在 APP 或者 APP 调用的 Native 进程里使用 am start 来启动 Activity,那么需要给其传递能通过校验的 –user 参数,参数值可以直接硬编码为 0,也可以使用 android.os.Process.myUserHandle().hashCode() 的值。

如果不给 am start 传递正确的 –user 参数,那调用进程对应 uid 需要拥有 INTERACT_ACROSS_USERS_FULL 权限,但是该权限的 protectionLevel 为 signature|installer,一般场景下是无法获取到的。

我做了一个 Demo APP,通过 Runtime.getRuntime().exec("am start xxxxxxx"); 来启动拔号程序界面,有两个按钮分别模拟了传递与不传递 –user 参数的情况,有兴趣的同学可以看看现象,完整源码在 AuthorityDemo

运行截图如下:

分析

接下来我们将借助于源码对 am start 的执行过程进行分析,一点一点吹散迷雾。

am start 的执行过程

am 命令的源码在 frameworks/base/cmds/am 里,里面的 am 文件即为 am 命令主体:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/system/bin/sh
#
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"

这段代码在 framworks/base/cmds/am/am 里。

am 命令是通过 app_process 最终调用到 com.android.commands.am.Am 类的 main 方法,并将所有参数传递给 main 来执行后续流程的。app_process 相关知识与 am start 执行逻辑无关,此处略去不表,放在本文最后一节附录中讲解。

am start 的关键方法调用如下:

文章开始处的异常就是在 handleIncomingUser 方法里校验 user id 和权限失败之后抛出的。下面按方法调用层级详细分析一下,如下源码所在源文件可以在上图中找到:

Am.main
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
    (new Am()).run(args);
}

就是一个简单的 new 和 run 方法调用,而 Am 类中并无 run(String[]) 原型的方法,所以其实调用的是 Am 类的基类 BaseCommand 的 run 方法。

BaseCommand.run
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void run(String[] args) {
    ......
    mArgs = args;
    ......

    try {
        onRun();
        ......
    }
    ......
}

BaseCommand 类的 onRun 方法是一个抽象方法,所以其实 run 方法只是保存了参数,然后调用了 Am 的 onRun 方法。

Am.onRun
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void onRun() throws Exception {

    mAm = ActivityManagerNative.getDefault();
    ......

    String op = nextArgRequired();

    if (op.equals("start")) {
        runStart();
    }
    ......
}

onRun 方法主要是对 am 命令后第一个参数进行判断并进行相应的方法调用,我们可以看到 am start 是调用了 runStart 方法。

这里可以顺便留意到的是 mAm 对象,追踪 ActivityManagerNative.getDefault() 可以知道它最终通过 binder 机制对应 ActivityManagerService 对象。

Am.runStart
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Am extends BaseCommand {
    ......
    private boolean mWaitOption = false;
    ......
    private int mUserId;
    ......
    private Intent makeIntent(int defUser) throws URISyntaxException {
        ......
        mWaitOption = false;
        ......
        mUserId = defUser;
        ......
        while ((opt=nextOption()) != null) {
            if (opt.equals("-a")) {
                ......
            } else if (opt.equals("-W")) {
                mWaitOption = true;
                ......
            } else if (opt.equals("--user")) {
                mUserId = parseUserArg(nextArgRequired());
            }
            ......
    }

    private void runStart() throws Exception {
        Intent intent = makeIntent(UserHandle.USER_CURRENT);
        ......
        if (mWaitOption) {
            result = mAm.startActivityAndWait(null, null, intent, mimeType,
                        null, null, 0, mStartFlags, profilerInfo, null, mUserId);
            res = result.result;
        } else {
            res = mAm.startActivityAsUser(null, null, intent, mimeType,
                    null, null, 0, mStartFlags, profilerInfo, null, mUserId);
        }
        ......
        switch (res) {
            // 启动 Activity 的结果提示
        }
        if (mWaitOption && launched) {
            // 输出启动 Activity 的结果状态,起止时间等
        }
        ......
    }
    ......
}

由如上代码可知,一般通过 am start 启动 Activity 时若未传 -W 参数(我一般的做法),会调用 ActivityManagerService.startActivityAsUser 来启动 Activity。(ActivityManagerService.startActivityAndWait 其实与 ActivityManagerService.startActivityAsUser 类似,只是在启动 Activity 后多了一个等待过程,下面不再重复分析。)

而 mUserId 的值,若命令行中有 –user 参数,则被赋为该参数的值;若命令行中无 –user 参数,则默认为 UserHandle.USER_CURRENT 的值,在 frameworks/base/core/java/android/os/UserHandle.java 中可知此默认值为 -2。

-2 这个数字是不是有点似曾相似?没错,文首的异常信息里就有这个值。

ActivityManagerService.startActivityAsUser
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, false, userId, null, null);
}

Binder.getCallingUid() 是一个 native 方法,在 frameworks/base/core/java/android/os/Binder.java 中能找到,它其实就是返回了当前进程的 uid,而该 uid 是从父进程继承的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Return the Linux uid assigned to the process that sent you the
 * current transaction that is being processed.  This uid can be used with
 * higher-level system services to determine its identity and check
 * permissions.  If the current thread is not currently executing an
 * incoming transaction, then its own uid is returned.
 */
public static final native int getCallingUid();
ActivityManagerService.handleIncomingUser
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
        int allowMode, String name, String callerPackage) {
    final int callingUserId = UserHandle.getUserId(callingUid);
    if (callingUserId == userId) {
        return userId;
    }
    ......
    if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
        final boolean allow;
        if (checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
                callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
            // If the caller has this permission, they always pass go.  And collect $200.
            allow = true;
        } else if (allowMode == ALLOW_FULL_ONLY) {
            // We require full access, sucks to be you.
            allow = false;
        } else if (......) {
            ......
        }
        if (!allow) {
            if (userId == UserHandle.USER_CURRENT_OR_SELF) {
                // In this case, they would like to just execute as their
                // owner user instead of failing.
                targetUserId = callingUserId;
            } else {
                StringBuilder builder = new StringBuilder(128);
                builder.append("Permission Denial: ");
                builder.append(name);
                if (callerPackage != null) {
                    builder.append(" from ");
                    builder.append(callerPackage);
                }
                builder.append(" asks to run as user ");
                builder.append(userId);
                builder.append(" but is calling from user ");
                builder.append(UserHandle.getUserId(callingUid));
                builder.append("; this requires ");
                builder.append(INTERACT_ACROSS_USERS_FULL);
                if (allowMode != ALLOW_FULL_ONLY) {
                    builder.append(" or ");
                    builder.append(INTERACT_ACROSS_USERS);
                }
                String msg = builder.toString();
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }
        }
    }
    ......
}

它先校验了当前进程的 user id 与参数里的 userId(即 –user 的值或默认的 -2)是否相等,如果相等则正常返回,执行后续的启动 Activity 动作;

如果不相等,普通应用程序的 callingUid 必为 0,则先进行权限校验,看当前 pid 和 uid 是否被赋予了 INTERACT_ACROSS_USERS_FULL 权限,我们在前面的「结论及解决方案」一节中已经交待过,该权限的 protectionLevel 为 signature|installer,一般场景下是无法获取到的;

如果没有 INTERACT_ACROSS_USERS_FULL 权限,allowMode 参数值又为 ALLOW_FULL_ONLY 则将抛出 SecurityException,从上一小节「ActivityManagerService.startActivityAsUser」中调用 handleIncomingUser 的参数可知 allowMode 参数就是 ALLOW_FULL_ONLY。

上方代码段里的 Permission Denial:asks to run as userbut is calling from user 等字符串是不是很熟悉?这就是从文首开始困惑我们的异常抛出的地方。

至此,am start 的大概执行过程和异常发生的情景分析完成。

实现功能,避免异常

从上方的分析可知,要避免异常最直接有效的方法就是让 handleIncomingUser 方法正常返回,既然声明 INTERACT_ACROSS_USERS_FULL 权限的路不通,就只有传递 –user 参数了。

那么给这个参数传递什么值呢?

从上文的分析可知,该参数应该与 am 进程的 user id 相等,所以传递父进程的 user id 即可。(user id 由 uid 运算得来,而 uid 与父进程相同。)

由「背景」一节可知,所有 APP 进程的 user id 都为 0,所以该参数直接写 0 是可以的;如果不想硬编码,那么可以先用 Process 类的 myUserHandle() 方法获取进程的 user handle:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Returns this process's user handle.  This is the
 * user the process is running under.  It is distinct from
 * {@link #myUid()} in that a particular user will have multiple
 * distinct apps running under it each with their own uid.
 */
public static final UserHandle myUserHandle() {
    return new UserHandle(UserHandle.getUserId(myUid()));
}

这段代码定义在 frameworks/base/core/java/android/os/Process.java 中。

继续分析 UserHandle 类里的相关方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final class UserHandle implements Parcelable {
    ......
    /** @hide */
    public UserHandle(int h) {
        mHandle = h;
    }

    /**
     * Returns the userId stored in this UserHandle.
     * @hide
     */
    @SystemApi
    public int getIdentifier() {
        return mHandle;
    }
    ......
    @Override
    public int hashCode() {
        return mHandle;
    }
    ......

这段代码定义在 frameworks/base/core/java/android/os/UserHandle.java 中。

构造方法 UserHandle(int h) 里将 user id 保存在 mHandle 成员里,本来 UserHandle 类有一个 getIdentifier 方法可以返回 mHandle 的,但该方法被标为了 SystemApi 和 hide,无法正常调用,所以找了一个取巧的办法,使用也返回 mHandle 值的 hashCode 方法来达成目标。

所以 am start 的 –user 的参数可以直接写为 0,也可以使用 android.os.Process.myUserHandle().hashCode() 的值。

引申思考

启动 Activity 的方法并非只有在 APP 进程里使用 am start 一种,还有通过 adb 命令 adb shell am start 或在 APP 进程里使用 startActivity 等,它们为什么没有抛出此异常呢?继续探索。

为何 adb shell am start 不抛此异常

原因: shell 是拥有 INTERACT_ACROSS_USERS_FULL 权限的,所以 am start 作为其子进程继承了 shell 的 uid 和对应权限,在如上流程中 ActivityManagerService.handleIncomingUser 里通过了权限检查,不会抛出文首的异常。

在 frameworks/base/packages/Shell/AndroidManifest.xml 里有如下声明:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.shell"
        coreApp="true"
        android:sharedUserId="android.uid.shell"
        >
    ......
    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
    ......
</manifest>    

Java 代码里 startActivity 的执行过程

其实与 am start 一样,都是执行到了 ActivityManagerService.startActivityAsUser,区别在于参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        resultWho, requestCode, startFlags, profilerInfo, options,
        UserHandle.getCallingUserId());
}

在 am start 流程中的,传给 startActivityAsUser 的最后一个参数是 –user 传入的或者默认的 -2,而 Java 代码里的 startActivity 流程中传给 startActivityAsUser 的是 UserHandle.getCallingUserId(),相当于到 handleIncomingUser 中是当前进程的 user id 与当前进程的 user id 比较(必相等),如果相等则通过校验,所以必能通过校验,不会抛出文首说的异常。

附录

app_process 简要执行过程

在第 2 步,AndroidRuntime::start 中调用了 startVm 启动虚拟机,最终在第 5 步 AppRuntime::onStarted 中调用通过参数传进来的类的 main 方法,并将类名后的参数传给它。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016/02/10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
am start --user x 好像无法直接启动指定用户的应用,如果存在分身应用的话会弹出一个选择弹窗,请问有什么方法可以直接打开指定用户下的应用嘛(比如绕开弹窗直接打开分身应用)?
am start --user x 好像无法直接启动指定用户的应用,如果存在分身应用的话会弹出一个选择弹窗,请问有什么方法可以直接打开指定用户下的应用嘛(比如绕开弹窗直接打开分身应用)?
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 )
在 Instrumentation 中 , 通过调用 ActivityManagerService ( AMS ) 的 startActivity 方法 ,
韩曙亮
2023/03/29
1.8K0
【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 )
滴滴插件化框架VirtualAPK原理解析(一)之插件Activity管理
上周末,滴滴与360都开源了各自的插件化框架,VirtualAPK与RePlugin,作为一个插件化方面的狂热研究者,在周末就迫不及待的下载了Virtualapk框架来进行研究,本篇博客带来的是VirtualAPK原理解析的第一篇Activity管理,博客只是自己的理解,小弟才疏学浅,可能有很多理解不对的地方,欢迎各位大神指出。(看博客之前,请大家先下载VirtualVirtualAPKapk的项目,https://github.com/didi/VirtualAPK)
老马的编程之旅
2022/06/23
1.2K0
滴滴插件化框架VirtualAPK原理解析(一)之插件Activity管理
慢~再来梳理一遍Activity的启动流程
activity启动的流程分为两部分:一是在activity中通过startActivity(Intent intent)方法启动一个Activity;二是我们在桌面通过点击应用图标启动一个App然后显示Activity;第二种方式相较于第一种方式更加全面,所以本文会以第二种流程来分析。
没关系再继续努力
2021/12/13
6K0
Android应用启动之从Launcher拉起APP(一)
函数中添加了FLAG_ACTIVITY_NEW_TASK,并且执行了startActivity函数。
李小白是一只喵
2021/03/17
2.7K0
Android | Activity 启动流程分析
前言 Activity 类是 android 应用的关键组件,在日常开发中,绝对少不了组件。既然用了这么久,你知道他的启动流程🐴?作为一个应用层开发者,大多数人可能觉得学习这些对日常开发可能没有太大帮助。但是多了解一下 framework 的代码还是很有必要的,了解系统组件机制,对于一些问题我们也能快速的定位找到问题的所在点,并且在面试的时候也是一个加分项。 本文基于 Android 12 版本源码,从 startActivity 作为切入点,对整个启动流程进行分析。 Activity 启动方式 启动一个
345
2023/01/30
9170
Android 深入研究之 ✨ Activity启动流程+Activity生命周期✨
关于activity的四个状态: running-paused-stopped-killed
呆呆敲代码的小Y
2021/08/12
1.6K0
你说一下 PendingIntent 和 Intent 的区别?
PendingIntent 的应用场景关键在于间接的 Intent 跳转需求, 即先通过一级 Intent 跳转到某个组件,在该组件完成任务后再间接地跳转到二级的 Intent。PendingIntent 中的单词 “pending” 指延迟或挂起,就是指它是延迟的或挂起的。例如,你在以下场景中就可以使用 PendingIntent:
用户9995743
2022/09/26
7750
你说一下 PendingIntent 和 Intent 的区别?
025android初级篇之Android am命令的实现
am命令一个重要的调试工具,主要功能包括如下: 启动停止Activity Service,启动Broadcast, 查看管理这些信息。
上善若水.夏
2018/09/28
1.6K0
Android深入四大组件(六)Android8.0 根Activity启动过程(前篇)
前言 在几个月前我写了Android深入四大组件(一)应用程序启动过程这篇文章,它是基于Android 7.0的,当我开始阅读Android 8.0源码时发现应用程序(根Activity)启动过程照Android 7.0有了一些变化,因此又写下了本篇文章,本篇文章照此前的文章不仅流程发生变化,而且增加了一些分析,算是升级版本。由于篇幅较长,Android8.0 根Activity启动过程仍旧分为前篇和后篇来进行讲解。 1.概述 Activity的启动过程分为两种,一种是根Activity的启动过程,另一种是
用户1269200
2018/02/01
1.2K0
Android深入四大组件(六)Android8.0 根Activity启动过程(前篇)
Android插件化架构 - Activity的启动流程分析
Android插件化架构,目前第三方的框架比较多,早几年自己用的是DL框架,这个框架的源码比较简单主要用的是静态代理。如果我们自己要去写一个插件化架构框架那要解决的问题会分为几个方面,类的加载,资源和布局的加载,广播的管理方式,Activity的加载和生命周期管理,Service的插件化,ContentProvider的插件化等等等等,反正加载一个没有运行的app到主程序,需要解决的问题基本就这么多,如果能够一一解决那么就可以实现插件化了。   内涵段子项目部分我们实现几个,然后介绍一个360开源框架DroidPlugin原理一致,后面我们再一一实现,那么这一期实现什么呢?我们需要启动插件APP那么就需要启动里面的Activity,这些Activity事先是不会在主工程的AndroidManifest.xml中配置,启动一个没有注册的Activity肯定会报错,我们是否可以想个办法去绕过系统的检测,让没有在AndroidManifest.xml中配置的Activity照样可以启动呢?   看源码的时候我们其实时常强调一定要带着思想,要解决这么个问题我们肯定需要清楚的知道系统启动Activity的具体流程,当然可以直接去了解为什么报错,这里我们还是把启动流程全部走一遍,也方便以后开发中再遇到什么问题。
程序员小何SS
2021/12/02
4900
Activity启动过程
Activity的启动通常从startActivity开始。 但是startActivity最终都会调用startActivityForResult
提莫队长
2019/02/21
9390
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )
【Android 插件化】插件化简介 ( 组件化与插件化 ) 【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 ) 【Android 插件化】插件化原理 ( 类加载器 )
韩曙亮
2023/03/29
9700
Activity的启动过程详解(基于10.0源码)
话说Android中有四大组件:Activity、Service、BroadcastReceiver、ContentProvider。我们最常接触也是用户直接感受到的就是Activity了,今天来就说说Android启动的执行过程和工作原理。
胡飞洋
2020/07/22
4.9K1
ActivityManagerService 启动初探
在之前的Android SystemServer启动(二)中,分析到在SystemServer中会启动大量的Service,其中就有一个比较特殊的Service,它就是ActivityManagerService。
Rouse
2021/01/12
9820
Activity启动过程
Activity作为Android四大组件中使用最频繁的组件,也是和用户交互最多的组件,可见它在Android技术体系的核心地位,了解Activity的启动过程可以帮助我们更好的了解Android系统和使用Activity。
八归少年
2024/03/11
4290
Android12 应用启动流程分析
最近因为一些需求,需要梳理 Android 应用的启动链路,从中寻找一些稳定的锚点来实现一些特殊的功能。本文即为对应用端启动全过程的一次代码分析记录。
evilpan
2023/02/12
1.4K0
Android12 应用启动流程分析
Android StartService()源码分析(一)
场景:在 APP M 中启动 APP N 中一个服务,即目标服务和 APP M 不在同一个进程
木子杂志
2020/08/05
9200
Android StartService()源码分析(一)
Activity启动流程源码分析
launcher就是android桌面应用程序。也是操作系统启动有第一个app。同时作为其他app的入口。我们找到其源码 android-6.0.0_r1\packages\apps\Launcher2 我们先看Manifest文件 找到app的入口Activity
用户2929716
2018/08/23
1.6K0
Android O 后台startService限制简析
Android O 推出出了Background Execution Limits,减少后台应用内存使用及耗电,一个很明显的应用就是不准后台应用通过startService启动服务,这里有两个问题需要弄清楚,第一:什么状态下startService的属于后台启动service;第二:如果想要在后台startService,如何兼容,因此分如下几个问题分析下
看书的小蜗牛
2019/06/11
12.9K0
Android O 后台startService限制简析
安卓broadcastreceiver_Android手电筒原理
广播作为四大组件之一,在平时开发过程中会大量使用到,使用方式也是多种多样的,既可以自己在manifest中注册,也可以在java代码中动态注册,既可以接收由系统发出的广播,也可以接受自己定义并发送的广播。广播可以实现进程内以及跨进程之间的通信。从本文开始将分别介绍广播的注册,广播的派发,本地广播(LocalBroadcast)以及Android O上对广播的限制,本文主要介绍广播动态注册。
全栈程序员站长
2022/10/01
4070
安卓broadcastreceiver_Android手电筒原理
推荐阅读
相关推荐
【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 )
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档