前在文章介绍过android系统管理层次:http://www.2cto.com/kf/201204/127682.html ,这里就核心代码分析一下
android系统充分利用了linux的用户权限管理方法,所以如果需要移植到其它系统,这一块也是一个相当不小的工作量。那么android系统到底是如何使用这些的有利因素呢?
首先需要知道linux权限的两个基本知识:
1、 一个用户可以属于多个组.
2、 一个文件只能属于某个组。
这里主要是在AndroidManifest.xml中声明权限,主要是通过在AndroidManifest.xml中显示地声明应用程序需要的权限,防止应用程序错误的使用服务,不恰当访问资源。
Android中每种权限都用一个独立的标签表示.如:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
当在安装(Install) 应用程序时,Android就会给予一个UID。这个UID可连结到该应用程序的 AndroidManifest.xml档案的内容。所User在安装你的应用程序时,在屏幕上的窗口里可以检视这个 AndroidManifest.xml档案的内容。在检视时,用户会看到你对应用程序的目的、权限等说明。当你接受这支程序的意图、权限说明之后,Android就安装它,并给它一个UID。万一在你的应用程序执行期间有越轨(企图做出非权限范围)的行为时,用户将会得到Android的警告讯息。
下面是两个安装程序安装时的界面
\\
这两个应用其实代码是一样的,唯一的不同就是它们的AndroidManifest.xml,图2的AndroidManifest.xml中多了如下内容:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
即需要使用存储设备和录音设备,在安装的时候,就会提示用户它需要的权限。Android里面是怎么去控制的呢?
在安装apk的时候,会解析这个AndroidManifest.xml,把相应的信息保存起来。
代码路径:frameworks\base\core\java\android\content\pm\PackageParser.java
最终调用的是private Package parsePackage(
Resources res, XmlResourceParser parser, int flags, String[] outError)
这个函数,在里面对AndroidManifest.xml进行了解析,其中就有
private Package parsePackage(
Resources res, XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
...
String tagName = parser.getName();
if (tagName.equals("application")) {
...
} else if (tagName.equals("permission-group")) {
if (parsePermissionGroup(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("permission")) {
if (parsePermission(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("permission-tree")) {
if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("uses-permission")) {
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestUsesPermission);
// Note: don't allow this value to be a reference to a resource
// that may change.
String name = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
sa.recycle();
if (name != null && !pkg.requestedPermissions.contains(name)) {
pkg.requestedPermissions.add(name.intern());
}
XmlUtils.skipCurrentTag(parser);
}
...
}
这里对它使用的权限进行了解析。
这里保存的都是"android.permission.WRITE_EXTERNAL_STORAGE"这样的字符串,在解析完后,会调用grantPermissionsLP函数获取对应的group_id,
代码路径:frameworks\base\services\java\com\android\server\PackageManagerService.java
private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) {
...
if (allowed) {
if (!gp.grantedPermissions.contains(perm)) {
changedPermission = true;
gp.grantedPermissions.add(perm);
gp.gids = appendInts(gp.gids, bp.gids);
} else if (!ps.haveGids) {
gp.gids = appendInts(gp.gids, bp.gids);
}
} else {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " because it was previously installed without");
}
...
}
这里把相应的组都保存到了gids中。
当应用程序启动的过程中会调用
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr)
代码路径:frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
...
try {
int uid = app.info.uid;
int[] gids = null;
try {
gids = mContext.getPackageManager().getPackageGids(
app.info.packageName);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
...
int pid = Process.start("android.app.ActivityThread",
mSimpleProcessManagement ? app.processName : null, uid, uid,
gids, debugFlags, null);
}
这里就是获取前面保存的gids,再后面调用创建了一个新的进程,这里传的参数就有gids
创建新进程利用jni最终调用 forkAndSpecializeCommon 函数 (路径:\dalvik\vm\native\dalvik_system_Zygote.c)
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];
int64_t permittedCapabilities, effectiveCapabilities;
...
pid = fork();
if (pid == 0) {
int err;
/* The child process */
err = setgroupsIntarray(gids);
if (err < 0) {
LOGE("cannot setgroups(): %s", strerror(errno));
dvmAbort();
}
err = setrlimitsFromArray(rlimits);
if (err < 0) {
LOGE("cannot setrlimit(): %s", strerror(errno));
dvmAbort();
}
err = setgid(gid);
if (err < 0) {
LOGE("cannot setgid(%d): %s", gid, strerror(errno));
dvmAbort();
}
err = setuid(uid);
if (err < 0) {
LOGE("cannot setuid(%d): %s", uid, strerror(errno));
dvmAbort();
}
...
}
我们看到在子进程里调用setgroupsIntarray设置该进程所属的组,这样它就拥有了该组的权限。也通过setgid及setuid决定了应用程序的uid及gid值。
举个例子:
我们新建一Android工程,读取其应用的uid/gid值,贴入如下代码:
try{
java.lang.Process process = Runtime.getRuntime().exec("id");
InputStream input = process.getInputStream();
byte[] bytes = new byte[1204];
int len;
while((len = (input.read(bytes))) > 0)
{
System.out.print(new String(bytes, 0, len));
}
input.close();
这里运行运行linux的id命令的代码,id命令的功能是输出当前用户的uid,主要的group id和所在的group
在其AndroidManifest.xml添加如下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
运行后看log里面有:
\
这里面就有groups=1015
再看下android_filesystem_config.h里面
代码路径:
system\core\include\private
有如下代码
#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_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 */
再看下platform.xml
路径:frameworks\base\data\etc
有如下配置
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_rw" />
</permission>
这样就把android.permission.WRITE_EXTERNAL_STORAGE 、"sdcard_rw"、以及 1015组关联起来了
我们再看下当sd卡挂载上去后目录的权限:
ls -l
drwxr-xr-x root system 1970-01-01 08:00 obb
drwxr-xr-x root system 1970-01-01 08:00 asec
drwx------ root root 1970-01-01 08:00 secure
d---rwxr-x system sdcard_rw 2012-03-29 17:11 sdcard
可以看到对于sd卡,组用户具有读写权限,而我们的应用也加入了这个组,这样它就可以操作sdcard了。
当一个应用需要操作sdcard而没有在AndroidManifest.xml添加相应的权限时,就不能成功完成。
以下是同一个程序,一个有在AndroidManifest.xml添加WRITE_EXTERNAL_STORAGE权限,一个没有,它们的对比,可以看到由于没有权限程序运行异常了。
\
摘自 andyhuabing的专栏
分享到:
相关推荐
3. **Android权限管理**:在Android系统中,远程控制涉及到敏感操作,因此需要获取相应的权限,如INTERNET权限、WRITE_EXTERNAL_STORAGE权限等。源码中会有对AndroidManifest.xml文件的修改,以请求必要的权限。 4....
5. **权限管理**:了解Android的权限模型,如何在源码层面实现权限控制。 6. **Dalvik/ART虚拟机**:运行时环境的优化,包括垃圾回收机制、dex文件格式、类加载等。 7. **网络通信**:Socket编程、HTTP库(如...
【Android上位机大棚控制源码】是一款专为农业大棚自动化控制设计的Android应用程序源代码。这个项目的主要目的是实现对温室大棚环境参数的监测与控制,例如温度、湿度、光照等,通过手机或平板等Android设备远程...
总的来说,这个"安卓Android源码——实现远程控制PC源代码"项目涵盖了Android应用开发的多个核心领域,对于深入理解和掌握Android系统及网络编程有极大的帮助。通过分析和学习这些源码,开发者可以提升自己的技能,...
在Android 11.0中,可能对Content Provider的安全性和权限控制进行了加强,以保护用户数据的安全。 再者,Broadcast Receiver是Android系统中实现广播事件监听的重要组件。在Android 11.0中,对于第三方应用的全局...
Android Studio SDK源码分析——聚焦Android 23 Android Studio是Google官方推荐的Android应用程序开发集成开发环境(IDE),它提供了强大的工具集,包括代码编辑器、调试器、构建工具等,极大地提升了开发者的工作...
总的来说,这个源码项目为开发者提供了一个深入理解Android权限管理和创新解决方案的机会,同时也提醒我们在开发过程中应尊重用户隐私,遵守平台规范。通过分析和学习,开发者可以提升自己的技能,同时在实际项目中...
为了更深入地理解Android的权限控制机制,我们可以通过查看源代码来了解其实现细节。例如,在Dalvik虚拟机中,每当一个方法被调用时,系统都会检查该方法所需的权限是否已被授予。此外,Linux内核级别的安全模块(如...
**Android手机管家源码解析** 本项目是一款基于Android平台的手机管理软件——“Android手机管家”的源码,它集成了四个主要功能:文件管理、应用管理、电话拦截以及文件加解密。这些功能覆盖了日常手机使用中的...
本篇将详细探讨一个特殊的项目——“Android代码-手机通过WiFi控制电脑程序”,并深入解析其背后的源码和技术实现。 首先,我们要理解这个项目的背景和基本原理。Android系统作为全球最流行的移动操作系统,拥有...
总的来说,这个C++版的Android实时投屏软件源码结合了Qt的跨平台能力、C++的高性能以及Android系统的开放接口,为开发者提供了一种无需root权限的投屏解决方案。深入研究和理解这个源码,不仅可以帮助开发者学习高级...
在Android系统中,运行时权限是一种安全机制,自Android 6.0(API级别23)引入,旨在增强...通过阅读和分析这个代码,开发者可以更好地理解和应用上述知识点,实现符合Android 6.0及以上版本权限管理规范的应用程序。
通过分析这个基于Android Studio的音乐播放器源码,开发者不仅可以学习到如何构建一个完整的音乐播放应用,还能深入理解Android平台上的多媒体处理、用户界面设计、服务组件使用等核心概念,为今后的Android开发打下...
通过分析和运行这个示例,开发者可以更好地理解和掌握Android 6.0动态权限的实践操作。 总之,Android 6.0的动态权限机制提高了用户对隐私的控制,同时也要求开发者重新思考权限管理的策略。理解并正确实现这一机制...
通过理解和分析Android Usb OTG源码,开发者可以掌握如何在Android平台上实现USB OTG功能,包括设备的检测、连接、数据传输和权限管理等,这对于开发涉及硬件交互的应用非常有帮助。同时,对于深入理解Android系统的...
通过分析和学习这个记账本源码,你可以提升Android编程技能,理解如何构建一个完整的Android应用,从UI设计到数据管理,再到用户体验的优化。同时,这也是一个实战练习,有助于你掌握面向对象设计原则、Android最佳...
9. **版本控制与Git**:Android源码使用Git进行版本控制,开发者需要熟悉Git命令来管理代码分支、合并和回滚更改。 10. **单元测试与调试**:修改源码后,开发者需要编写和运行单元测试确保改动不会引入新的错误,...
### Android PackageManagerService源码分析深度解析 #### 引言 `PackageManagerService`是Android系统中的核心组件之一,负责管理所有应用程序的安装、卸载、升级等操作,同时也是系统权限管理和应用资源查询的...
"基于访问控制列表机制的Android权限管控方案" 本文主要介绍了一种基于访问控制列表(ACL)机制的 Android 权限管控方案。该方案旨在解决 Android 权限管理中存在的粗粒度问题,避免恶意应用程序的访问,保护系统...
通过这本书的源码分析,我们可以了解到Android系统的架构、运行机制以及各个组件的工作原理。 1. **Android系统架构**:Android系统基于Linux内核,采用了分层的架构设计,包括Linux内核层、硬件抽象层(HAL)、...