androidam机制,从amstart的--ur参数说到Android多用户

更新时间:2023-07-11 20:57:37 阅读: 评论:0

androidam机制,从amstart的--ur参数说到Android多⽤户本⽂的讨论围绕⼀个 java.lang.SecurityException 展开,异常的关键词是权限
android.permission.INTERACT_ACROSS_USERS_FULL。
java.lang.SecurityException: Permission Denial: startActivity asks to run as ur -2 but is calling from ur 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
福布斯外贸论坛at android.adException(Parcel.java:1425)
at android.adException(Parcel.java:1379)
at android.app.ActivityManagerProxy.startActivityAsUr(ActivityManagerNative.java:1921)
at ands.am.Am.runStart(Am.java:494)
at ands.am.Am.run(Am.java:109)
at ands.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)processing
先就我所了解的知识说⼀下此异常发⽣的背景。
背景
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 myUrHandle() in that a uid identifies a specific app sandbox in a specific ur.
所以注定 Android 如果要实现多⽤户不能直接使⽤ Linux 的 uid 机制了,需要另做⼀套机制。
在 Android API level 17 的 Features 列表⾥有⼀项是
Multiple ur accounts (tablets only)
所以在 API level 17 以上的 Android 系统⾥其实已经内置了多⽤户的⽀持,只不过暂时只对平板启⽤(据说是因为多⽤户⼿机专利早已被Symbian 雇员注册,不知真假。)。在实现上是新引⼊了 UrHandle 的概念,封装了 ur id,在 android.os.Process 类的myUrHandle() ⽅法 的描述⾥的原话是:
Returns this process’s ur handle. This is the ur the process is running under. It is distinct from myUid() in that a particular ur will have multiple distinct apps running under it each with their own uid.
ur id 与 uid
结论
ur id = uid / 100000
⽬前 Android ⼿机上所有 APP 的 ur id 都为 0
root 权限与 uid 是否为 0 有关,与 ur id ⽆关
分析
/**
* Reprentation of a ur on the device.
*/
public final class UrHandle implements Parcelable {
/**
* @hide Range of uids allocated for a ur.
*/
public static final int PER_USER_RANGE = 100000;
......
/**
* @hide Enable multi-ur related side effects. Set this to fal if
* there are problems with single ur u-cas.
*/
public static final boolean MU_ENABLED = true;
......
/**爱探险的多拉
* Returns the ur id for a given uid.
* @hide
*/
public static final int getUrId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
} el {
return 0;
}
}
......
}
这个类定义在 frameworks/ba/core/java/android/os/UrHandle.java ⾥。上⾯这段代码能得出结论 1 ⾥的公式。
/**
笔友的英文* Tools for managing OS process.
*/
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 rerved 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/ba/core/java/android/os/Process.java ⾥。
从 FIRST_APPLICATION_UID 与 LAST_APPLICATION_UID 的值,结合结论 1 ⾥的公式来看,所有
APP 运⾏时获取⾃⾝的 ur id 都为 0;⽽运⾏时 uid 为 ROOT_UID (即 0)的 APP 获取⾃⾝的 ur id 也为 0,所以 ur id 是否为 0 与是否获取 root 权限并⽆关联。
异常发⽣的场景
该异常发⽣在 API level 17 以上的机型⾥,在 APP 或者 APP 调⽤的 Native 进程⾥使⽤ am start 来启动 Activity 时。
在 Java 代码中直接 startActivity 并不会触发此异常。
好了,背景交待完毕,下⾯按惯例先上结论及解决⽅案,以便急于解决⽂章开始提到的异常⽽不想探究原理的同学可以省时地带着结论⼼满意⾜地离去。
结论及解决⽅案
在 API level 17 以上的 Android 设备⾥,通过 am start 命令来启动 Activity 时会校验调⽤ am 命令的进程的 ur id 与 am 进程从 –ur 参数获取到的 ur id(默认值为 UrHandle.USER_CURRENT,即 -2)是否相等, 如果想在 APP 或者 APP 调⽤的 Native 进程⾥使⽤ am start 来启动 Activity,那么需要给其传递能通过校验的 –ur 参数,参数值可以直接硬编码为 0,也可以使⽤
android.UrHandle().hashCode() 的值。湖北省英语三级成绩查询
如果不给 am start 传递正确的 –ur 参数,那调⽤进程对应 uid 需要拥有 INTERACT_ACROSS_USERS_FULL 权限,但是该权限的protectionLevel 为 signature|installer,⼀般场景下是⽆法获取到的。
我做了⼀个 Demo APP,通过 Runtime().exec("am start xxxxxxx"); 来启动拔号程序界⾯,有两个按钮分别模拟了传递与不传递 –ur 参数的情况,有兴趣的同学可以看看现象,完整源码在 AuthorityDemo。
运⾏截图如下:
分析
接下来我们将借助于源码对 am start 的执⾏过程进⾏分析,⼀点⼀点吹散迷雾。
am start 的执⾏过程
am 命令的源码在 frameworks/ba/cmds/am ⾥,⾥⾯的 am ⽂件即为 am 命令主体:
#!/system/bin/sh
#
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
荆楚理工学院地址ba=/system
exportCLASSPATH=$ba/framework/am.jar
bbmexecapp_process $ba/bin ands.am.Am "$@"
这段代码在 framworks/ba/cmds/am/am ⾥。
am 命令是通过 app_process 最终调⽤到 ands.am.Am 类的 main ⽅法,并将所有参数传递给 main 来执⾏后续流程的。app_process 相关知识与 am start 执⾏逻辑⽆关,此处略去不表,放在本⽂最后⼀节附录中讲解。
am start 的关键⽅法调⽤如下:
⽂章开始处的异常就是在 handleIncomingUr ⽅法⾥校验 ur id 和权限失败之后抛出的。下⾯按⽅法调⽤层级详细分析⼀下,如下源码所在源⽂件可以在上图中找到:
Am.main
学费英文
public static void main(String[] args) {
(new Am()).run(args);
}
就是⼀个简单的 new 和 run ⽅法调⽤,⽽ Am 类中并⽆ run(String[]) 原型的⽅法,所以其实调⽤的是 Am 类的基类 BaCommand 的 run ⽅法。
BaCommand.run
public void run(String[] args) {
......
mArgs = args;
......
try {
onRun();
......
}
......
}
BaCommand 类的 onRun ⽅法是⼀个抽象⽅法,所以其实 run ⽅法只是保存了参数,然后调⽤了 Am 的 onRun ⽅法。
@Override
public void onRun() throws Exception {
mAm = Default();
......
String op = nextArgRequired();
if (op.equals("start")) {
runStart();
}
......
}
onRun ⽅法主要是对 am 命令后第⼀个参数进⾏判断并进⾏相应的⽅法调⽤,我们可以看到 am start 是调⽤了 runStart ⽅法。
这⾥可以顺便留意到的是 mAm 对象,追踪 Default() 可以知道它最终通过 binder 机制对应ActivityManagerService 对象。
Am.runStart
public class Am extends BaCommand {
......
private boolean mWaitOption = fal;
......
private int mUrId;
......

本文发布于:2023-07-11 20:57:37,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/174457.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:权限   参数   结论
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图