一、原因

原因:Android具有system权限为什么不可以访问SDcard
官方文档解释

Processes that continue holding open fds on the sdcard a little after it is
requested to be unmounted will be killed so that it can unmount.
We don’t want the system process to be able to access the sdcard to avoid
these kinds of issues (and just general security cleanliness), so that it
does not have permission to access it.

中文翻译

sdcard属于易插拔的外部设备,如果说我们系统app可以访问sdcard,并且一直持有sdcard中相应文件的fds(文件句柄),如果我们sdcard这时候拔除,
这时系统app就有可能因为fds文件句柄没有被killed,但是系统app一般是不可以被killed,因为你想想如果我们的主页launcher被killed了或者其他重要系统app被killed
就有可能导致一系列安全问题,如主页crash或者手机重启等等,也就是我一拔sdcard结果手机死机了的悲剧结果

简单总结就是以前的sdcard卡是可插拔的,如果系统进程去访问sdcard目录,会持有sdcard文件句柄,如果sdcard被拔除,可能会导致系统崩溃,故官方做了这个限制。但是目前的sdcard一般是内置的,不可插拔,一般不会存在这种情况。

二、解决方法

1、方法一

参考链接:【framework】framework中为systemserver添加权限

问题解决思路:查看system_server是否属于sdcard读写相关用户组**
解决过程
  1. 查看sdcard目录信息

红框标注的地方为所属用户组信息,进程属于这个用户组才能访问sdcard目录

  1. 查看 sdcard_r对应的用户组id

头文件位置:system/core/include/private/android_filesystem_config.h

#define AID_ROOT             0  /* traditional unix root user */#define AID_SYSTEM        1000  /* system server */#define AID_RADIO         1001  /* telephony subsystem, RIL */
#define AID_BLUETOOTH     1002  /* bluetooth subsystem */
#define AID_GRAPHICS      1003  /* graphics devices */
#define AID_INPUT         1004  /* input devices */
#define AID_AUDIO         1005  /* audio devices */
#define AID_CAMERA        1006  /* camera devices */
#define AID_LOG           1007  /* log devices */
#define AID_COMPASS       1008  /* compass device */
#define AID_MOUNT         1009  /* mountd socket */
#define AID_WIFI          1010  /* wifi subsystem */
#define AID_ADB           1011  /* android debug bridge (adbd) */
#define AID_INSTALL       1012  /* group for installing packages */
#define AID_MEDIA         1013  /* mediaserver process */
#define AID_DHCP          1014  /* dhcp client */
#define AID_SDCARD_RW     1015  /* external storage write access */
#define AID_VPN           1016  /* vpn system */
#define AID_KEYSTORE      1017  /* keystore subsystem */
#define AID_USB           1018  /* USB devices */
#define AID_DRM           1019  /* DRM server */
#define AID_MDNSR         1020  /* MulticastDNSResponder (service discovery) */
#define AID_GPS           1021  /* GPS daemon */
#define AID_UNUSED1       1022  /* deprecated, DO NOT USE */
#define AID_MEDIA_RW      1023  /* internal media storage write access */
#define AID_MTP           1024  /* MTP USB driver access */
#define AID_UNUSED2       1025  /* deprecated, DO NOT USE */
#define AID_DRMRPC        1026  /* group for drm rpc */
#define AID_NFC           1027  /* nfc subsystem */
#define AID_SDCARD_R      1028  /* external storage read access */
#define AID_CLAT          1029  /* clat part of nat464 */
#define AID_LOOP_RADIO    1030  /* loop radio devices */
#define AID_MEDIA_DRM     1031  /* MediaDrm plugins */
#define AID_PACKAGE_INFO  1032  /* access to installed package details */
#define AID_SDCARD_PICS   1033  /* external storage photos access */
#define AID_SDCARD_AV     1034  /* external storage audio/video access */
#define AID_SDCARD_ALL    1035  /* access all users external storage */#define AID_SHELL         2000  /* adb and debug shell user */
#define AID_CACHE         2001  /* cache access */
#define AID_DIAG          2002  /* access to diagnostic resources *//* The 3000 series are intended for use as supplemental group id's only.* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN  3001  /* bluetooth: create any socket */
#define AID_NET_BT        3002  /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET          3003  /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW       3004  /* can create raw INET sockets */
#define AID_NET_ADMIN     3005  /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS  3006  /* read bandwidth statistics */
#define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK  3008  /* bluetooth: access config files */#define AID_MISC          9998  /* access to misc storage */
#define AID_NOBODY        9999#define AID_APP          10000  /* first app user */#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END   99999 /* end of uids for fully isolated sandboxed processes */#define AID_USER        100000  /* offset for uid ranges for each user */#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END   59999 /* start of gids for apps in each user to share */

