概述

Android 是一个多任务的系统,所以安全成了一个系统中一大重要的课题,为了保证应用的数据安全采用了应用签名,沙箱机制,权限机制等三种机制,在Android系统中用户在安装了一个应用程序后,操作系统为该应用程序创建一个与之关联的新的用户配置文件,每个应用程序都作为不同的用户运行,它在文件系统中拥有自己的文件,用户ID和一个安全的操作环境。应用程序在操作系统上使用自己的用户ID,自己的Dalvik虚拟机实例运行在自己的进程内。要访问系统上的共享资源,Android应用程序需要注册所需的权限,同时可以将自己的权限声明为可供其他程序使用,也可以为了更加精细得控制应程序而声明任意数量的不同权限,如只读,读写权限。作为内容提供的应用程序也可能需要为其他应用程序提供即时的权限,以共享特定的信息,这可以通过使用URI来进行临时的授权与撤销。应用程序通过签名建立用户信任,所有的Android应用程序包都使用证书进行了签名,这样用户可以了解应用程序的可靠性。证书的私钥为开发人员所有,这有助于在开发人员和用户之间建立一种信任关系。要在Android市场上发布应用程序,开发人员需要创建一个账号,Android市场管理非常严密,不允许出现任何的恶意软件。Android平台上没有本地应用和开发人员创建的第三方应用程序的区别,在为应用程序提供适当授权后,所有的应用程序都具有对核心库和底层硬件接口的访问权。

沙箱机制

应用的签名已经在之前的博客中已经做了介绍,这里就不再详细展开。

下面重点介绍沙箱机制和权限机制:

上面介绍过Linux内核给每个用户分配一个UID,用户可同时拥有多个运行进程,每个进程都运行于各自独立的内存空间,进程与进程之前无法进行数据访问,Android为每个应用程序分配一个UID,通过这种方式将每一个应用程序置于“沙箱”之内,实现应用程序之间的隔离,通过权限限制API调用及数据访问

不同数据之间数据是不能相互访问是,而同一个UID的应用之间可以共享数据,如下图所示:


要想两个应用通过UID共享数据需要在在Manifest节点中增加相同的android:sharedUserId属性,并确保共享数据的两个应用拥有相同的签名

Android系统权限机制

系统已定义的权限,我们可以通过执行

$ adb shell pm list permissions查看

我们可以通过在应用的Manifest使用这些权限来达到访问被保护的API或资源的目的,但并不是使用了就一定能够访问的,需要看指定权限的保护级别。

定义权限:

在应用中自定义权限,我们可以在应用的Manifest文件中进行权限声明,基本格式如下:

<permission       
android:name="com.tct.permission.START_JIMMY_ACTIVITY"
android:protectionLevel="normal"
android:label="@string/lable_start_Act"
android:description="@string/permdesc_startAct">
</permission>

定义权限的四个关键属性如下所示:



权限的使用方式,通过在Manifest文件中声明标签来使用已定义的权限,从而达到访问受保护数据的目的:

<uses-permission android:name="com.idealist.permission.START_JIMMY_ACTIVITY"/>
<uses-permission android:name="com.idealist.permission.WRITE_CONTENTPROVIDER"/>
<uses-permission android:name="com.idealist.permission.READ_CONTENTPROVIDER"/>

下面是几个比较典型的例子:

从一个应用的Activity启动另一个应用中的Activity
ComponentName componentName = new ComponentName(
"com.idealist.test.activity",/*包路径*/
"com.idealist.test.activity.DemoActivity"/*Activity类*/
);

Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("resUrl", resurl);
bundle.putSerializable("picUrlList", picurllist);
intent.putExtras(bundle);
intent.setComponent(componentName);
startActivity(intent);
从一个应用中控制另一个应用中的服务

首先需要在声明服务的时候将enable和exported设置为true

<service Android:name=".xxxService" android:enabled="true" android:exported="true">

然后和上一个例子一样使用完整的包名来设置component

Intent  testIntent = newIntent();
testIntent.setComponent(new ComponentName("包名","包名.xxxService"));
booleanisbind=bindService(testIntent,serviceConnection,Context.BIND_AUTO_CREATE);
发送带权限的广播以及给广播接收器添加权限
  • 权限定义,并且使用自定义权限
<uses-permission android:name="com.idealist.permissions.MY_BROADCAST" />
<permission
android:name="com.idealist.permissions.MY_BROADCAST"
android:protectionLevel="signature" >
</permission>
  • 自定义并注册广播
