Android之UID and PID

本文详细探讨了在Android中从一个Activity启动另一个Activity时可能遇到的权限问题,包括权限拒绝异常的原因及其解决方法,并介绍了如何确保跨应用Activity启动的安全性和正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们经常在一个activity中去start另一个activity,或者与另一个acitivity的结果进行交互(startActivityForResult)。但有没有想过可能会出现的permission问题呢?如果你遇到了permission denial的Exception,那么你需要读读这篇文章啦。 

我们在同一个application内部,可以随意的startActivity from Activity A to Activity B,而官方的文档中说startActivity可能会报NotFoundException,表示被start的Activity不存在。因此,我们很容易忽略另一个可能的Exception,Permission Denial。 

当我们在不同的application中,如application A中的Activity去start一个application B中的Activity,也许你什么Exception都不会得到,也可能会直接Force Close掉。因为再Start Activity时,代码是有去检验permission的。 

如下情况,可以成功startActivity而不会得到permission denial 

1、同一个application下 

2、Uid相同 

3、permission匹配 

4、目标Activity的属性Android:exported=”true” 

5、目标Activity具有相应的IntentFilter,存在Action动作或其他过滤器并且没有设置exported=false 

6、启动者的Pid是一个System Server的Pid 

7、启动者的Uid是一个System Uid(Android规定android.system.uid=1000,具有该Uid的application,我们称之为获得Root权限) 

如果上述调节,满足一条,一般即可(与其他几条不发生强制设置冲突),否则,将会得到Permission Denial的Exception而导致Force Close。 

现在,我来解释一下Uid机制 

众所周知,Pid是进程ID,Uid是用户ID,只是Android和计算机不一样,计算机每个用户都具有一个Uid,哪个用户start的程序,这个程序的Uid就是那个那个用户,而Android中每个程序都有一个Uid,默认情况下,Android会给每个程序分配一个普通级别互不相同的 Uid,如果用互相调用,只能是Uid相同才行,这就使得共享数据具有了一定安全性,每个软件之间是不能随意获得数据的。而同一个application 只有一个Uid,所以application下的Activity之间不存在访问权限的问题。 

如果你需要做一个application,将某些服务service,provider或者activity等的数据,共享出来怎么办,三个办法。

1、完全暴露,这就是android:exported=”true”的作用,而一旦设置了intentFilter之后,exported就默认被设置为true了,除非再强制设为false。当然,对那些没有intentFilter的程序体,它的exported属性默认仍然是false,也就不能共享出去。 

2、权限提示暴露,这就是为什么经常要设置usePermission的原因,如果人家设置了 android:permission=”xxx.xxx.xx”那么,你就必须在你的application的Manufest中 usepermission xxx.xxx.xx才能访问人家的东西。 

3、私有暴露,假如说一个公司做了两个产品,只想这两个产品之间可互相调用,那么这个时候就必须使用shareUserID将两个软件的Uid强制设置为一样的。这种情况下必须使用具有该公司签名的签名文档才能,如果使用一个系统自带软件的ShareUID,例如Contact,那么无须第三方签名。 

这种方式保护了第三方软件公司的利益于数据安全。 

当然如果一个activity是又system process跑出来的,那么它就可以横行霸道,任意权限,只是你无法开发一个第三方application具有系统的Pid(系统Pid不固定),但是你完全可以开发一个具有系统Uid的程序,对系统中的所有程序任意访问,只需再Manufest中声明shareUserId为 android.system.uid即可,生成的文件也必须经过高权限签名才行,一般不具备这种审核条件的application,google不会提供给你这样的签名文件。当然你是在编译自己的系统的话,想把它作成系统软件程序,只需在Android.mk中声明 Certificate:platform则可以了,既采用系统签名。这个系统Uid的获得过程,我们把它叫做获得Root权限的过程。所以很多第三方系统管理软件就是有Root权限的软件,因为他需要对系统有任意访问的权限。那么它的Root签名则需要和编译的系统一致,例如官方的系统得用官方的签名文件,CM的系统就得用CM的签名文件。


来源:http://yelinsen.iteye.com/blog/992345

