Android权限分析

发布时间:2012-04-10 11:40:14   来源:文档文库   
字号:

Android权限分析

.Linux 权限介绍

Linux 系统同 Unix 系统一样,通过信任状(credential)把进程与一个特定的用户或用户组捆绑在一起。信任状决定了每个进程能做什么,不能做什么,从而保证整个系统的数据完整性和整体稳定性。

1.文件类型

Linux 中的文件共有如下几种类型,由于 Android 中不同类型的文件会通过不同的方式来设置权限位,故简单介绍 Linux 中的文件类型如下:

1).普通文件。对应 system.img ramdisk.img 中的所有文件。

2).目录文件。对应 system.img ramdisk.img 中的所有目录。

3).块特殊文件。基本存在于 /sys/proc /dev 三个目录中。

4).字符特殊文件。基本存在于 /sys/proc /dev 三个目录中。

5)FIFO。用于进程间通信,也叫命名管道,只能由相关进程使用。

6).套接字。用于网络间进程通信,也可用于本机的非网络通信。一般都在 /dev/socket 下。

7).符号链接。指向另一个文件。

注:查看文件详细信息时,文件类型显示在文件权限位的前面。命令:

ls -l ll 命令

2.文件访问权限位

文件访问权限位的组成:

u(owner) | g(group) | o(other)

r w x r w x r w x

4 2 1 4 2 1 4 2 1

注:修改文件权限时使用 chmod 命令,格式如下:

chmod path 644

chmod path 777

.Android 权限管理概述

Android 是一个多进程系统,每一个应用程序(不论是 C C++ 编译而成的二进制程序,还是运行在 dalvik 虚拟机中的 APK 包格式的 Java 程序)都运行在自己的进程中。Android 使用标准的 Linux 功能集实现了大多数应用程序和系统之间的安全性,例如通过被分配给应用程序的用户和用户组 ID,但该权限粒度较大,一般用于控制进程可访问的具体资源和设备。Android 中更细粒度的安全特性则通过许可机制来提供,该机制能够对一个指定进程可实现的特定操作进行约束。

1.文件系统中的权限设定

Android 系统编译完成后会生成三个后缀为 img 的文件,ramdisk.imgsystem.imguserdata.img,各自包含许多目录和文件。Android 系统编译时会使用两个 Android 命令 mkbootfs mkyaffs2image 来生成这些 img文件,这两个命令都会调用文件 android_filesystem_config.h 中预制的权限,来写入这些目录和文件资源初始的访问权限。

下面列出该文件内容,并给出了相应的修改实例(红色字体标出):

文件: system/core/include/private/android_filesystem_config.h

/*

* Copyright (C) 2007 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

/* This file is used to define the properties of the filesystem

** images generated by build tools (mkbootfs and mkyaffs2image) and

** by the device side of adb.

*/

#ifndef _ANDROID_FILESYSTEM_CONFIG_H_

#define _ANDROID_FILESYSTEM_CONFIG_H_

#include

#include

#include

/* This is the master Users and Groups config for the platform.

** DO NOT EVER RENUMBER.

*/

#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_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_MISC 9998 /* access to misc storage */

#define AID_NOBODY 9999

#define AID_APP 10000 /* first app user */

#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)

struct android_id_info {

const char *name;

unsigned aid;

};

