下一代开放操作系统的主流将不会在桌面上,但是将会出现在我们每天携带的手机上。这些开放性的环境将会带领这些新的应用可能集成这些已经存在的在线服务,当然随着日以具增的数据与服务在手机上的支持,手机上的安全缺陷也越发明显。下一代操作系统本质在于是否提供一个完整综合的安全平台。
由开放手机联盟(open Handset Alliance 谷歌领导)所开发的android 系统是一个被广泛看好的一个手机开源系统,该系统提供一个基本的操作系统,一个中间件应用层,一个java开发工具和一个系统应用收集器(collection of system applications)。尽管android SDK自2007年就发布了,但是第一部android 手机却在2008年10月才诞生。自从这时起谷歌开起了自己的时代,T-Mobile的G1的制造商台湾 HTC估算G1的发货量在2008年底已经超过100万部。据业内人士预期该G1手机的销量将会在2009年继续保持。不久的将来其他许多手机供应商要计划支持这个系统。
一个围绕android庞大的开发者社区已经建立,同时很多新的产品和应用已经可以在android上使用。一个Android的主要卖点是它使开发人员无缝把在线服务扩展到手机。这方面最明显的例子是谷歌的紧密集成Gmail,日历和联系人Web应用程序通过该系统。用户只需提供一个android用户名和密码,其手机自动同步与谷歌的服务。其他厂商正在迅速适应自己的现有的即时通讯,社交网络和游戏服务。Android和许多企业寻找新途径来整合他们的自己已有的业务到android上。
传统的台式机和服务器的操作系统一直在努力进行安全功能的集成。这些个人和商业应用在单一平台的很出色,然而这一块业务一个手机平台上像android上不是很有用。它给了许多研究人员希望。Android没有停在为其他平台体用应用支持:应用的执行依赖于顶层JAVA中间件,这个中间件运行在嵌入式Linux 内核之上。所以开发人员要把他们的应用部署到Android必须使用其自定义的用户界面环境。
此外,android系统应用限制各应用相互调用API协作,并且对方为自己的用户应用进行身份验证。尽管这些应用有一定的安全特性,我们一些有经验的开发人员开发android应用人士透露,设计安全应用程序并不总是直线前进的。Android使用一个简单的许可标签分配模式限制访问的资源,但其他应用程序的原因必要性和便利,其设计师们增加了困惑对这个系统。本文试图对Android的安全的复杂性进行讲解,并注意一些可能的发展缺陷以及应用程序的安全。我们通过尝试得出一些经验教训,希望对未来的安全有用。
Android应用程序框架对开发者来说是一个强制架构。它没有一个main()函数功能或单一入口点执行,相反,开发人员必须在设计方面的应用组件。我们开发的应用对android的sdk的帮助的API
Android系统定义了4种组件类型。
Activity 组件定义应用程序的用户界面。通常,应用程序开发者定义每一个活动“画面。”Activity可以自己开始,也可能通过传递和返回值。在一时间只有一个键盘的系统Activity可以进行处理,在这个时候所有其他的Activity都会被暂停。
Service组件执行后台处理。当一个活动需要进行一些操作,在用户界面消失以后(如下载一个文件或播放音乐),它通常采取此种动作特殊设计的服务。开发人员还可以在系统启动使用特殊的守护进程,Service通常定义一个远程过程调用(RPC),其他系统组件可以用来传送接口命令和检索数据,以及注册一个回调函数。
ContentProvider组件存储和共享数据 用关系数据库接口。每个Content供应者都有一个关联的“权限”来形容它的内容包含。其他组件使用时作为一个handle执行SQL查询(如SELECT,INSERT或DELETE内容。虽然Content供应者通常存储把数值放在数据库记录中,数据检索是实现特殊的例子,文件也同时通过内容提供商共享接口。
Broadcast receiver该组件作为为从邮件信箱发送信息给他应用程序。通常,广播消息的应用程序代码隐含的目的地。因此,广播接收器订阅这些目的地接收发送给它的消息。应用程序代码也可以解决明确广播接收机包括命名空间分配。
Component Interaction该组件交互的主要机制是一个intent ,这是一个简单的消息对象,其中包含一个目的地组件的地址和数据。 Android的API定义了他的方法中传入intent ,并使用该信息来启动一个activity例如开始一个activity(startActivity(intent)),启动服务(startService(intent))和广播信息(sendBroadcast(intent))。Android框架来通知这些方法的调用开始执行在目标应用程序代码。这个过程中内部组件通信称为一个动作。简单地说, Intent对象定义的“Intent”以执行“action”。Android的一个最强大的特点是允许的多种intent寻址机制。开发人员可以解决一个目标组件使用其应用的空间,他们也可以指定一个隐含的名称。在后一种情况下,系统决定了一个action的最佳组件,通过考虑安装的应用程序和用户的选择 。
这个隐含的名字被称为动作字符串因为他特殊的类型的请求动作。例如一个view动作字符串,在一个intent中和数据域指向一个图像文件,系统将会直接指首选图像浏览器。
开发者也能使用动作字符串进行大量广播发送和接收。在接收端的接收者,开发者使用一intent 过滤器来定制特殊的动作字符串。Android系包括附加目标的决议规则,但可选的数据操作字符串类型是最常见的。
Android应用程序使用Java编程语言开发。apt工具吧编译后的Java代码连同应用程序所需的其他数据和资源文件一起打包到一个Android包文件中,这个文件使用.apk作为扩展名。此文件是分发并安装应用程序到移动设备的载体;是用户下载到他们的设备的文件。单一.apk文件中的所有代码被认为是一个应用程序。
从多个角度来看,每个Android应用程序都存在于它自己的世界之中:
1. 默认情况下,每个应用程序均运行于它自己的Linux进程中。当应用程序中的任何代码需要被执行时,Android启动此进程,而当不再需要此进程并且其它应用程序又请求系统资源时,则关闭这个进程。
2. 每个进程都有其独有的虚拟机(VM),所以应用程序代码与其它应用程序代码是隔离运行的。
3. 默认情况下,每个应用程序均被赋予一个唯一的Linux用户ID,并加以权限设置,使得应用程序的文件仅对此用户及此应用程序可见—尽管也有其它的方法使得这些文件同样能为其他应用程序访问。
1.应用程序组件
Android的一个核心特性就是一个应用程序可以使用其它应用程序的元素(如果那个应用程序允许的话)。例如,如果你的应用程序需要显示一个图片卷动列表,而另一个应用程序已经开发了一个合用的而又允许别的应用程序使用的话,你可以直接调用那个卷动列表来完成工作,而不用自己再开发一个。你的应用程序并没有吸纳或链接其它应用程序的代码。它只是在有需求的时候启动了其它应用程序的那个功能部分。
为达到这个目的,系统必须能够在一个应用程序的任何一部分被需要时启动一个此应用程序的进程,并将那个部分的Java对象实例化。因此,不像其它大多数系统上的应用程序,Android应用程序并没有为应用程序提供一个单独的入口点(比如说,没有main()函数),而是为系统提供了可以实例化和运行所需要的必备组件。一共四种组件类型:
(1)Activity
Activity是为用户操作而展示的可视化用户界面。例如,一个activity可以展示一个菜单项列表供用户选择,接着显示一些包含说明文字的照片。一个短消息应用程序可以包括一个用于显示要发送消息到的联系人列表的activity,一个给选定的联系人写短信的activity以及翻阅以前的短信或改变设置的其他activity。尽管它们一起组成了一个内聚的用户界面,但其中每个activity都不与其它的保持独立。每一个都实现为以Activity类为基类的子类。
一个应用程序可以只有一个activity,或者,如刚才提到的短信应用程序那样,包含很多个。每个activity的作用,以及有多少个activity,当然是取决于应用程序及其设计的。一般情况下,总有一个应用程序被标记为用户在应用程序启动的时候第一个看到的。从一个activity转向另一个activity靠的是用当前的activity启动下一个。
每个activity都被给予一个默认的窗口以进行绘制。一般情况下,这个窗口是满屏的,但它也可以是一个小的位于其它窗口之上的浮动窗口。一个activity也可以使用附加窗口—例如,一个在activity运行过程中弹出的供用户响应的对话框,或是一个当用户选择了屏幕上特定项目后显示的必要信息的窗口。
窗口显示的可视内容是由一系列层次化view构成的,这些view均继承自View基类。每个view均控制着窗口中一块特定的矩形区域中进行绘制,并对用户直达其区域的操作做出响应。因此,view是activity与用户进行交互的界面。例如,view可以显示一个小图片,并在用户指定它的时候产生动作。Android有一些预置的view供开发者使用—包括按钮、文本域、滚动条、菜单项、复选框等等。
view层次结构是由Activity.setContentView()方法放入activity的窗口之中的。content view是位于层次结构根位置的View对象。(参见独立的用户界面文档以读取关于view及层次结构的更多信息。)
2.Service
Service没有可视化的用户界面,而是在一段时间内在后台运行,例如,一个service可以在用户做其它事情的时候在后台播放背景音乐、从网络上获取数据或者计算一些东西并提供给需要这个运算结果的activity使用。每个service都继承自Service基类。
一个媒体播放器播放列表中的曲目是一个不错的例子。播放器应用程序可能有一个或多个activity来给用户选择歌曲并进行播放。然而,音乐播放这个任务本身应该由任何activity来处理,因为用户期望即使在他们离开播放器应用程序而开始做别的事情时,音乐仍在继续播放。为达到这个目的,媒体播放器activity可以启动一个运行于后台的service。系统将在这个activity不再显示于屏幕后,仍维持音乐播放service的运行。
连接至(绑定到)一个正在运行的service(如果service没有运行,则启动之)是可能的。连接之后,你可以通过那个service暴露出来的接口不service进行通讯。对于音乐service来说,这个接口可以允许用户暂停、回退、停止以及重新开始播放。
如同activity和其它组件一样,service运行于应用程序进程的主线程内。所以它不会对其他组价或用户界面有任何妨碍,它们一般会派生一个新线程来执行一些时间消耗型任务(比如音乐回放)。参见稍后的进程和线程。
(1)Broadcast receiver
Broadcast receiver是一个与注于接收广播通知信息,并做出相应处理的组件。许多广播是由系统代码产生的—例如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以发起广播—例如,通知其它应用程序一些数据已经下载到设备上处于可用状态。
一个应用程序可以拥有任意数量的broadcast receiver,以对所有它认为重要的通知信息予以响应。所有的receiver均继承自Broadcast Receiver基类。
Broadcast receiver没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者也可以使用NotificationManager来通知用户。通知可以用多种方式来吸引用户的注意力—闪动背光灯、震动设备、播放声音等等。通知一般是在状态栏上放一个持丽的图标,用户可以打开它并获取消息。
(2)Content provider
Content provider将一些特定的应用程序数据供给其它应用程序使用。数据可以存储于文件系统、SQLite数据库或者其它有意义的方式。content provider继承于ContentProvider基类,实现了一套使得其他应用程序能够检索和存储它所管理的类型数据的标准方法。然而,应用程序并不直接调用返回这些方法,而是使用一个ContentResolvert对象,调用它的方法作为替代。ContentResolver可以与任何content provider进行会话;与其合作对任何相关的进程间通讯进行管理。
参阅独立的Content Providers文档以获得更多关于使用content provider的信息。
每当出现一个需要被特定组件处理的请求时,Android会确保那个组件的应用程序进程处于运行状态,必要时会启动它,并确保那个组件的一个合适的实例可用,必要时会创建那个实例。
1.1激活组件:intent
当接收到ContentResolver发出的请求后,content provider被激活。而其它三种组件—activity、service和broadcast receiver,被一种叫做intent的异步消息所激活。intent是一个保存着消息内容的Intent对象:对于activity和service来说,它指明了所请求的操作名称,并指定了用来操作的数据的URI和其它一些信息。例如,它可以承载一个对一个activity的请求,让它为用户显示一张图片,或者让用户编辑一些文本。而对于broadcast receiver来说,Intent对象指明了所通报的操作。例如,它可以对所有感兴趣的对象通报照相按钮被按下。
对于每种组件来说,激活的方法是不同的:
1.通过传递—IntentContext.setActivity()Activity.startActivityForResult(以启动(或指定新工作给)一个activity。相应的activity可以通过调用自身的getIntent()方法来查看最新激活它的intent。Android通过调用activity的onNewIntent()方法来传递给它随后的任何intent。)
一个activity经常启动另一个activity。如果它期望它所启动的那个activity返回一个结果,它会调用startActivityForResult()而不是startActivity()。例如,如果它所启动了另外一个activity以使用户挑选一张照片,它也许想知道哪张照片被选中了。其结果将会被封装在一个Intent对象中,并传递给发出调用的activity的onActivityResult()方法。
2.通过传递一个Intent对象至Context.startService()以启动一个service(或向正在运行的service给出一个新的指令)。Android调用此service的onStart()方法并将Intent对象传递给它。
与此类似,一个intent可以被传递给Context.bindService()以建立一个处于调用组件和目标service之间的活动连接。此service会通过onBind()方法的调用来获取此Intent对象(如果此service尚未运行,bindService()会先启动它)。例如,一个activity可以建立一个不前述的音乐回放service的连接,这样它就可以提供给用户一些途径(用户界面)来控制回放。这个activity可以调用bindService()来建立此连接,然后调用service中定义的方法来控制回放。
稍后的远程方法调用一节有关于如何绑定至一个service的更多细节。
3.应用程序可以通过传递一个Intent对象至Context.sendBroadcast(),Context.sendOrderedBroadcast(),以及Context,sendStickyBroadcast()和其它类似方法来发起一个广播。Android会调用所有对此广播有兴趣的broadcast receiver的onReceive()方法,将此intent传递给它们。
1.2关闭组件
content provider仅在响应来自ContentResolver的请求时处于活动状态。而broadcast receiver仅在响应一条广播信息的时候处于活动状态。所以没有必要去显示地关闭返回这些组件。
而activity则不同,它提供了用户界面:只要会话依然持续,无论会话过程有无空闲,activity同用户进行长时间会话且可能一直处于活动状态。与此相似,service也会很长一段时间内保持运行。所以Android为关闭activity和service提供了一系列有序的方法。
Activity可以通过调用自身的finish()方法来关闭。一个activity可以通过调用finishActivity()方法来关闭另外一个activity(它用startActivityForResult()启动的)。
Service可以通过调用自身的stopSelf()方法,或调用Context.stopService()来停止。
系统也会在组件不再被使用的时候或者当Android必须为更多的活动组件回收内存时关闭它。稍后的组件的生命周期一节,将对返种可能性及结果进行更详细的讨论。
1.3 manifest文件
当Android启动一个应用程序组件之前,它必须知道那个组件是存在的。因此,应用程序会在一个被打包到Android包中的manifest文件中声明它的组件,.apk文件还将涵括应用程序的代码、文件以及其他资源。
Manifest文件时一个结构化的XML文件,而对于所有应用程序,文件名总是AndroidManifest.xml。除了声明此应用程序各个组件,它会做很多其他工作,比如指明应用程序所需连接到的库的名称(除了默认的Android库之外)以及标出应用程序期望获得的各种权限。
但manifest文件最重要的任务是向Android报告此应用程序的各个组件。举例说明,一个activity可能声明如下:
<activity>元素的name属性指定了实现此activity的Activity子类。icon和label属性指向包含展示给用户的此activity的图标和标签的资源文件。
其它组件也以类似的方法声明—<service>元素用于声明service,<receiver>元素用于声明broadcast receiver,而<provider>元素用于声明content provider。未在manifest文件中进行声明的activity、service以及content provider将不为系统所见,从而也就永不会被运行。然而,broadcast receiver既可以在manifest文件中声明,也可以在代码中动态创建(为BroadcastReceiver对象),并以调用Context.registerReceiver()的方式注册至系统。
1.4 Intent过滤器
一个Intent对象可以显式地指定一个目标组件。如果进行了返种指定,Android会找到这个组件(基于manifest文件中的声明)并激活它。但如果intent没有显式的指定一个目标,Android就必须找到合适的组件来响应此intent。这个过程是通过比较Intent对象和所有潜在目标的int扭头过滤器完成的。组件的intent过滤器会通知Android它所能处理的intent类型。如同组件的其它必要信息一样,这些intent过滤器是在manifest文件中进行声明的。返里有一个对先前例子的扩展,其中加入了针对activity的两个intent过滤器:
示例中的第一个过滤器—action"android.intent.action.MAIN"和category"android.intent.category.LAUNCHER"的组合—是常见的一个。它标明了此activity应该在应用程序启动其中显示,就是用户在屏幕上看到的此设备上可供启动的应用程序的列表。换句话说,这个activity是应用程序的入口点,是用户在启动器中选择运行这个应用程序后所见到的第一个activity。