Line 17196: [ 124.790242] init: init: Control message: Could not ctl.interface_start for 'aidl/android.hardware.nfc.INfc/default' from pid: 417 (/system/bin/servicemanager): File /vendor/bin/hw/android.hardware.nfc2-service.nxp(labeled "u:object_r:vendor_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials. Note: this error shows up even in permissive mode in order to make auditing denials possible. Line 17196: [ 124.790242] init: init: Control message: Could not ctl.interface_start for 'aidl/android.hardware.nfc.INfc/default' from pid: 417 (/system/bin/servicemanager): File /vendor/bin/hw/android.hardware.nfc2-service.nxp(labeled "u:object_r:vendor_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials. Note: this error shows up even in permissive mode in order to make auditing denials possible. Line 17196: [ 124.790242] init: init: Control message: Could not ctl.interface_start for 'aidl/android.hardware.nfc.INfc/default' from pid: 417 (/system/bin/servicemanager): File /vendor/bin/hw/android.hardware.nfc2-service.nxp(labeled "u:object_r:vendor_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials. Note: this error shows up even in permissive mode in order to make auditing denials possible. Line 18001: [ 148.994352] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18001: [ 148.994352] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18001: [ 148.994352] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18081: [ 154.022668] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18081: [ 154.022668] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18081: [ 154.022668] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18196: [ 159.036990] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18196: [ 159.036990] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting). Line 18196: [ 159.036990] servicemanager: servicemanager: Caller(pid=4330,uid=1027,sid=u:r:nfc:s0) Since 'android.hardware.nfc.INfc/default' could not be found trying to start it as a lazy AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or still starting).
最新发布
07-14
<think>我们正在处理一个Android SELinux权限问题,具体是关于NFC服务启动失败,错误信息显示无法从init上下文切换到android.hardware.nfc2-service.nxp的域。 根据SELinux规则,当init进程(u:r:init:s0)尝试启动一个服务时,需要允许域转换到该服务的域。 解决方案通常涉及修改SELinux策略文件(.te文件),添加允许规则。 步骤: 1. 确定目标服务的域(domain)类型。根据错误信息,目标域是`android.hardware.nfc2-service.nxp`(但通常我们使用类型名,如`nfc_nxp_domain`等,需要查看服务定义和.te文件确认)。 2. 在服务对应的.te文件中,添加允许init进程切换到该域的规则。 规则语法可能如下: ``` # 允许init进程执行该域的可执行文件 allow init nfc_nxp_exec:file { execute }; # 允许从init域切换到nfc_nxp域 domain_auto_trans(init, nfc_nxp_exec, nfc_nxp_domain) ``` 或者直接使用: ``` type_transition init nfc_nxp_exec:process nfc_nxp_domain; ``` 但更推荐使用宏`domain_auto_trans`(如果系统支持)因为它同时包含多个必需的规则。 注意:实际类型名需要根据设备的具体实现确定。通常,服务在init.rc中定义,其可执行文件被赋予一个类型(通过`seclabel`或根据文件路径的规则),然后进程域转换的目标类型就是该服务的域。 3. 如果服务已经定义了域(假设为`nfc_nxp_domain`),那么我们需要在`nfc_nxp.te`文件中添加上述规则。 4. 另外,检查服务可执行文件的上下文是否正确。可以使用`ls -Z`查看,确保其文件上下文与策略中定义的`nfc_nxp_exec`一致。 5. 编译策略并重新启动服务以测试。 由于具体类型名可能因设备而异,这里假设为`nfc_nxp_domain`和`nfc_nxp_exec`。 因此,在`nfc_nxp.te`文件中添加: ``` allow init nfc_nxp_exec:file { execute getattr open read }; domain_auto_trans(init, nfc_nxp_exec, nfc_nxp_domain) ``` 注意:如果系统不支持`domain_auto_trans`宏(在Android中通常使用),我们可以显式地写: ``` # 允许init执行该可执行文件 allow init nfc_nxp_exec:file { execute }; # 类型转换 type_transition init nfc_nxp_exec:process nfc_nxp_domain; ``` 但是,仅此还不够,还需要允许init进程在切换域时具有权限,通常需要: ``` allow init nfc_nxp_domain:process transition; allow nfc_nxp_domain init:process sigchld; # 以及可能需要的其他权限,如dyntransition等 ``` 所以使用宏可以简化。 在Android SELinux策略中,通常使用`domain_auto_trans`宏(在`te_macros`文件中定义)。在Android O之后,也可能使用`binder_use`等,但这里我们关注域转换。 如果问题仍然存在,可能需要查看avc denied日志,使用`audit2allow`生成规则。 但是根据错误信息,我们已知是域转换被拒绝,因此添加域转换规则。 另外,确保服务在init.rc中的定义正确,例如: ``` service nfc_nxp /vendor/bin/hw/android.hardware.nfc@2.0-service.nxp class hal user nfc group nfc seclabel u:r:nfc_nxp_domain:s0 # 这里指定了域,但实际转换需要策略允许 ``` 如果没有指定seclabel,则默认使用可执行文件的安全上下文。 因此,确保可执行文件的安全上下文是`nfc_nxp_exec`类型,例如: ``` /vendor/bin/hw/android.hardware.nfc@2.0-service.nxp u:object_r:nfc_nxp_exec:s0 ``` 总结步骤: 1. 在`nfc_nxp.te`文件中添加允许init域转换到nfc_nxp_domain的规则。 2. 确保可执行文件有正确的文件上下文。 3. 重新编译策略,并重新启动。 如果问题仍未解决,请检查avc日志,确认是否有其他权限问题。 相关问题: 1. 如何查看Android设备的avc拒绝日志? 2. 如何编译和推送SELinux策略到Android设备? 3. 如何为Android服务定义SELinux域?</think>### Android NFC服务SELinux权限问题解决方案 针对`android.hardware.nfc2-service.nxp`服务启动失败的错误信息: ``` Could not ctl.interface_start domain transition from u:r:init:s0 to another domain ``` 这表明SELinux策略阻止了从`init`进程到NFC服务域的域转换。以下是系统级的解决方案: #### 1. **添加域转换规则** 在`nfc_nxp.te`策略文件中添加: ```te # 允许init执行nfc_nxp的可执行文件 allow init nfc_nxp_exec:file { execute getattr open read }; # 允许域转换 domain_auto_trans(init, nfc_nxp_exec, nfc_nxp_domain) # 允许接收信号 allow nfc_nxp_domain init:process sigchld; ``` `domain_auto_trans`宏会自动处理域转换所需的三个核心权限:`transition`、`noatsecure`和`rlimitinh`[^1]。 #### 2. **验证可执行文件标签** 确保NFC服务二进制文件有正确的标签: ```sh adb shell ls -Z /vendor/bin/hw/android.hardware.nfc@2.0-service.nxp # 应显示:u:object_r:nfc_nxp_exec:s0 ``` 若标签错误,在`file_contexts`中添加: ```txt /vendor/bin/hw/android\.hardware\.nfc@2\.0-service\.nxp u:object_r:nfc_nxp_exec:s0 ``` #### 3. **检查服务定义** 确认`init.rc`中的服务定义: ```rc service nfc_nxp /vendor/bin/hw/android.hardware.nfc@2.0-service.nxp class hal user nfc group nfc seclabel u:r:nfc_nxp_domain:s0 # 关键声明 ``` #### 4. **编译与测试** ```sh # 编译策略 make -j8 selinux_policy # 推送新策略 adb push out/target/product/<device>/vendor/etc/selinux /vendor/etc/selinux adb reboot ``` 重启后检查日志: ```sh adb logcat | grep 'avc:.*nfc_nxp' ``` ### 常见问题排查 1. **若仍有权限拒绝** 检查完整avc日志,常见缺失权限: ```te # 示例补充规则 allow nfc_nxp_domain device:chr_file { open read write }; allow nfc_nxp_domain kernel:system syslog_read; ``` 2. **Binder调用权限** 若涉及HIDL调用需添加: ```te allow nfc_nxp_domain hal_nfc_default:service_manager find; binder_use(nfc_nxp_domain) ``` ### 根本原因 当`init`进程尝试启动NFC服务时,SELinux策略需明确允许: 1. `init`域执行服务二进制文件(`execute`权限) 2. 从`init`域转换到`nfc_nxp_domain`域(`transition`权限) 3. 目标域对源域的进程信号处理权限(`sigchld`)[^2] [^1]: SELinux策略中`domain_auto_trans`宏自动处理域转换的三种基本权限 [^2]: Android要求目标域必须拥有`sigchld`权限来接收源进程信号
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值