static struct android_id_info android_ids[] = {

{ "root", AID_ROOT, },

{ "system", AID_SYSTEM, },

{ "radio", AID_RADIO, },

{ "bluetooth", AID_BLUETOOTH, },

{ "graphics", AID_GRAPHICS, },

{ "input", AID_INPUT, },

{ "audio", AID_AUDIO, },

{ "camera", AID_CAMERA, },

{ "log", AID_LOG, },

{ "compass", AID_COMPASS, },

{ "mount", AID_MOUNT, },

{ "wifi", AID_WIFI, },

{ "dhcp", AID_DHCP, },

{ "adb", AID_ADB, },

{ "install", AID_INSTALL, },

{ "media", AID_MEDIA, },

{ "shell", AID_SHELL, },

{ "cache", AID_CACHE, },

{ "diag", AID_DIAG, },

{ "net_bt_admin", AID_NET_BT_ADMIN, },

{ "net_bt", AID_NET_BT, },

{ "sdcard_rw", AID_SDCARD_RW, },

{ "vpn", AID_VPN, },

{ "keystore", AID_KEYSTORE, },

{ "inet", AID_INET, },

{ "net_raw", AID_NET_RAW, },

{ "net_admin", AID_NET_ADMIN, },

{ "misc", AID_MISC, },

{ "nobody", AID_NOBODY, },

};

#define android_id_count \

(sizeof(android_ids) / sizeof(android_ids[0]))

struct fs_path_config {

unsigned mode;

unsigned uid;

unsigned gid;

const char *prefix;

};

/* Rules for directories.

** These rules are applied based on "first match", so they

** should start with the most specific path and work their

** way up to the root.

*/

static struct fs_path_config android_dirs[] = {

{ 00770, AID_SYSTEM, AID_CACHE, "cache" },

{ 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },

{ 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },

{ 00771, AID_SYSTEM, AID_SYSTEM, "data/dalvik-cache" },

{ 00771, AID_SYSTEM, AID_SYSTEM, "data/data" },

{ 00771, AID_SHELL, AID_SHELL, "data/local/tmp" },

{ 00771, AID_SHELL, AID_SHELL, "data/local" },

{ 01771, AID_SYSTEM, AID_MISC, "data/misc" },

{ 00770, AID_DHCP, AID_DHCP, "data/misc/dhcp" },

{ 00771, AID_SYSTEM, AID_SYSTEM, "data" },

{ 00750, AID_ROOT, AID_SHELL, "sbin" },

{ 00755, AID_ROOT, AID_SHELL, "system/bin" },

{ 00755, AID_ROOT, AID_SHELL, "system/xbin" },

{ 00755, AID_ROOT, AID_ROOT, "system/etc/ppp" },

{ 00777, AID_ROOT, AID_ROOT, "sdcard" },

/* 新增目录的权限在此处添加 */

{ 00755, AID_ROOT, AID_ROOT, 0 },

};

/* Rules for files.

** These rules are applied based on "first match", so they

** should start with the most specific path and work their

** way up to the root. Prefixes ending in * denotes wildcard

** and will allow partial matches.

*/

