• ClipboardService(CBS)中的权限管理


    ClipboardService(CBS)是Android系统中的元老级服务了,自Android 1.0起就支持剪贴功能。在Android 4.0中再遇见它时,此功能已有了长足改进。本节将集中讨论CBS中的权限管理。先来回顾一下CBS中和权限管理相关的函数调用。

    //copy方设置ClipData在CBS的setPrimaryClip函数中进行:
    checkDataOwnerLocked(clip, Binder.getCallingUid());
    clearActiveOwnersLocked();
    //paste方获取ClipData在CBS的getPrimaryClip函数中进行:
    addActiveOwnerLocked(Binder.getCallingUid(), pkg);
    在分析这3个函数之前,先介绍一下Android系统中的URI权限管理。

    1. URI权限管理介绍Android系统的权限管理中有一类是专门针对URI的,先来看一个示例,该例来自package/providers/ContactsProvider,在它的AndroidManifest.xml中有如下声明:

    [-->AndroidManifest.xml]

    <provider android:name="ContactsProvider2"
             ......
              android:readPermission="android.permission.READ_CONTACTS"
              android:writePermission="android.permission.WRITE_CONTACTS">
              ......
              <grant-uri-permission android:pathPattern=".*" />
    </provider>

    这里声明了一个名为ContactsProvider2的ContentProvider,并定义了几个权限声明,下面对其进行解释。

    • readPermission:要求调用query函数的客户端必须声明一个use-permission为READ_CONTACTS的权限。
    • writePermission:要求调用update或insert函数的客户端必须声明一个use-permission为WRITE_CONTACTS的权限。
    • grant-uri-permission:和授权有关。
    writePermission:要求调用update或insert函数的客户端必须声明一个use-permission为WRITE_CONTACTS的权限。grant-uri-permission:和授权有关。

    初识grant-uri-permission时,会觉得它比较难理解,下面通过举例分析帮助读者加深认识。

    • Contacts 和ContactProvider这两个APP都是由系统提供的程序,而且二者关系紧密,所以Contacts一定会声明use_Permission为 READ_CONTACTS和WRITE_CONTACT的权限。如此,Contacts就可以毫无阻碍地通过ContactsProvider来查询或 更新数据库了。
    • 假设Contacts新增一个功能,将ContactsProvider中的某条数据复制到剪切板。根据前面已介绍过的知识可以知道,Contacts会向剪切板中复制一个URI类型的数据。
    • 另外一个程序从剪切板中粘贴(paste)这条数据,由于是URI类型的,所以此程序会通过ContentResolver来查询该uri所指向的数据。但是这个程序却并未声明READ_CONTACTS的权限,所以它查询数据时必然会失败。
    假设Contacts新增一个功能,将ContactsProvider中的某条数据复制到剪切板。根据前面已介绍过的知识可以知道,Contacts会向剪切板中复制一个URI类型的数据。另外一个程序从剪切板中粘贴(paste)这条数据,由于是URI类型的,所以此程序会通过ContentResolver来查询该uri所指向的数据。但是这个程序却并未声明READ_CONTACTS的权限,所以它查询数据时必然会失败。

    或许有人会问,为什么第三个程序不声明相应权限呢?原因很简单,第三个程序不知道自己该声明怎样的权限(除非这两个程序的开发者能互通信息)。本例 ContactsProvider设置的读权限是READ_CONTACTS,以后可能换成READ_CONTACTS_EXTEND,第三个程序不太可 能知道其中的变化。为了解决类似问题,Android提供了一套专门针对uri的权限管理机制。以这套机制解决示例中权限声明问题的方法是这样的:当第三 个程序从剪切板中粘贴数据时,系统会判断是否需要为这个程序授权。当然,系统不会随意授权,而是需要考虑ContactsProvider的情况。因为 ContactsProvider声明了grant-uri-permission,所以只要第三个程序所粘贴的URI匹配其中的 pathPattern,授权就能成功。倘若ContactsProvider没有声明grant-uri-permission,或者uri不匹配指定 的pathPattern,则授权失败。

    有了前面介绍的权限管理机制,相信下面CBS中的权限管理理解起来就比较简单了。

    提示 感兴趣的读者可阅读SDK安装目录下/docs/guide/topics/security/security.html中关于uri Permission的说明部分。

    2. checkDataOwnerLocked函数分析

    checkDataOwnerLocked函数的代码如下:

    [-->ClipboardService.java::checkDataDwnerLocked]

    private final void checkDataOwnerLocked(ClipData data, int uid) {
          //第二个参数uid为copy方进程的uid
          final int N = data.getItemCount();
          for (int i=0; i<N; i++) {
              //为每一个item调用checkItemOwnerLocked
              checkItemOwnerLocked(data.getItemAt(i), uid);
          }
    }
    // checkItemOwnerLocked函数分析
    private final void checkItemOwnerLocked(ClipData.Item item, int uid) {
          if (item.getUri() != null) {//检查uri
              checkUriOwnerLocked(item.getUri(), uid);
          }
          Intent intent = item.getIntent();
          //getData函数返回的也是一个uri,因此这里实际上检查的也是uri
          if (intent != null && intent.getData() != null) {
              checkUriOwnerLocked(intent.getData(), uid);
          }
    }
    权限检查就是针对uri的,因为uri所指向的数据可能是系统内部使用或私密的。例如Setting数据中的Secure表,这里的数据不 能随意访问。虽然直接使用ContentResolver访问这些数据时系统会进行权限检查,但是由于目前的剪切板服务也支持URI数据类型,所以这里也 需要做检查,否则恶意程序就能轻松读取私密信息。
    下边来分析checkUriOwnerLocked函数,其代码如下:

    [-->ClipboardService.java::checkUriOwnerLocked]

    private final void checkUriOwnerLocked(Uri uri, int uid) {
          ......
          long ident = Binder.clearCallingIdentity();
          boolean allowed = false;
          try {
              /*
                调用ActivityManagerService的checkGrantUriPermission函数,
                 该函数内部将检查copy方是否能被赋予URI_READ权限。如果不允许,
                 该函数会抛SecurityException异常
              
    */
              mAm.checkGrantUriPermission(uid, null, uri, 
                                             Intent.FLAG_GRANT_READ_URI_PERMISSION);
          } catch (RemoteException e) {
          } finally {
              Binder.restoreCallingIdentity(ident);
          }
      }
    根据前面的知识,这里先要检查copy方是否有读取uri的权限。下面来分析paste方的权限管理。

    3. clearActiveOwnersLocked函数分析

    clearActiveOwnersLocked函数的代码如下:

    [-->ClipboardService.java::clearActiveOwnersLocked]

    private final void addActiveOwnerLocked(int uid, String pkg) {
          PackageInfo pi;
          try {
             /*
             调用PackageManagerService的getPackageInfo函数得到相关信息
              然后做一次安全检查,如果PacakgeInfo的uid信息和当前调用的uid不一致,
              则抛出SecurityException。这个很好理解,因为paste方可以传递虚假的
              packagename,但uid是没法造假的
              
    */
              pi = mPm.getPackageInfo(pkg, 0); 
              if (pi.applicationInfo.uid != uid) {
                  throw new SecurityException("Calling uid " + uid
                          + " does not own package " + pkg);
              }
           } ......
          }
          //mActivePermissionOwners用来保存已经通过安全检查的package
          if (mPrimaryClip != null && !mActivePermissionOwners.contains(pkg)) {
              //针对ClipData中的每一个Item,都需要调用grantItemLocked来检查权限
              final int N = mPrimaryClip.getItemCount();
              for (int i=0; i<N; i++) {
                  grantItemLocked(mPrimaryClip.getItemAt(i), pkg);
              }//保存package信息到mActivePermissionOwners
              mActivePermissionOwners.add(pkg);
          }
    }
    //grantItemLocked分析
    private final void grantItemLocked(ClipData.Item item, String pkg) {
          if (item.getUri() != null) {
              grantUriLocked(item.getUri(), pkg);
          } //和copy方一样,这里仅检查uri的情况
          Intent intent = item.getIntent();
          if (intent != null && intent.getData() != null) {
              grantUriLocked(intent.getData(), pkg);
          }
    }
    再来看grantUriLocked的代码:

    [-->ClipboardService.java::grantUriLocked]

    private final void grantUriLocked(Uri uri, String pkg) {
          long ident = Binder.clearCallingIdentity();
          try {
             /*
                 调用ActivityManagerService的grantUriPermissionFromOwner函数,
                 注意第二个参数传递的是CBS所在进程的uid。该函数内部也会检查权限。
                  该函数调用成功后,paste方就被授予了对应uri的读权限
              
    */
              mAm.grantUriPermissionFromOwner(mPermissionOwner, 
                                      Process.myUid(), pkg, uri,
                                      Intent.FLAG_GRANT_READ_URI_PERMISSION);
          } catch (RemoteException e) {
          } finally {
              Binder.restoreCallingIdentity(ident);
          }
    }
    既然有授权,那么客户端使用完毕后就需要撤销授权,这个工作是在setPrimaryClip函数的 clearActiveOwnersLocked中完成的。当为剪切板设置新的ClipData时,自然需要将与旧ClipData相关的权限撤销。读者 可自行分析clearActiveOwnersLocked函数。
    ------------------------------

    本文节选自《深入理解Android:卷II》第3章“深入理解SystemServer”第3.7.3节:CBS中的权限管理。

    【内容简介】

    本 书是“深入理解Android”系列的第二本,第一本书上市后得到了广大读者的高度评价,在Android开发者社群内口口相传。本书不仅继承了第一本的 优点、改正了其在细微处存在的一些不足,而且还在写作的总体思想上进行了创新,更强调从系统设计者的角度去分析Android系统中各个模块内部的实现原 理和工作机制。从具体内容上讲,本书的重点是Android Framework的Java层,对Java层涉及的核心模块和服务进行了深入而细致的分析。通过本书,读者不仅能对Android系统本身有更深入的理 解,而且还能掌握分析大型复杂源代码的能力。

    全书共8章:第1章介绍了阅读本书所需要做的准备工作,包括Android 4.0源码的下载和编译、Eclipse环境的搭建,以及Android系统进程(system_process)的调试等;第2章对Java Binder和MessageQueue的实现进行了深入分析;第3章详细剖析了SystemServer的工作原理,这些服务包括 EntropyService、DropboxManagerService、DiskStatsService、 DeviceStorageMonitorService、SamplingProfilerService和ClipboardService;第4章 对系统中负责Package信息查询和APK安装、卸载、更新等工作的服务PackageManagerService进行了详细分析;第5章则对 Android系统中负责电源管理的核心服务 PowerManagerService的原理进行了一番深入的分析;第6章以ActivityManagerService为分析重点,对它的启动、 Activity的创建和启动、BroadcastReceiver的工作原理、Android中的进程管理等内容展开了较为深入的研究;第7章对 ContentProvider的创建和启动、SQLite、Cursor query和close的实现等进行了深入分析;第8章以ContentService和AccountManagerService为分析对象,介绍了 数据更新通知机制的实现,以及账户管理和数据同步等相关知识。

    【作者简介】

    邓凡平,资深Android开发工程师和系统工程 师,热衷于Android源代码的研究,对Android的架构设计和实现原理有非常深刻的认识和理解,应用开发经验也十分丰富。《深入理解 Android:卷I》的作者,同时也是“深入理解Andriod”系列图书的总策划。目前就职于国内领先的Android企业中科创达 (ThunderSoft),负责Android Framework的开发和维护。喜欢钻研,乐于分享,活跃于CSDN、51CTO和开源中国等专业技术社区,撰写的Android Framework源码分析的系列文章深受读者欢迎。此外,他对Linux内核、C/C++/Python相关的技术,以及高性能网络服务器和多核并行开 发等也有一定的研究。

    作者博客:http://blog.csdn.net/Innost

    【关于本书的各种网址】

    豆瓣网:http://book.douban.com/subject/11542973/
    互动网:http://product.china-pub.com/3683060
    当当网:http://product.dangdang.com/product.aspx?product_id=22840152
    卓越网:http://www.amazon.cn/dp/B008RVQMBK
    京东网:http://book.360buy.com/11056661.html

  • 相关阅读:
    人生小悟1
    对偶传播神经网络(CPN)
    对偶传播神经网络(CPN)
    学习向量量化神经网络
    学习向量量化神经网络
    自组织特征映射神经网络(SOFM)
    自组织特征映射神经网络(SOFM)
    竞争学习的基本概念和原理
    竞争学习的基本概念和原理
    人工神经网络基础概念、原理知识(补)
  • 原文地址:https://www.cnblogs.com/hzbook/p/2625292.html
Copyright © 2020-2023  润新知