由以上头文件可查看到一下这行定义
#define AID_SDCARD_R 1028 /* external storage read access */
所以sdcard_r对应的groud_id 为1028

  1. 查看system_server 进程信息
    ① 查看uid

    ② 查看进程详细信息
    cd proc/1863
    cat status

从上图可以看出system_server并不属于sdcard_r(1028)用户组,所以没有读写sdcard目录的权限,所以system_server在读写sdcard文件的时候会报(Permission denied)错误(不过也可能是别的原因)

  1. 修改system_server 用户组

system_server是由ZygoteInit类负责初始化和启动的,相关的代码在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中。其中关键的启动代码如下。从代码中可以看到,在启动sysetm_server时通过–setgroups为其设置了所属用户组。

private static boolean startSystemServer()throws MethodAndArgsCaller, RuntimeException {long capabilities = posixCapabilitiesAsBits(OsConstants.CAP_KILL,OsConstants.CAP_NET_ADMIN,OsConstants.CAP_NET_BIND_SERVICE,OsConstants.CAP_NET_BROADCAST,OsConstants.CAP_NET_RAW,OsConstants.CAP_SYS_MODULE,OsConstants.CAP_SYS_NICE,OsConstants.CAP_SYS_RESOURCE,OsConstants.CAP_SYS_TIME,OsConstants.CAP_SYS_TTY_CONFIG);/* Hardcoded command line to start the system server */String args[] = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007","--capabilities=" + capabilities + "," + capabilities,"--runtime-init","--nice-name=system_server","com.android.server.SystemServer",};ZygoteConnection.Arguments parsedArgs = null;int pid;try {parsedArgs = new ZygoteConnection.Arguments(args);ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);/* Request to fork the system server process */pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,parsedArgs.debugFlags,null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}/* For child process */if (pid == 0) {handleSystemServerProcess(parsedArgs);}return true;}

我们可以在--setgroups添加1028(不是固定的,根据实际情况)


重新编译framework并烧录验证,可以查看进程信息验证用户组是否添加成功。

1、方法二

解决思路:提高system_server权限
代码路径:dalvik/vm/native/dalvik_system_Zygote.cpp

/** Utility routine to fork zygote and specialize the child process.*/
static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
{pid_t pid;uid_t uid = (uid_t) args[0];gid_t gid = (gid_t) args[1];ArrayObject* gids = (ArrayObject *)args[2];u4 debugFlags = args[3];ArrayObject *rlimits = (ArrayObject *)args[4];u4 mountMode = MOUNT_EXTERNAL_NONE;int64_t permittedCapabilities, effectiveCapabilities;char *seInfo = NULL;char *niceName = NULL;if (isSystemServer) {/** Don't use GET_ARG_LONG here for now.  gcc is generating code* that uses register d8 as a temporary, and that's coming out* scrambled in the child process.  b/3138621*///permittedCapabilities = GET_ARG_LONG(args, 5);//effectiveCapabilities = GET_ARG_LONG(args, 7);permittedCapabilities = args[5] | (int64_t) args[6] << 32;effectiveCapabilities = args[7] | (int64_t) args[8] << 32;} else {mountMode = args[5];permittedCapabilities = effectiveCapabilities = 0;StringObject* seInfoObj = (StringObject*)args[6];if (seInfoObj) {seInfo = dvmCreateCstrFromString(seInfoObj);if (!seInfo) {ALOGE("seInfo dvmCreateCstrFromString failed");dvmAbort();}}StringObject* niceNameObj = (StringObject*)args[7];if (niceNameObj) {niceName = dvmCreateCstrFromString(niceNameObj);if (!niceName) {ALOGE("niceName dvmCreateCstrFromString failed");dvmAbort();}}}......

从以上代码分析中可以看到,如果是system_server(isSystemServer)
u4 mountMode = MOUNT_EXTERNAL_NONE;
从代码分析,如果是系统进程的情况下,通过mountMode控制,让系统进程不能访问sdcard目录
(但是海思方案也是这样定义,但是system_sever也能正常访问sdcard目录,可能是底层文件系统不一样导致,还有待研究)

我们再查看mountMode参数枚举,可以看到

//代码位置:dalvik/vm/native/dalvik_system_Zygote.cpp
enum {MOUNT_EXTERNAL_NONE = 0,MOUNT_EXTERNAL_SINGLEUSER = 1,MOUNT_EXTERNAL_MULTIUSER = 2,MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
};

我们修改默认的mountMode参数

如上图,修改mountMode参数为MOUNT_EXTERNAL_MULTIUSER_ALL,允许所有的用户访问(可能会造成别的问题,谨慎修改),修改完成后单编/整编进行验证。

三、总结

因为在项目中,有个需求是需要在system_server中去读取sdcard文件,发现了system_server竟然不能访问sdcard目录文件,起先感觉到很奇怪,在我们印象中系统进程的权限一般都高于普通应用进程,普通应用都能正常读写,system_server竟然不能?通过查询资料,发现其中端倪,故写此文章记录一下问题,方便以后翻阅。

以上分析属于笔者自己理解如果有错误请大神指出,欢迎转载

Android system_server无法访问sdcard目录问题记录(Android 4.4 mtk平台)相关推荐

  1. android代码无法访问data目录,解决Android7.1.1中无法打开/data目录的问题

    C:\Users\Administrator>cd F:\AndroidSDK\platform-tools C:\Users\Administrator>F: F:\AndroidSDK ...

  2. Android SELinux开发入门指南之正确姿势解决访问data目录权限问题

      Android SELinux开发入门指南之正确姿势解决访问data目录权限问题 Android SELinux开发多场景实战指南目录: Android SELinux开发入门指南之SELinux ...

  3. android 访问data目录、6.0模拟器读写sdcard、相关sdcard路径

    转载请标明出处: http://blog.csdn.net/xx326664162/article/details/52259980 文章出自:薛瑄的博客 你也可以查看我的其他同类文章,也会让你有一定 ...

  4. Android中访问sdcard路径的几种方式

    以前的Android(4.1之前的版本)中,SDcard路径通过"/sdcard"或者"/mnt/sdcard"来表示,而在JellyBean(安卓4.1)系统 ...

  5. Android studio File Explorer sdcard文件怎么访问

    DexClassLoader myDexClassLoader = new DexClassLoader(//模拟器都没上传到手机sd卡里怎么也读出来了这个类,//说明就是找到的本地的类,//如果上传 ...

  6. Android存储访问及目录

    原文:Android存储访问及目录 Android存储访问及目录 Android的外部存储 Android支持外部存储(case-insensitive filesystem with immutab ...

  7. android访问asset目录下的资源

    android提供了AssetManager来访问asset目录下的资源, 在activity中通过getAssets()获取AssetManager 常用的api如下: 1.列举路径下的资源Stri ...

  8. Android获取SDcard目录及创建文件夹;

    获取sdcard目录 public static String getSDPath() {File sdDir = null;boolean sdCardExist = Environment.get ...

  9. android预置资源到data分区,Android R 如何访问Android/data目录?

    前言 Android R上分区存储的限制得到进一步加强,无论APP的targetsdkversion是多少,都将无法访问Android/data和Android/obb这二个应用私有目录.这无疑对会部 ...

  10. Android实现Mtp访问浏览手机存储(一)访问Mtp目录

    MTP,全称是 Media Transfer Protocol(媒体传输协议),它是微软的一个为计算机和便携式设备之间传输图像.音乐等所定制的协议.MTP 的应用分两种角色,一个是作为 Initiat ...

最新文章

  1. 用mkfs.jffs2 命令制作jffs2镜像文件 (转)
  2. 电脑开机3秒就重启循环_U盘如何变成万能维修工具?分享3款PE制作软件,小白秒变电脑高手...
  3. Express + Element-ui 实现图片/文件上传
  4. 驳《阿里「Java开发手册」中的1个bug》?
  5. L-BFGS算法/Broyden族/BFGS算法/阻尼牛顿法的Python实现代码
  6. EBITDA的计算公式
  7. Python批量提取PowerPoint文件中所有幻灯片标题和备注文本
  8. 升级到NVelocity1.1版本
  9. Pattern类正则表达式的编译表示形式
  10. 基于pycrfsuite和sklearn_crfsuite的命名实体识别NER实战【以CoNLL2002数据集为基准】
  11. uni-app image组件当显示不出图片时显示默认图片
  12. 电容电感充电曲线仿真图
  13. cie色度图matlab,带你解读 CIE1931色度图
  14. android官方开发文档中学英文-uniformly distributed int(均匀分布的整数)
  15. 关于按钮“按下”效果的两种实现
  16. java小算盘金钱存银行1秒算出每一年的利息及存款,利息一目了然
  17. 解锁“绿色计算产业白皮书”,海量数据携手绿盟成员共促生态繁荣
  18. 【Java】IntellIDEA软件的安装
  19. tcp socket 和 socket文件
  20. 如何提高模型的泛化能力

热门文章

  1. COJ 3012 LZJ的问题 (有向图判环)
  2. Python实现网络爬虫
  3. 【数据可视化】Echarts世界地图需要的数据 - JSON格式世界国家中英文对照表
  4. 虚拟主机,VPS,云主机之间的区别?
  5. Java 深入面向对象
  6. vostro3470装win7_dell latitude3470怎么安装win7系统
  7. 【笔记】C++之SLT的常用容器
  8. win10家庭版不能远程连接,升级企业版过程
  9. 020.3.25普及C组 母鸡下蛋(hen)【纪中】【模拟】
  10. ResultSet.TYPE_SCROLL_SENSITIVE到底发生了什么?