运行安全通过两个层面进行保护。进程层面:不同应用运行在不同的进程,每个应用有独自的user ID;在操作层面,Android定义了所需保护的功能和资源,如果应用需要访问这些信息,必须在AndroidManifest.xml文件中请求许可,应用可以有自定义的许可。
进程边界
每个应用的userID不同,使得各个进程之间存在隔离的边界,防止应用直接获取其他应用的数据,需要通过content provider,用intent唤起其他应用的acitivity,通过service和其他应用通信,这些需要专门代码仔细实现。
声明和使用权限
Android对需要保护的资源和能力要求在AndroidManifest.xml中进行生命,在安装时由用户进行许可,如果没有许可,任何尝试执行或访问相关功能的会permission failure。Android系统相关的许可,可以阅读:http://developer.android.com/reference/android/Manifest.permission.html。
AndroidManifest.xml的许可设置
下面是设置访问摄像头,读取联系人和日历。
<manifest … >
<application>
…
</application>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALENDAR" />
</manifest>
也可以通过图形界面进行设置。
自定义权限
可对任何的component进行自定义许可,例如activity。在下面的例子中,应用A为ProPermission,当中有个activity为PrivActivity,在应用A中,我们将对这个组件进行权限的自定义声明。应用B为ProPermissionClient,在应用B中,通过intent唤起应用A的PrivActivity,应用B需要请求在应用A中的自定义权限。
我们先来看看应用A。
应用A的PrivActivity很简单,layout里面就一个textview。重点看看在AndroidManifest.xml中如何为PrivActivity提供自定义的权限。首先,我们要定义一个自定义的权限,其次,我们将这个自定义的权限加诸在PrivActivity上。
定义自定义的权限,可以使用图形界面,如下所示:
我们自定义的权限名字为wei.permission.STARTPRIVACTIVITY,格式参考系统权限android.permission.xxxxx。Label和Description都不是必须的,主要用来描述权限的内容,起到注释的作用,对于不喜欢写文档的我们,就要在编程中尽量做到不言自明,因此好的编程风格,应该加上相关的说明。Permission group对于自定义的权限是不应该填写的,如果非要设置(何必呢),可以填android.permission-group.SYSTEM_TOOLS。
Protection level值得注意,权限保护等级划分为normal、dangerous、signature、signatureOrSystem。normal表示权限是低风险的,不会对系统、用户或其他应用程序造成危害。dangerous表示权限是高风险的,系统将可能要求用户输入相关信息,才会授予此权限。signature表明只有当应用程序所用数字签名与声明此权限的应用程序所有数字签名相同时,才能将权限授给它。signatureOrSystem表示将权限授给具有相同数字签名的应用程序或Android包类,这一级别适用于非常特殊的情况,比如多个供应商需要通过系统img共享功能时。
AndroidManifest.xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest ……>
<uses-sdk …… />
<!-- 自定义的代码由上述的图形界面帮助生产 -->
<permission android:name="wei.permission.STARTPRIVACTIVITY"
android:label="start priv activity"
android:protectionLevel="normal"
android:description="@string/startPrivActivityDesc" />
<application ....... >
<activity android:name="cn.wei.flowingflying.propermission.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="PrivActivity"
android:permission="wei.permission.STARTPRIVACTIVITY"
android:label="@string/privActivity">
<intent-filter >
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
</application>
</manifest>
在PrivAcitivity的定制中,通过android:permission属性来声明该组件的需要具备的权限。我们还注意到,通过<intent-filter>来对activity做进一步说明。如果没有<intent-fliter>,应用B调用是则会报错,如下:
这个报错和权限没有关系,而是应用B视图调用其他应用的activity,而两者具有不同的userID,无法进行调用。如果要调用,则PrivActivity需要声明自己运行被调用,本例通过表明是MAIN,可以被外部调用。也可以用下面表明支持隐性调用方式,说明可被调用。
<intent-filter >
<action android:name="cn.wei.flowingflying.propermission.intent.action.PrivActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
现在,让我们来看看应用B,应用B通过intent的方式调用应用A的PrivActivity,程序代码很简单,不在重复,可以下载例子来查看。应用B在AndroidManifest.xml中请求自定义权限的方式和请求系统权限方式一样,如下:
<uses-permission android:name="wei.permission.STARTPRIVACTIVITY" />
如果没有进行权限请求,则会报错:
本博文涉及的例子代码,可以在Pro Android学习:permission例子中下载。