private static final String BROADCAST_PERMISSION_DISC = "com.idealist.permissions.MY_BROADCAST";
private static final String BROADCAST_ACTION_DISC = "com.idealist.permissions.my_broadcast";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_permissions_activity);
//......................................
// 注册广播接收
BroadcastReceiver receiveBroadCast = new ReceiveBroadCast();
IntentFilter filter = new IntentFilter();
filter.addAction(BROADCAST_ACTION_DISC);
registerReceiver(receiveBroadCast, filter,BROADCAST_PERMISSION_DISC,null);
}

public class ReceiveBroadCast extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(BroadcastPermissionsActivity.this,
"Hello!", 0).show();
}

}

注册一个广播,并且申明,这个广播需要BROADCAST_PERMISSION_DISC权限才能收到消息。但是我们应用程序已经注册了这个权限。所以是有这个权限的。

  • 发送广播
    发送广播的函数有好几个,其中一个是sendBroadcast(Intent intent, String receiverPermission)。使用这个函数发送广播之后,接收器需要先注册权限才可以接收的。
    public void sendBroadcastWithPermissions() {
    Intent intent = new Intent();
    intent.setAction(BROADCAST_ACTION_DISC);
    sendBroadcast(intent,BROADCAST_PERMISSION_DISC);
    }
给Content Provider设置权限
<provider
android:name="com.example.activityplancontentprovider.contentprovider.CustomProvider"
android:authorities="com.example.provider.activityplancontentprovider"
android:exported="true"
android:readPermission="com.example.provider.activityplancontentprovider.permission.READPROVIDER"
android:writePermission="com.example.provider.activityplancontentprovider.permission.WRITEPROVIDER" >
<path-permission
android:pathPattern="/activity" android:readPermission="com.example.provider.activityplancontentprovider.permission.READACTIVITY_PROVIDER" />
<path-permission
android:pathPattern="/attend_person" android:readPermission="com.example.provider.activityplancontentprovider.permission.READATTEND_PEOPLE_PROVIDER" />
</provider>

上面的例子中为整个数据库的写入设置了
android:writePermission=”com.example.provider.activityplancontentprovider.permission.WRITEPROVIDER”权限,
为整个数据库的读设置了
android:readPermission=”com.example.provider.activityplancontentprovider.permission.READPROVIDER”权限
为activity表格设置了
android:readPermission=”com.example.provider.activityplancontentprovider.permission.READACTIVITY_PROVIDER”权限
为attend_person表格设置了
android:readPermission=”com.example.provider.activityplancontentprovider.permission.READATTEND_PEOPLE_PROVIDER”权限

将权限临时赋予另一个没有权限的Activity
<provider
android:name="com.example.activityplancontentprovider.contentprovider.CustomProvider"
android:authorities="com.example.provider.activityplancontentprovider"
android:exported="true"
android:readPermission="com.example.provider.activityplancontentprovider.permission.READPROVIDER"
android:writePermission="com.example.provider.activityplancontentprovider.permission.WRITEPROVIDER" >
<path-permission
android:pathPattern="/activity" android:readPermission="com.example.provider.activityplancontentprovider.permission.READACTIVITY_PROVIDER" />
<path-permission
android:pathPattern="/attend_person" android:readPermission="com.example.provider.activityplancontentprovider.permission.READATTEND_PEOPLE_PROVIDER" />
<grant-uri-permission android:pathPrefix="/activity" />
</provider>

假设ActivityWithNoPermission中没有访问活动表格的权限,但是在ActivityPlans启动ActivityWithNoPermission的时候使用
startActivityIntent.setData(Uri.parse(“content://com.example.provider.activityplancontentprovider/activity”));
startActivityIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
自己拥有的访问活动表格的权限通过Intent赋予ActivityWithNoPermission,这样在ActivityWithNoPermission就可以使用临时的访问权限,以及传递过来的Uri访问活动表格。

Contents
  1. 1. 概述
  2. 2. 沙箱机制
  3. 3. Android系统权限机制
    1. 3.1. 定义权限:
    2. 3.2. 从一个应用的Activity启动另一个应用中的Activity
    3. 3.3. 从一个应用中控制另一个应用中的服务
    4. 3.4. 发送带权限的广播以及给广播接收器添加权限
    5. 3.5. 给Content Provider设置权限
    6. 3.6. 将权限临时赋予另一个没有权限的Activity