1 Android 安全机制概述
Android安全机制在三个方面来体现。分别从kernel,dalvik, framework三个层次管理。在kernel方面,android系统引入SE linux;在dalvik方面引入沙箱隔离技术;在framework层面引入应用权限控制。详细如下:

A. SE Linux:Linux内核层的安全增强,是一套独立于传统Linux权限访问控制的强制性权限控制机制。Google已将这套机制移植到Android内核,增强了内核的安全性。

B.    沙箱隔离:沙箱是基于不同应用之间User ID的不同而实现的,其本质是Linux对于不同用户间访问权限的隔离。每个APP和系统进程都被分配唯一并且固定的User Id,这个uid与内核层进程的uid对应。每个APP在各自独立的Dalvik虚拟机中运行,拥有独立的地址空间和资源。运行于Dalvik虚拟机中的 进程必须依托内核层Linux进程而存在,因此Android使用Dalvik虚拟机和Linux的文件访问控制来实现沙箱机制。

C.    应用权限控制:Android应用需要申请相应的权限才能访问系统的资源和信息,大多数权限由Android框架层的API进行控制,另一部分权限映射到应用所在的Group ID上,由Linux内核做出控制。

2    UID,GID,GIDS说明与设置(android L)
2.1    UID, GID, GIDS说明
Android 的权限分离的基础是建立在 Linux 已有的 uid 、 gid 、 gids 基础上的 。
UID:        Android 在安装一个应用程序,就会为它分配一个 uid。
GID:    对于普通应用程序来说, gid 等于uid。
GIDS:     gids 是由框架在 Application 安装过程中生成,与 Application 申请的具体权限相关。 如果 Application 申请的相应的 permission 被 granted ,而且 中有对应的 gid s , 那么 这个 Application 的 gids 中将 包含这个 gid s

2.2    UID, GID, GIDS 设置
1    Android启动某一个App应用,创建进程:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 



     private final void startProcessLocked(ProcessRecord app, String hostingType, 

             String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) 

 { 

 ........ 

 int uid = app.uid; 

 ........ 

 permGids = pm.getPackageGids(app.info.packageName); 

 ........ 

 System.arraycopy(permGids, 0, gids, 2, permGids.length); 

 ........ 

 Process.ProcessStartResult startResult = Process.start(entryPoint, 

                     app.processName, uid, uid, gids, debugFlags, mountExternal, 

                     app.info.targetSdkVersion, app.info.seinfo, 

 requiredAbi, instructionSet, 

                     app.info.dataDir, entryPointArgs); 

 ........ 

 } 


 frameworks/base/core/java/android/os/Process.java 


 public static final ProcessStartResult start(final String processClass, 

                                   final String niceName,   

                                   int uid, int gid, int[] gids, 

                                   int debugFlags, int mountExternal, 

                                   int targetSdkVersion, 

                                   String seInfo,                  

                                   String abi,                     

                                   String instructionSet, 

                                   String appDataDir, 

                                   String[] zygoteArgs) { 

 ........ 

 return startViaZygote(processClass, niceName, uid, gid, gids, 

                     debugFlags, mountExternal, targetSdkVersion, seInfo, 

                     abi, instructionSet, appDataDir, zygoteArgs); 

 ........ 

 } 


     private static ProcessStartResult startViaZygote(final String processClass, 

                                   final String niceName, 

                                   final int uid, final int gid, 

                                   final int[] gids, 

                                   int debugFlags, int mountExternal, 

                                   int targetSdkVersion, 

                                   String seInfo, 

                                   String abi, 

                                   String instructionSet, 

                                   String appDataDir, 

                                   String[] extraArgs) 

                                   throws ZygoteStartFailedEx { 

 ........ 

 argsForZygote.add("--runtime-init"); 

 argsForZygote.add("--setuid=" + uid); 

 argsForZygote.add("--setgid=" + gid); 

 ........ 

 sb.append("--setgroups="); 

 ........ 

 argsForZygote.add(sb.toString()); 

 ........ 

 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); 

 } 



 frameworks/base/core/java/com/android/internal/os/Zygote.java 


     public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, 

           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, 

           String instructionSet, String appDataDir) { 

 ........ 

   int pid = nativeForkAndSpecialize( 

                   uid, gid, gids, debugFlags, rlimits, 

                    mountExternal, seInfo, niceName, fdsToClose, 

                   instructionSet, appDataDir); 

 ........ 


 } 


 frameworks/base/core/jni/com_android_internal_os_Zygote.cpp 


 static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, 

                                      jint debug_flags, jobjectArray javaRlimits, 

                                      jlong permittedCapabilities, 

  jlong effectiveCapabilities, 

                                      jint mount_external, 

                                      jstring java_se_info, jstring java_se_name, 

                                      bool is_system_server, jintArray fdsToClose, 

                                      jstring instructionSet, jstring dataDir) { 


 ........ 

 pid_t pid = fork(); 

 ........ 

 SetGids(env, javaGids); 

 ........ 

 int rc = setresgid(gid, gid, gid); 

 ........ 

 rc = setresuid(uid, uid, uid); 

 ........ 


 }


创建进程完毕,同时该进程设置了相应的uid, gid, gids

3    app权限信息的加载过程
所有App权限信息保存在/data/system/packages.xml。 系统启动后,会检查/data/system/packages.xml 是否存在。这个文件是在解析 apk 时由writeLP()创建的,里面记录了系统的 permissions,以及每个 apk name, codePath, flags, ts, version, uesrid 等信息,这些信息主要通过 apk 的AndroidManifest.xml 解析获取,解析完 apk 后将更新信息写入这个文件并保存到 flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有 apk升级,安装或删除时会更新这个文件。

3.1    SystemServer中启动PackageManagerService

frameworks/base/services/java/com/android/server/SystemServer.java 

 mPackageManagerService = PackageManagerService.main(mSystemContext, 

 mInstaller,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); 


 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 

 mSettings = new Settings(context); 


 frameworks/base/services/core/java/com/android/server/pm/Settings.java 

         mSettingsFilename = new File(mSystemDir, "packages.xml"); 

         mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml"); 

         mPackageListFilename = new File(mSystemDir, "packages.list"); 

         FileUtils.setPermissions(mPackageListFilename, 0660, 

 SYSTEM_UID, PACKAGE_INFO_GID);


读取/data/目录下文件:

/data/packages.xml, /data/packages.list 


 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 

             mSettings.insertPackageSettingLPw(pkgSetting, pkg); 

             // Add the new setting to mPackages 

             mPackages.put(pkg.applicationInfo.packageName, pkg); 


     @Override 

     public int[] getPackageGids(String packageName) { 

 ........ 

             PackageParser.Package p = mPackages.get(packageName); 

 ........ 

                 final PackageSetting ps = (PackageSetting)p.mExtras; 

                 return ps.getGids(); 

 ........ 

     }




3.2    安装新应用权限信息的写入过程
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
a.    installNewPackageLI()
b.     PackageParser.Package newPackage = scanPackageLI(pkg,
parseFlags, scanFlags, System.currentTimeMillis(), user);

c.    updateSettingsLI(newPackage, installerPackageName, null, null, res);
d.    mSettings.writeLPr();
将解析的每个 apk 的信息保存到 packages.xml 和 packages.list 文件里,