static struct fs_path_config android_files[] = {

{ 00440, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.rc" },

{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.goldfish.sh" },

{ 00440, AID_ROOT, AID_SHELL, "system/etc/init.trout.rc" },

{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.ril" },

{ 00550, AID_ROOT, AID_SHELL, "system/etc/init.testmenu" },

{ 00550, AID_DHCP, AID_SHELL, "system/etc/dhcpcd/dhcpcd-run-hooks" },

{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },

{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/main.conf" },

{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/input.conf" },

{ 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/audio.conf" },

{ 00444, AID_NET_BT, AID_NET_BT, "system/etc/bluetooth/blacklist.conf" },

{ 00640, AID_SYSTEM, AID_SYSTEM, "system/etc/bluetooth/auto_pairing.conf" },

{ 00444, AID_RADIO, AID_AUDIO, "system/etc/AudioPara4.csv" },

{ 00555, AID_ROOT, AID_ROOT, "system/etc/ppp/*" },

{ 00644, AID_SYSTEM, AID_SYSTEM, "data/app/*" },

{ 00644, AID_SYSTEM, AID_SYSTEM, "data/app-private/*" },

{ 00644, AID_APP, AID_APP, "data/data/*" },

/* the following two files are INTENTIONALLY set-gid and not set-uid.

* Do not change. */

{ 02755, AID_ROOT, AID_NET_RAW, "system/bin/ping" },

{ 02750, AID_ROOT, AID_INET, "system/bin/netcfg" },

/* the following five files are INTENTIONALLY set-uid, but they

* are NOT included on user builds. */

{ 06755, AID_ROOT, AID_ROOT, "system/xbin/su" },

{ 06755, AID_ROOT, AID_ROOT, "system/xbin/librank" },

{ 06755, AID_ROOT, AID_ROOT, "system/xbin/procrank" },

{ 06755, AID_ROOT, AID_ROOT, "system/xbin/procmem" },

{ 06755, AID_ROOT, AID_ROOT, "system/xbin/tcpdump" },

{ 04770, AID_ROOT, AID_RADIO, "system/bin/pppd-ril" },

/* the following file is INTENTIONALLY set-uid, and IS included

* in user builds. */

{ 06750, AID_ROOT, AID_SHELL, "system/bin/run-as" },

{ 00755, AID_ROOT, AID_SHELL, "system/bin/*" },

{ 00755, AID_ROOT, AID_SHELL, "system/xbin/*" },

{ 00750, AID_ROOT, AID_SHELL, "sbin/*" },

{ 00755, AID_ROOT, AID_ROOT, "bin/*" },

{ 00750, AID_ROOT, AID_SHELL, "init*" },

/* BEGIN Helgan added.

/* 新增文件的权限在此处添加 */

/* END Helgan added */

{ 00644, AID_ROOT, AID_ROOT, 0 },

};

static inline void fs_config(const char *path, int dir,

unsigned *uid, unsigned *gid, unsigned *mode)

{

struct fs_path_config *pc;

int plen;

pc = dir ? android_dirs : android_files;

plen = strlen(path);

for(; pc->prefix; pc++){

int len = strlen(pc->prefix);

if (dir) {

if(plen < len) continue;

if(!strncmp(pc->prefix, path, len)) break;

continue;

}

/* If name ends in * then allow partial matches. */

if (pc->prefix[len -1] == '*') {

if(!strncmp(pc->prefix, path, len - 1)) break;

} else if (plen == len){

if(!strncmp(pc->prefix, path, len)) break;

}

}

*uid = pc->uid;

*gid = pc->gid;

*mode = (*mode & (~07777)) | pc->mode;

#if 0

fprintf(stderr,"< '%s' '%s' %d %d %o >\n",

path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode);

#endif

}

#endif

#endif

2.设备类文件的权限

1) .设备文件

Android 系统中,kernel 启动后启动的第一个上层进程为 init 进程,init 进程会打开定义为 NETLINK_KOBJECT_UEVENT 15 socket,来接收内核发送的添加和删除设备的 uevnet消息。并根据 devices.c 文件中定义的数组 devperms 中的权限给相应的设备节点设置权限位。新增设备文件或修改设备文件的权限和所有者时,可通过修改该数组实现。

该数组定义和相应的修改位置如下:

文件 system/core/init/devices.c

static struct perms_ devperms[] = {

{ "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/full", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/random", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },

{ "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },

/* logger should be world writable (for logging) but not readable */

{ "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 },

/* the msm hw3d client device node is world writable/readable. */

{ "/dev/msm_hw3dc", 0666, AID_ROOT, AID_ROOT, 0 },

/* gpu driver for adreno200 is globally accessible */

{ "/dev/kgsl", 0666, AID_ROOT, AID_ROOT, 0 },

/* these should not be world writable */

{ "/dev/diag", 0660, AID_RADIO, AID_RADIO, 0 },

{ "/dev/diag_arm9", 0660, AID_RADIO, AID_RADIO, 0 },

{ "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 },

{ "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },

{ "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },

{ "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 },

{ "/dev/uinput", 0660, AID_SYSTEM, AID_BLUETOOTH, 0 },

{ "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },

{ "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 },

{ "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },

{ "/dev/msm_hw3dm", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },

{ "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },

{ "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 },

{ "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 },

{ "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },

{ "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 },

{ "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },

{ "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/snd/", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },

{ "/dev/msm_camera/", 0660, AID_SYSTEM, AID_SYSTEM, 1 },

{ "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },

{ "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },

{ "/dev/akm8973_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },

{ "/dev/akm8973_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },

{ "/dev/bma150", 0640, AID_COMPASS, AID_SYSTEM, 0 },

{ "/dev/cm3602", 0640, AID_COMPASS, AID_SYSTEM, 0 },

{ "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },

{ "/dev/lightsensor", 0640, AID_SYSTEM, AID_SYSTEM, 0 },

{ "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/audience_a1026", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/tpa2018d1", 0660, AID_SYSTEM, AID_AUDIO, 1 },

{ "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/msm_audio_ctl", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/vdec", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/q6venc", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/snd/dsp", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/snd/dsp1", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/snd/mixer", 0660, AID_SYSTEM, AID_AUDIO, 0 },

{ "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },

{ "/dev/qemu_trace", 0666, AID_SYSTEM, AID_SYSTEM, 0 },

{ "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },

{ "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },

{ "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },

{ "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },

/* CDMA radio interface MUX */

{ "/dev/ts0710mux", 0640, AID_RADIO, AID_RADIO, 1 },

{ "/dev/ppp", 0660, AID_RADIO, AID_VPN, 0 },

{ "/dev/tun", 0640, AID_VPN, AID_VPN, 0 },

/* BEGIN Helgan added */

/* 新增设备时添加到此处 */

/* END Helgan added */

{ NULL, 0, 0, 0, 0 },

};

2).其他文件

其他由 kernel init及其脚本创建的文件,如果需要修改访问权限,可以通过通过 init 程序使用的脚本文件控制,但不建议直接修改 init.rc 文件,而应该集中在和硬件相关的或新增的 init.vendore.rc 脚本文件中修改,这样做的好处是集中管理,便于移植和版本升级。

原始的 init.c 文件中会解析加载两个 init 脚本文件,代码如下:

文件 system/core/init/init.c

……

open_devnull_stdio();

log_init();

INFO("reading config file\n");

parse_config_file("/init.rc"); /* 加载标准的 init 脚本文件 */

/* pull the kernel commandline and ramdisk properties file in */

qemu_init();

import_kernel_cmdline(0);

get_hardware_name();

snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); /* 硬件相关 init 脚本 */

parse_config_file(tmp);

action_for_each_trigger("early-init", action_add_queue_tail);

drain_action_queue();

INFO("device init\n");

device_fd = device_init();

property_init();

……

其中和硬件相关的脚本文件名称由从 kernel 中传入的 /proc/cmdline 节点解析组合而来。

如在高通平台为 init.qcom.rc,修改在脚本文件的相应位置添加如下代码即可:

# BEGIN Helgan added.

chown system system /proc/driver/audiocontrolproc/pointercal

chmod 644 /proc/driver/audiocontrolproc/pointercal

# END Helgan added.

3.Android 上层应用即 APK 权限的实现

Android 上层使用的细粒度权限控制不是本文讨论的重点,下面给出 SDK 中的一段标准说明,已翻译。如有不明请参考最新的 SDK 文档。

Android的安全与权限

Android是一个多进程系统,每一个应用程序(和系统的组成部分)都运行在自己的进程中。在应用程序和系统间的安全通过标准的Linux设备在进程级被执行,例如被分配给应用程序的用户和组ID。额外的细粒度安全特性通过许可机制来提供,该机制能够对一个指定进程可实现的特定操作进行约束。

内容

安全结构

应用程序签名

用户标识和文件访问

权限命名

权限的声明和支持

AndroidManifest.xml文件中支持权限

发送广播时支持权限

其它权限的支持

URI权限

安全结构

Android安全学中的一个重要的设计点是在默认情况下应用程序没有权限执行对其它应用程序、操作系统或用户有害的操作。这些操作包括读/写用户的隐私数据(例如联系方式或e-mail),读/写其它应用程序的文件,执行网络访问,保持设备活动,等等。

应用程序的进程是一个安全的沙箱。它不能干扰其它应用程序,除非在它需要添加原有沙箱不能提供的功能时明确声明权限。这些权限请求能够被不同方式的操作所处理,特别的要基于证书和用户的提示被自动的允许或禁止。权限的请求在那个应用程序中通过一个应用程序被声明为静态的,所以在此之后在安装时或没有改变时它们会预先知道。

应用程序签名

所有的Android应用程序(.apk文件)必须通过一个证书的签名,此证书的私钥必须被开发者所掌握。这个证书的标识是应用程序的作者。这个证书需要通过证书组织的签署:Android应用程序对于使用自签署的证书是完全允许的和特别的。这个证书仅仅被用于与应用程序建立信任关系,不是为了大规模的控制应用程序可否被安装。最重要的方面是通过确定能够访问原始签名权限和能够共享用户ID的签名来影响安全。

用户标识和文件访问

安装在设备中的每一个Android包文件(.apk)都会被分配给一个属于自己的统一的Linux用户ID,并且为它创建一个沙箱以防止影响其它应用程序(或者其它应用程序影响它)。用户ID 在应用程序安装到设备中时被分配,并且在这个设备中保持它的永久性。

因为安全执行发生在进程级,所以一些不同包中的代码在相同进程中不能正常的运行,自从他们需要以不同Linux用户身份运行时。你可以使用每一个包中的AndroidManifest.xml文件中的manifest 标签属性sharedUserId 拥有它们分配的相同用户ID。通过这样做,两个包被视为相同的应用程序的安全问题被解决了,注意为了保持安全,仅有相同签名(和请求相同sharedUserId标签)的两个应用程序签名将会给相同的用户ID

应用创建的任何文件都会被赋予应用的用户标识,并且,正常情况下不能被其它包访问。当你通过getSharedPreferences(String, int), openFileOutput(String, int) 或者 openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)创建一个新文件时, 你可以同时或分别使用 MODE_WORLD_READABLE MODE_WORLD_WRITEABLE 标志允许其它包读/写此文件。当设置了这些标志时,这个文件仍然属于你的应用程序,但是它的全局读、写和读写权限已经设置所以其它任何应用程序可以看到它。

权限命名

一个基本的Android应用程序没有与其相关联的权限,意味着它不能做任何影响用户体验或设备中的数据的有害操作。要利用这个设备的保护特性,在你的应用程序需要时,你必须在AndroidManifest.xml文件中包含一个或更多的 标签来声明此权限。

例如:需要监听来自SMS消息的应用程序将要指定如下内容:

xmlns:android="http://schemas.android.com/apk/res/android"

package="com.android.app.myapp" >

android:name="android.permission.RECEIVE_SMS" />

在安装应用程序时,通过包安装器应用程序要通过权限请求的许可,使建立在与应用程序签名的核对下声明对于用户的那些权限和影响。在应用运行期间对用户不做检查:它要么在安装时被授予特定的许可,并且使用想用的特性;要么不被授予许可,并且使得一切使用特性的尝试失败而不提示用户。

例如,sendBroadcast(Intent) 方法就是当数据被发送给到每个接收器时检查许可的,在方法调用返回之后,因此当许可失败时你不会收到一个异常。然而,几乎在所有例子中,许可失败都会被打印到系统日志中。通常,多次的许可错误会产生抛回至应用程序的SecurityException异常。

Android系统提供的许可可以在Manifest.permission中找到。每个引用也可以定义和Enforce它自己的许可,因此这不是全面的所有可能的列表。

在程序操作期间,个别权限在一些地方可能被强制:

在系统接到呼叫的时候,预防一个应用程序去执行特定的函数。

在启动Activity时,防止一个应用启动其它应用程序的Activities

发送和接收Intent广播时,控制谁能接收你的广播或者谁能发送广播给你。

在一个内容提供器上访问和操作时。

绑定或开始一个服务时。

权限的声明和支持

为了执行你自己的权限,你必须首先在你的AndroidManifest.xml中使用一个或多个 标签声明它们。

例如,一个应用程序想用控制谁能启动一个activities,它可以为声明一个做这个操作的许可,如下:

xmlns:android="http://schemas.android.com/apk/res/android"

package="com.me.app.myapp" >

android:name="com.me.app.myapp.permission.DEADLY_ACTIVITY"

android:label="@string/permlab_deadlyActivity"

android:description="@string/permdesc_deadlyActivity"

android:permissionGroup="android.permission-group.COST_MONEY"

android:protectionLevel="dangerous" />

属性是必需的,告诉系统用户应如何处理应用程序接到请求此权限的通知,或者在这个文档中对这个权限的许可的描述。

属性是可选的,仅仅用于帮助系统为用户显示权限。通常,你要设置这些,向一个标准的系统组(列在android.Manifest.permission_group中),或者在更多的情况下要自定义。它更偏向于使用一个已经存在的组,做为简化的权限用户界面显示给用户。

注意:应该为每个权限提供标签(label) 和描述(description)。当用户浏览权限列表时,它们可以为用户展示字符资源,如(android:label) 或者一个许可的详细信息 ( android:description) 。标签(label)比较短,用几个词来描述该权限保护的关键功能。描述(description)应该是一组句子,用于描述获得权限的用户可以做什么。我们写描述的习惯是两句话,第一句声明权限,第二句警告用户如果应用许可该权限时,会发生什么不好的事情。

下面是一个CALL_PHONE权限的标签和描述的例子:

name="permlab_callPhone">directly call phone numbers

name="permdesc_callPhone">Allows the application to call

phone numbers without your intervention. Malicious applications may

cause unexpected calls on your phone bill. Note that this does not

allow the application to call emergency numbers.

你可以在系统中通过shell命令 adb shell pm list permissions查看权限当前定义。特别,'-s'  操作以简单粗略的方式为使用者显示权限:

$ adb shell pm list permissions -s

All Permissions:

Network communication: view Wi-Fi state, create Bluetooth connections, full

Internet access, view network state

Your location: access extra location provider commands, fine (GPS) location,

mock location sources for testing, coarse (network-based) location

Services that cost you money: send SMS messages, directly call phone numbers

...

AndroidManifest.xml文件中支持权限

通过 AndroidManifest.xml 文件可以设置高级权限,以限制访问系统的所有组件或者使用应用程序。所有的这些请求都包含在你所需要的组件中的 android:permission属性,命名这个权限可以控制访问此组件。

Activity 权限 (使用 标签) 限制能够启动与 Activity 权限相关联的组件或应用程序。此权限在 Context.startActivity() Activity.startActivityForResult() 期间要经过检查;如果调用者没有请求权限,那么会为调用抛出一个安全异常( SecurityException )

Service 权限(应用 标签)限制启动、绑定或启动和绑定关联服务的组件或应用程序。此权限在 Context.startService(), Context.stopService() Context.bindService() 期间要经过检查;如果调用者没有请求权限,那么会为调用抛出一个安全异常( SecurityException )

BroadcastReceiver 权限(应用 标签)限制能够为相关联的接收者发送广播的组件或应用程序。在 Context.sendBroadcast() 返回后此权限将被检查,同时系统设法将广播递送至相关接收者。因此,权限失败将会导致抛回给调用者一个异常;它将不能递送到目的地。在相同方式下,可以使 Context.registerReceiver() 支持一个权限,使其控制能够递送广播至已登记节目接收者的组件或应用程序。其它的,当调用 Context.sendBroadcast() 以限制能够被允许接收广播的广播接收者对象一个权限(见下文)。

ContentProvider 权限(使用 标签)用于限制能够访问 ContentProvider 中的数据的组件或应用程序。(Content providers 有一个重要的附加安全设施可用于它们调用被描述后的URI权限。) 不同于其它组件,它有两个不相连系的权限属性要设置:android:readPermission 用于限制能够读取提供器的组件或应用程序, android:writePermission 用于限制能够写入提供器的组件或应用程序。注意,如果一个提供者的读写权限受保护,意思是你只能从提供器中读,而没有写权限。当你首次收回提供者(如果你没有任何权限,将会抛出一个SecurityException异常),那么权限要被检查,并且做为你在这个提供者上的执行操作。 使用 ContentResolver.query() 请求获取读权限; 使用 ContentResolver.insert(), ContentResolver.update() ContentResolver.delete() 请求获取写权限。在所有这些情况下,一个SecurityException异常从一个调用者那里抛出时不会存储请求权限结果。

发送广播时支持权限

当发送一个广播时你能总指定一个请求权限,此权限除了权限执行外,其它能发送Intent到一个已注册的BroadcastReceiver 的权限均可以。 通过调用 Context.sendBroadcast() 及一些权限字符串, 为了接收你的广播,你请求一个接收器应用程序必须持有那个权限。

注意,接收者和广播者都能够请求一个权限。当这样的事发生了,对于Intent来说,这两个权限检查都必须通过,为了交付到共同的目的地。

其它权限支持

任意一个好的粒度权限都能够在一些调用者的一个服务中被执行。 Context.checkCallingPermission() method. 方法一起被完成。调用并产生一个需要的权限字符串,它将返回一个整型,以确定当前调用进程是否被许可。注意,仅仅当你执行的调用进入到其它进程的时候这些才会被使用,通常,通过IDL接口从一个服务发布,或从一些其它方式通知其它进程。

这有许多其它有益的方式去检查权限。如果你有一个其它进程的PID,你可以使用上下文的方法 Context.checkPermission(String, int, int) 检查权限违反PID 如果你有一个其它应用程序的包名, 你可以使用直接的包管理器方法 PackageManager.checkPermission(String, String) 去查看特定的包是否被指定的权限所许可。

URI权限

迄今为止,在与内容提供器共同使用时,标准权限系统描述通常是不充分的。一个内容提供器要保护它自己及读和写权限,当为了它们产生作用,它的直接客户端总是需要手动的对其它应用程序指定URI。一个典型的例子是邮件应用程序中的附件。访问邮件的权限应该被保护,因为这是敏感用户数据。可以,如果一个网址图片附件提供给一个图片查看器,那个图片查看器将没有权限打开这个附件,因为它没有原因去拥有一个权限从而不能访问所有的电子邮件。

对于这个问题的解决是通过网址权限:当开始一个活动或对一个活动返回一个结果,调用者可通过设置Intent.FLAG_GRANT_READ_URI_PERMISSION Intent.FLAG_GRANT_WRITE_URI_PERMISSION 中的一个或者两个。允许接收活动权限访问在Intent中特定的数据地址,不论它有权限访问数据在内容提供器相应的Intent中。

这种机制允许一个公用的功能性模型使用户相互交互(打开一个附件,从一个列表中选择一个联系人,等等)驱动ad-hoc在优粒度权限的许可下。这可能是一个主要设备,应用程序为了减少这个权限而需要,仅仅直接关系到它们的行为。

这优粒度URI权限的许可工作,然而,请求一些协作和内容提供者保持那些URI。强烈推荐内容提供者实现这种设备,并且通过android:grantUriPermissions 属性或者 标签声明支持它。

更多信息可以在Context.grantUriPermission(), Context.revokeUriPermission(), Context.checkUriPermission() 方法中找到。

本文来源:https://www.2haoxitong.net/k/doc/45e8c209ba1aa8114431d946.html

《Android权限分析.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式