`

android安全与权限,属性

 
阅读更多
介绍:
Android是一个权限分离的操作系统,每个应用以唯一的身份标识(Linux用户ID和组ID)运行。系统的不同部分也分成不同的身份。因而Linux把应用之间以及应用与系统之间相互隔离起来。

附加细粒度的安全功能是通过一个“许可”的机制,限定特定的进程能够执行指定的操作以及给予对每一个资源点对点的访问的URI许可。
安全体系结构

Android安全体系结构设计中心是没有任何一个应用程序在默认情况下可以执行对其他应用程序、操作系统或者用户有害的操作。其中包括读写用户的私有数据(例如联系人或者电子邮件),读写其他应用程序的文件,进行网络访问或者唤醒设备,等等。

       由于内核让每个应用程序运行在独立的沙盒中,应用程序必须明确的分配资源和数据。他们通过声明他们所需要的但是沙盒没有提供的权限来做这些。应用程序静态的声明他们所需要的权限,android系统在程序安装时提示用户同意它们获取这些权限。Android没有准许动态权限机制,因为它会使用户体验复杂对安全不利。

       内核独自地为彼此的沙盒应用负责。特别Dalvik虚拟机不是一个安全的边界,而且任何的应用程序都能够运行本地代码(查看Android NDK)。所有类型的应用程序——java、native和混合的——均用相同的方式置于砂箱中并且有着相同的安全等级。
应用程序签名

所有的Android应用程序(apk文件)必须使用一个开发人员掌握私钥的证书进行签名。证书用于识别应用程序的作者。该证书并不需要由证书颁发机构进行签名:它是非常宽松的,典型的Android应用程序使用自签名的证书。Android证书的目的是区分应用程序的作者。这样就可以允许操作系统授予或者拒绝应用程序使用签名级别的权限和操作系统授予或者拒绝应用程序请求和其他应用程序相同的Linux身份。
用户ID和文件访问

在安装的时候,Android给予每个程序包不同的Linux用户ID。软件包在设备上的生命周期中身份标识保持恒定不变。在不同的设备上,相同的软件包可能会有一个不同的UID;重要的是每个包都有不同的身份标识在给定的设备上。

       因为安全在进程级别上实现,两个软件包的代码不能够正常的运行在同一个进程中,因为他们需要以不同的Linux用户运行。可以使用每个程序包的AndroidManifest.xml中的manifest标签中的shareUserId属性将它们分配相同的用户ID。这样做是为了安全,把两个应用程序包看作同一个应用程序,拥有同样的用户ID和文件权限。既然为了保持安全,为了保持安全,只有具有相同签名(并请求同样的sharedUserId)的应用程序才会分配通用的用户ID。

       任何由应用程序存储的数据将被赋予应用程序的用户ID,正常情况不能被其它应用程序访问。当使用getSharedPreferences(String, int), openFileOutput(String, int), 或 openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)创建一个新的文件时,你可以使用MODE_WORLD_READABLE或MODE_WORLD_WRITEABLE标记允许任何其他应用程序来读/写入文件。当设置这些标记,该文件仍然为创建文件的应用程序所拥有,但是它全局的读写权限已经被设置,所以任何其他应用程序可以看到它。
使用权限

一个Android应用程序没有任何权限,这意味着它不能做任何会对用户体验或设备上的任何数据造成不利影响的操作。利用该设备的保护功能,必须在AndroidManifest.xmlone文件中的一个或多个<uses-permission>标签上声明应用程序所需要的权限。

       例如,一个应用程序需要监控接收短信会指定:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
</manifest>

       在应用程序安装时,应用程序所需的权限被安装者基于签名的应用程序所声明的权限交互的进行授权。应用程序运行时不会进行权限检查:它要么在安装后被给予一个特殊的权限,并且可以使用它期望的权限,要么就不被授予权限,并且任何试图使用这些权限将会失败并没有用户提示。

       通常一个请求权限的失败将导致应用程序抛出一个SecurityException异常。但是并不能够保证一定会发生。例如,sendBroadcast(Intent)方法在所有数据被投递到接收者,当方法返回后才会进行对于数据的权限检查,所以假如权限异常也不能接收到任何权限异常。几乎所有情况下,权限异常将会记录在日志中。

       将在所有Android系统提供的权限可以在Manifest.permission中找到。任何应用程序也可以定义并执行其自己的权限,所以这不是一个对于所有可能的权限的全面的清单。

任何应用程序也可以定义并执行其自己的权限:

l  当调用系统调用时,阻止应用程序执行特定的功能。

l  当启动一个Activity时,阻止应用程序启动其他应用程序的Activity。

l  在发送或接受广播时,控制谁可以接受你的广播或者谁可以向你发送广播。

l  谁可以访问或操作一个特定的内容提供者。

l  绑定或者启动一项服务。
声明和实施许可

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

例如,一个应用程序想要控制谁能够开始它的一个Activity,可以声明此操作的权限如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.me.app.myapp" >
<permission 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" />
...
</manifest>

<protectionLevel>属性是必须的,它告诉系统户当其它应用程序需要该权限或者谁可以持有该权限时怎样通知用。

<permissionGroup>属性是可选的,用于帮助系统展示的权限给用户。您通常会希望将它设置为一个标准的系统组(在android.Manifest.permission_group中)或者在更多罕见的情况下由自己进行定义。它优先使用现有的组,用于简化权限UI展示给用户。

请注意,这两个标签和描述应提供许可。用户在查看的权限列表(android:label)或单个权限( android:description)的细节时,这些内容被展现。标签应该简洁的介绍权限保护的关键功能。用几个简单的句子描述拥有该权限可以做什么。我们的惯例是用两个句子,第一句描述权限,第二句警告用户当授权该权限后会发生什么。

这里是一个CALL_PHONE权限的标签和描述的的例子:

<string name="permlab_callPhone">directly call phone numbers</string>

<string 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.</string>

可以通过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>标签)用于限制谁才可以启动相关的Activity。该权限在Context.startActivity()和Activity.startActivityForResult()期间被检查;如果调用方不具有这个必需的权限,那么将会从此次调用中抛出SecurityException。

Service许可(应用于<service>标签)用于限制谁才可以启动或绑定该service。在Context.startService() , Context.stopService()和Context.bindService()调用的时候会进行权限检查。如果调用方没有所需的权限,则会抛出一个SecurityException。

BroadcastReceiver许可(应用于<receiver>标签)用于限制谁才可以向相关的接收器发送广播。权限检查会在Context.sendBroadcast() 返回时进行,由系统去发送已经提交的广播给相应的Receiver。最终,一个permission failure不会再返回给调用方一个异常;它只是不会去实现该Intent而已。同样地,Context.registerReceiver()也可以有自己permission用于限制谁才可以向一个在程序中注册的receiver发送广播。另一种方式是,一个permission也可以提供给Context.sendBroadcast() 用以限制哪一个BroadcastReceiver才可以接收该广播。(见下文)

ContentProvider许可(应用于<provider>标签)用于限制谁才可以访问ContentProvider提供的数据。(Content providers有一套额外的安全机制叫做URI permissions,这些在稍后讨论)不像其他组件,它有两个单独的权限属性,你可以设置:android:readPermission由于限制谁才能够读,android:writePermission用于限制谁才能够写。需要注意的是如果provider同时被读写许可,如果这时只有写许可并不意味着你就可以读取provider中的数据了。当你第一次检索内容提供者时,(假如你没有任何权限时,抛出SecurityException),和当你完成操作时权限被检查。使用ContentResolver.query()需要持有读许可;使用ContentResolver.insert(),ContentResolver.update(),ContentResolver.delete()需要写许可。在所有这些情况下,没有所需的权限将会导致抛出SecurityException。
发送广播时实施许可

除了之前说过的许可(用于限制谁才可以发送广播给相应的BroadcastReceiver),你还可以在发送广播的时候指定一个许可。在调用Context.sendBroadcast()的时候使用一个permission string,你就可以要求接收器的宿主程序必须有相应的许可。

       值得注意的是接收器和广播都可以要求许可。当这种情况发生时,这两种permission检查都需要通过后才会将相应的intent发送给相关的目的地。
其他权限实施

在调用service的过程中可以设置任意细化的许可。这是通过Context.checkCallingPermission()方法来完成的。调用的时候使用一个想得到的permission string,并且当该权限获批的时候可以返回给调用方一个Integer(没有获批也会返回一个Integer)。需要注意的是这种情况只能发生在来自另一个进程的调用,通常是一个service发布的IDL接口或者是其他方式提供给其他的进程。

Android提供了很多其他有效的方法用于检查许可。如果你有另一个进程的pid,你就可以通过Context.checkPermission(String, int, int)去针对那个pid去检查许可。如果你有另一个应用程序的包名,你可以直接用PackageManager的方法PackageManager.checkPermission(String, String)来确定该包是否已经拥有了相应的权限。
URI许可

到目前为止我们讨论的标准的permission系统对于内容提供者(content provider)来说是不够的。一个内容提供者可能想保护它的读写权限,而同时与它对应的直属客户端也需要将特定的URI传递给其它应用程序,以便对该URI进行操作。一个典型的例子是邮件应用程序的附件。访问邮件需要使用permission来保护,因为这些是敏感的用户数据。然而,如果有一个指向图片附件的URI需要传递给图片浏览器,那个图片浏览器是不会有访问附件的权利的,因为它不可能拥有所有的邮件的访问权限。

针对这个问题的解决方案就是per-URI permission:当启动一个activity或者给一个activity返回结果的时候,调用方可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION。这赋予接收活动(activity)访问该意图(Intent)指定的URI的权限,而不论它是否有权限进入该意图对应的内容提供者。

这种机制允许一个通常的能力-风格(capability-style)模型,以用户交互(如打开一个附件, 从列表中选择一个联系人)来驱动细化的特别授权。这是一个很关键的能力,可以减少应用程序所需要的权限,只留下和程序行为直接相关的权限。

这些URI permission的获取需要内容提供者(包含那些URI)的配合。强烈推荐在内容提供者中实现这种能力,并通过android:grantUriPermissions或者<grant-uri-permissions>标签来声明支持。

更多的信息可以参考Context.grantUriPermission(), Context.revokeUriPermission()和Context.checkUriPermission()方法。
PID和UID:
我们经常在一个activity中去start另一个activity,或者与另一个acitivity的结果进行交互(startActivityForResult)。但有没有想过可能会出现的permission问题呢?如果你遇到了permission denial的Exception,那么你需要读读这篇文章啦。

我们在同一个application内部,可以随意的startActivity from Activity A to Activity B,而官方的文档中说startActivity可能会报NotFoundException,表示被start的Activity不存在。因此,我们很容易忽略另一个可能的Exception,Permission Denial。

当我们在不同的application中,如application A中的Activity去start一个application B中的Activity,也许你什么Exception都不会得到,也可能会直接Force Close掉。因为再Start Activity时,代码是有去检验permission的。

如下情况,可以成功startActivity而不会得到permission denial

1、同一个application下

2、Uid相同

3、permission匹配

4、目标Activity的属性Android:exported=”true”

5、目标Activity具有相应的IntentFilter,存在Action动作或其他过滤器并且没有设置exported=false

6、启动者的Pid是一个System Server的Pid

7、启动者的Uid是一个System Uid(Android规定android.system.uid=1000,具有该Uid的application,我们称之为获得Root权限)

如果上述调节,满足一条,一般即可(与其他几条不发生强制设置冲突),否则,将会得到Permission Denial的Exception而导致Force Close。

现在,我来解释一下Uid机制

众所周知,Pid是进程ID,Uid是用户ID,只是Android和计算机不一样,计算机每个用户都具有一个Uid,哪个用户start的程序,这个程序的Uid就是那个那个用户,而Android中每个程序都有一个Uid,默认情况下,Android会给每个程序分配一个普通级别互不相同的 Uid,如果用互相调用,只能是Uid相同才行,这就使得共享数据具有了一定安全性,每个软件之间是不能随意获得数据的。而同一个application 只有一个Uid,所以application下的Activity之间不存在访问权限的问题。

如果你需要做一个application,将某些服务service,provider或者activity等的数据,共享出来怎么办,三个办法。

1、完全暴露,这就是android:exported=”true”的作用,而一旦设置了intentFilter之后,exported就默认被设置为true了,除非再强制设为false。当然,对那些没有intentFilter的程序体,它的exported属性默认仍然是false,也就不能共享出去。

2、权限提示暴露,这就是为什么经常要设置usePermission的原因,如果人家设置了 android:permission=”xxx.xxx.xx”那么,你就必须在你的application的Manufest中 usepermission xxx.xxx.xx才能访问人家的东西。

3、私有暴露,假如说一个公司做了两个产品,只想这两个产品之间可互相调用,那么这个时候就必须使用shareUserID将两个软件的Uid强制设置为一样的。这种情况下必须使用具有该公司签名的签名文档才能,如果使用一个系统自带软件的ShareUID,例如Contact,那么无须第三方签名。

这种方式保护了第三方软件公司的利益于数据安全。

当然如果一个activity是又system process跑出来的,那么它就可以横行霸道,任意权限,只是你无法开发一个第三方application具有系统的Pid(系统Pid不固定),但是你完全可以开发一个具有系统Uid的程序,对系统中的所有程序任意访问,只需再Manufest中声明shareUserId为 android.system.uid即可,生成的文件也必须经过高权限签名才行,一般不具备这种审核条件的application,google不会提供给你这样的签名文件。当然你是在编译自己的系统的话,想把它作成系统软件程序,只需在Android.mk中声明 Certificate:platform则可以了,既采用系统签名。这个系统Uid的获得过程,我们把它叫做获得Root权限的过程。所以很多第三方系统管理软件就是有Root权限的软件,因为他需要对系统有任意访问的权限。那么它的Root签名则需要和编译的系统一致,例如官方的系统得用官方的签名文件,CM的系统就得用CM的签名文件。

Android中如何修改系统时间(应用程序获得系统权限)

在 android 的API中有提供 SystemClock.setCurrentTimeMillis()函数来修改系统时间,可惜无论你怎么调用这个函数都是没用的,无论模拟器还是真机,在logcat中总会得到"Unable to open alarm driver: Permission denied ".这个函数需要root权限或者运行与系统进程中才可以用。

本来以为就没有办法在应用程序这一层改系统时间了,后来在网上搜了好久,知道这个目的还是可以达到的。

第一个方法简单点,不过需要在Android系统源码的环境下用make来编译:

1. 在应用程序的AndroidManifest.xml中的manifest节点中加入

android:sharedUserId="android.uid.system"这个属性。

2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform这一行

3. 使用mm命令来编译,生成的apk就有修改系统时间的权限了。

第二个方法麻烦点,不过不用开虚拟机跑到源码环境下用make来编译:

1. 同上,加入android:sharedUserId="android.uid.system"这个属性。

2. 使用eclipse编译出apk文件,但是这个apk文件是不能用的。

3. 用压缩软件打开apk文件,删掉META-INF目录下的CERT.SF和CERT.RSA两个文件。

4. 使用目标系统的platform密钥来重新给apk文件签名。这步比较麻烦,

首先找到密钥文件,在我的Android源码目录中的位置

是"build argetproductsecurity",下面的platform.pk8和platform.x509.pem

两个文件。

然后用Android提供的Signapk工具来签名,signapk的源代码是

在"build oolssignapk"下,

用法为"signapk platform.x509.pem platform.pk8 input.apk output.apk",

文件名最好使用绝对路径防止找不到,也可以修改源代码直接使用。

这样最后得到的apk和第一个方法是一样的。

最后解释一下原理,首先加入android:sharedUserId="android.uid.system"这个属性。通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中。那么把程序的UID配成android.uid.system,也就是要让程序运行在系统进程中,这样就有权限来修改系统时间了。

只是加入UID还不够,如果这时候安装APK的话发现无法安装,提示签名不符,原因是程序想要运行在系统进程中还要有目标系统的platform key,就是上面第二个方法提到的platform.pk8和platform.x509.pem两个文件。用这两个key签名后apk才真正可以放入系统进程中。第一个方法中加入LOCAL_CERTIFICATE := platform其实就是用这两个key来签名。

这也有一个问题,就是这样生成的程序只有在原始的Android系统或者是自己编译的系统中才可以用,因为这样的系统才可以拿到 platform.pk8和platform.x509.pem两个文件。要是别家公司做的Android上连安装都安装不了。试试原始的Android 中的key来签名,程序在模拟器上运行OK,不过放到G3上安装直接提示"Package ... has no signatures that match those in shared user android.uid.system",这样也是保护了系统的安全。

最最后还说下,这个android:sharedUserId属性不只可以把apk放到系统进程中,也可以配置多个APK运行在一个进程中,这样可以共享数据。

属性系统是android的一个重要特性。它作为一个服务运行,管理系统配置和状态。所有这些配置和状态都是属性。每个属性是一个键值对(key/value pair),其类型都是字符串。

         从功能上看,属性与windows系统的注册表非常相似。许多android应用程序和库直接或者间接地依赖此特性,以决定它们的运行时行为。例如,adbd进程查询属性服务已确认当前是否运行在模拟器环境中。另一个例子是java.io.File.pathSpearator,其返回存储于属性服务中的值。

属性系统是如何工作的

         属性系统的上层架构如下图所示。
图中有3个进程、一组永久属性文件和一块共享内存区域。共享内存区域是所有属性记录的存储所在。只有属性服务进程才可以写入共享内存区域,它负责从永久文件中加载属性记录并将它们保存在共享内存中。
consumer进程将共享内存加载到其自身的虚拟地址空间并直接访问这些属性。setter进程同样将共享内存加载到其自身的虚拟地址空间,但其不能直接写该内存。当setter试图增加或者更新一个属性时,它将该属性通过unix domain socket发送至属性服务。属性服务代表setter进程将该属性写入共享内存和永久文件中。(疑问1.如何将共享内存加载到其自身的虚拟地址;2.setter进程为什么要将共享内存加载到其自身的虚拟地址)
属性服务运行于init进程中。init进程首先创建一个共享内存区域,并保存一个指向该区域的描述符fd。init进程将该区域通过使用了MAP_SHARED标志的mmap映射至它自身的虚拟地址空间,这样,任何对于该区域的更新对于所有进程都是可见的。fd和区域大小被存储在一个名为ANDROID_PROPERTY_WORKSPACE的变量中。任何其他进程,比如consumer和setter将使用这个变量来获得fd和尺寸,这样它们就能mmap这个区域到它们自身的虚拟地址空间中。该共享内存区域如下图所示。

在这之后,init进程将从下列文件加载属性:

/default.prop
/system/build.prop
/system/default.prop
/data/local.prop

       下一步是启动属性服务。在这一步中,一个unix domain socket服务被创建。此socket的路径是/dev/socket/property_service,该路径对于其他客户端进程是熟知的。最后,init进程调用poll来等待该socket上的连接事件。

在consumer一边,当它初始化libc(bionic/libc/bionic/libc_common.c__libc_init_common 函数),它将从环境变量中返回fd和尺寸,并映射共享内存到其自身的地址空间(bionic/libc/bionic/system_properties.c__system_properties_init 函数)。在这之后,libcutils可以想读取普通内存那样为consumer读取属性。

         目前,属性是不能够被删除的。也就是说,一旦添加了一个属性,它将不能够被删除,其键也不能够被改变。

如何读取/设置属性

         Android上有三种主要途径来get/set属性。

1、  native code

当编写本地应用程序时,可以使用property_get和property_set 这两个API来读取/设置属性。要使用它们,我们需要include cutils/properties.h,并链接libcutils库。

2、  java code

在Java包(java.lang.System)中提供有System.getProperty和System.setProperty方法。但值得注意的是,尽管这两个API在语义上等同native函数,但其将数据存储于完全不同的位置。实际上,dalvik VM使用一个哈希表来存储这些属性。所以,用这两个API存储的属性是独立的,不能存取native属性,反之亦然。

然而Android有一个内部隐藏类(@hide,对SDK不可见)android.os.SystemProperties来操纵native属性。其通过jni来存取native属性库。

3、  shell脚本

Android提供getprop和setprop命令行工具来获取和更新属性。其依赖libcutils实现。

getprop <属性名>
setprop <属性名><<属性值>

特别属性
如果属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变。
如果属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property。
如果属性名称以“net.”开头,当设置这个属性时,“net.change”属性将会自动设置,以加入到最后修改的属性名。(这是很巧妙的。netresolve模块的使用这个属性来追踪在net.*属性上的任何变化。)
属性“ctrl.start ”和“ctrl.stop ”是用来启动和停止服务。每一项服务必须在/init.rc中定义.系统启动时,与init守护进程将解析init.rc和启动属性服务。一旦收到设置“ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“init.svc.<服务名>“属性中 。客户端应用程序可以轮询那个属性值,以确定结果。

补充:通过查看property_service.c,我们可以明确以下事实:
1、  属性名不是随意取的。在property_perms数组中定义了当前系统上可用的所有属性的前缀,以及相对应的存取权限UID。对属性的设置要满足权限要求,同时命名也要在这些定义的范围内。
2、  PA_COUNT_MAX指定了系统(共享内存区域中)最多能存储多少个属性。
3、  PROP_NAME_MAX指定了一个属性的key最大允许长度;PROP_VALUE_MAX则指定了value的最大允许长度。
此外,http://blog.csdn.net/tekkamanita ... /06/18/4280982.aspx 这篇文章翻译了Android的官方文档,从另一个角度叙述了属性系统,需要者请参看。

4、设置key的value时,需要作鉴权,根据设置程序所在进程的fd获知uid值,比如system server进程可以设置net打头的key,不可以设置gsm打头的key,相关的定义如下:
5、Android 的系统属性包括两部分:文件保存的持久属性和每次开机导入的cache属性。(cache属性也可以理解为持久属性,比如在开机初始化程序时调用setprop <property_name> <property_value>);在程序里设置的属性应该叫temp属性(自己理解),因为是保存在内存中,所以每次开机时会被清空。

android系统属性的命名方式:
创建与修改android属性用Systemproperties.set(name,value),获取android属性用Systemproperties.get(name),需要注意的是android属性的名称是有一定的格式要求的,如下: 前缀必须用system\core\init\property_service.c中定义的前缀 ,进行系统属性设置的程序也必须有相应的进程权限,
如何将android程序的权限提升到system权限?方法是这样的:
1、在AndroidManifest.xml中,在manifest加入android:sharedUserId="android.uid.system "。
2、在Android.mk中,將LOCAL_CERTIFICATE:= XXX修改成LOCAL_CERTIFICATE := platform 。
经过以上两步就可以把ap的权限提升到system权限了。 但是用这种方法提升权限有两个弊端,如下:
1、程序的拥有都必须有程序的源码;
2、程序的拥有都还必须有android开发环境,就是说自己能make整个android系统。
---------

我改的是Contacts,加入权限后,发现明显的有两个问题1.启动SynSimService的时候说without permission private to package,没搞明白;2.读取数据库的时候发生异常,刚开始怀疑是 Contacts改到system进程,而ContactsProvider还是com.uid.shared进程,随将ContactsProvider改为com.uid.system,结果情况依旧,提示:
01-0100:15:10.270: ERROR/DatabaseUtils(1319): Writing exception to parcel
01-0100:15:10.270: ERROR/DatabaseUtils(1319):java.lang.UnsupportedOperationException: Only CrossProcessCursor cursors aresupported across process for now
01-0100:15:10.270: ERROR/DatabaseUtils(1319):    atandroid.database.CursorToBulkCursorAdaptor.<init>(CursorToBulkCursorAdaptor.java:97)
01-0100:15:10.270: ERROR/DatabaseUtils(1319):    atandroid.content.ContentProvider$Transport.bulkQuery(ContentProvider.java:155)
01-0100:15:10.270: ERROR/DatabaseUtils(1319):    atandroid.content.ContentProviderNative.onTransact(ContentProviderNative.java:111)
01-0100:15:10.270: ERROR/DatabaseUtils(1319):    at android.os.Binder.execTransact(Binder.java:288)
01-0100:15:10.270: ERROR/DatabaseUtils(1319):    at dalvik.system.NativeStart.run(Native Method)
01-0100:15:10.270: ERROR/DatabaseUtils(1319): Caused by:java.lang.ClassCastException:com.android.providers.contacts.ContactsProvider2$3
01-0100:15:10.270: ERROR/DatabaseUtils(1319):    atandroid.database.CursorToBulkCursorAdaptor.<init>(CursorToBulkCursorAdaptor.java:81)
01-0100:15:10.270: ERROR/DatabaseUtils(1319):    ... 4 more
01-0100:15:10.280: WARN/AsyncQuery(1311): java.lang.UnsupportedOperationException:Only CrossProcessCursor cursors are supported across process for now
出这个错误的原因是由于只要你用如下代码:
uri=buildSectionIndexerUri(Contacts.CONTENT_URI);
uri.buildUpon().appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
加一个这样到查询参数(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true")
就会走到ContactsProvider2.java 中的bundleLetterCountExtras方法:
    /**
     * Computes counts by the address book index titles and adds the resulting tally
     * to the returned cursor as a bundle of extras.
     */
    private Cursor bundleLetterCountExtras(Cursor cursor, final SQLiteDatabase db,
            SQLiteQueryBuilder qb, String selection, String[] selectionArgs, String sortOrder) {
        String sortKey;

        // The sort order suffix could be something like "DESC".
        // We want to preserve it in the query even though we will change
        // the sort column itself.
        String sortOrderSuffix = "";
        if (sortOrder != null) {
            int spaceIndex = sortOrder.indexOf(' ');
            if (spaceIndex != -1) {
                sortKey = sortOrder.substring(0, spaceIndex);
                sortOrderSuffix = sortOrder.substring(spaceIndex);
            } else {
                sortKey = sortOrder;
            }
        } else {
            sortKey = Contacts.SORT_KEY_PRIMARY;
        }

        String locale = getLocale().toString();
        HashMap<String, String> projectionMap = Maps.newHashMap();
        projectionMap.put(AddressBookIndexQuery.LETTER,
                "SUBSTR(" + sortKey + ",1,1) AS " + AddressBookIndexQuery.LETTER);

        /**
         * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3,
         * to map the first letter of the sort key to a character that is traditionally
         * used in phonebooks to represent that letter.  For example, in Korean it will
         * be the first consonant in the letter; for Japanese it will be Hiragana rather
         * than Katakana.
         */
        projectionMap.put(AddressBookIndexQuery.TITLE,
                "GET_PHONEBOOK_INDEX(SUBSTR(" + sortKey + ",1,1),'" + locale + "')"
                        + " AS " + AddressBookIndexQuery.TITLE);
        projectionMap.put(AddressBookIndexQuery.COUNT,
                "COUNT(" + Contacts._ID + ") AS " + AddressBookIndexQuery.COUNT);
        qb.setProjectionMap(projectionMap);

        Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs,
                AddressBookIndexQuery.ORDER_BY, null /* having */,
                AddressBookIndexQuery.ORDER_BY + sortOrderSuffix);

        try {
            int groupCount = indexCursor.getCount();
            String titles[] = new String[groupCount];
            int counts[] = new int[groupCount];
            int indexCount = 0;
            String currentTitle = null;

            // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up
            // with multiple entries for the same title.  The following code
            // collapses those duplicates.
            for (int i = 0; i < groupCount; i++) {
                indexCursor.moveToNext();
                String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE);
                int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT);
                if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) {
                    titles[indexCount] = currentTitle = title;
                    counts[indexCount] = count;
                    indexCount++;
                } else {
                    counts[indexCount - 1] += count;
                }
            }

            if (indexCount < groupCount) {
                String[] newTitles = new String[indexCount];
                System.arraycopy(titles, 0, newTitles, 0, indexCount);
                titles = newTitles;

                int[] newCounts = new int[indexCount];
                System.arraycopy(counts, 0, newCounts, 0, indexCount);
                counts = newCounts;
            }

            final Bundle bundle = new Bundle();
            bundle.putStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles);
            bundle.putIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts);
            return new CursorWrapper(cursor) {

                @Override
                public Bundle getExtras() {
                    return bundle;
                }
            };
        } finally {
            indexCursor.close();
        }
    }
给你返回个CursorWrapper,而当Contacts作为非系统应用运行就和ContactsProvider的访问跨进程了,所以在2.2以上跨进程的Cursor为CrossProcessCurss,其中interface CrossProcessCursor extends Cursor,CursorWrapper直接实现了Cursor接口而非CrossProcessCursor 这样当然就会报类型强转错误了。
分享到:
评论

相关推荐

    Android权限管理之Permission权限机制及使用详解

    前言: 最近突然喜欢上一句诗...权限是一种安全机制。Android权限主要用于限制应用程序内部某些具有限制性特性的功能使用以及应用程序之间的组件访问。 Android权限列表: 访问登记属性 android.permission.ACCES

    Android高级编程--源代码

    11.1 Android的安全性 353 11.1.1 Linux内核安全 354 11.1.2 权限简介 354 11.1.3 声明和实施权限 354 11.1.4 为广播Intent实施权限 355 11.2 使用AIDL来支持服务IPC 355 11.3 使用Internet服务 360 11.4 ...

    《Android高级编程》

    11.1 Android的安全性 11.1.1 Linux内核安全 11.1.2 权限简介 11.1.3 声明和实施权限 11.1.4 为广播Intent实施权限 11.2 使用AIDL来支持服务IPC 11.3 使用Internet服务 11.4 构建内容丰富的用户界面 11.4.1 使用动画...

    新版Android开发教程.rar

    与 Android Market 联机;支持谷歌 “ 街景 ” 服务;包装盒内附 数据工具包。 更多信息 https://sites.google.com/a/android.com/opensource/release-features Android Android Android Android 盈利模式 Android ...

    PdfViewer:基于pdf.js和内容提供商的简单Android PDF查看器。 该应用程序不需要任何权限。 PDF流被馈送到沙盒WebView中,而没有访问内容或文件的权限。 CSP用于强制WebView中JavaScript和样式属性是完全静态的

    PDF渲染代码本身是内存安全的,并且禁用了动态代码评估,即使攻击者通过利用底层的Web渲染引擎获得了代码执行权限,它们也位于Chromium渲染器沙箱中,无法访问网络(与浏览器不同) ,文件或其他内容。

    Android高级编程.pdf

    11.1 Android的安全性 11.1.1 Linux内核安全 11.1.2 权限简介 11.1.3 声明和实施权限 11.1.4 为广播Intent实施权限 11.2 使用AIDL来支持服务IPC 11.3 使用Internet服务 11.4 构建内容丰富的用户界面 11.4.1 使用...

    android 面试2

    请解释下Android程序运行时权限与文件系统权限的区别。  13. 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?请说明原由。  14. 有一个一维整型数组int[]data保存的是一张宽为width,高为height的图片...

    基于朴素贝叶斯的Android软件恶意行为智能识别 (2015年)

    抽取软件是否为系统应用、权限使用时是否有用户操作、软件是否申请了过多的权限、是否存在敏感权限组合、权限的使用是否存在突发性等作为分类属性,并通过对Android安全框架的扩展,实现了对恶意行为的实时分析和处理....

    SELinux介绍.pdf

    SELinux是一套完整的安全策略,最开始是美国国家安全局和一些公司联合设计为了针对Linux系统的安全隐患而产生的一套系统,它为每一个进程,每一个文件,每一个属性都定义了标签,用来控制进程对文件的操作的权限控制...

    Android 中Manifest.xml文件详解

    它还提供了各种属性来详细地说明应用程序的元数据(如它的图标或者主题)以及额外的可用来进行安全设置和单元测试顶级节点,如下所述。 清单由一个根manifest标签构成,该标签带有一个设置项目包的pa

    adb1.0.26包含fastboot.exe

    注:有部分命令的支持情况可能与 Android 系统版本及定制 ROM 的实现有关。 基本用法 命令语法 adb 命令的基本语法如下: adb [-d|-e|-s ] 如果只有一个设备/模拟器连接时,可以省略掉 [-d|-e|-s ] 这一部分,...

    安卓移动开发项目大作业图书管理系统源代码报告

    本系统使用Android Studio作为开发工具进行开发,以SQLite建立系统的后台数据库储存相关数据,使用MVC模式进行系统的设计与开发。 本系统含有以下功能: 1、修改密码功能 2、忘记密码功能 3、查看图书功能 图书展示...

    techtranslate:技术文章翻译

    Android安全性: 欢迎来到Shell(权限) Android原生支持Java8的Lambdas表达式 使用Gradle额外属性管理Android依赖版本 异步布局加载 Keeping Android runtime permissions from cluttering your app (Headless Dialog ...

    【05-面向对象(下)】

    •对于类属性而言,要么在静态初始化中初始化,要么在声明该属性时初始化。 •对于实例属性,要么在普通初始化块中指定初始值。要么在定义时、或构造器中指定初始值。 final修饰局部变量 •使用final修饰...

    Countly移动分析应用-其他

    借助于Javascript SDK,Countly是一个Web分析平台,其功能与移动SDK相当。 Countly有两个部分:收集和分析数据的服务器,以及发送此数据的SDK(移动,Web或桌面)。该存储库包括Countly Community Edition(服务器端...

    记事狗微博系统最新官方版

    这是记事狗微博系统最新官方版,记事狗微博系统,是一套创新的PHP开源微博程序,兼有BBS和轻博系统特性,支持短信、手机客户端,可与新浪微博平台内容互通,既可用来独立建站也可通过Ucenter与已有网站整合,通过...

    记事狗微博系统 v4.0.5 Build20130510

    整个V3.5版本从数据库结构、代码规范完善、系统负载性能、后台安全管理、信息导航架构、注册认证体系、内容审核管理、用户关系挖掘、多客户端接入、应用功能扩展等十多个方面做了全面改进提高! 更新说明: 记事狗...

    CKplayer-超酷网页视频播放器

    ckplayer是一种前台使用的程序,不涉及到服务器程序(asp,php,jsp,.net),也不涉及到对服务器的操作(即不需要写入权限),所以不存在安全方面的问题。同时可以集成在任何程序中,包括asp,php,jsp,.net以及其它支持...

    JAVA上百实例源码以及开源项目

    此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这...

Global site tag (gtag.js) - Google Analytics