zhangAndroidBlogjava

PackageManagerService小解

功能有三部分

  1. 提供一个能够根据intent匹配到具体的Activity、Service、Provider。即当应用程序调用了startActivity(intent)时,能够把参数中指定的intent转换成一个具体的包含了程序包名称及具体Component(组件、构建、元件),以便java类加载器加载具体的Component。        
  2. 进行权限检查。即当应用程序调用某个需要一定权限的函数调用时,系统能够判断调用者是否具备该权限,从而保证系统的安全。
  3. 提供安装、删除应用程序的接口。
--------------------------------------------------------------------

Framework中的包管理框架分为三层,应用程序层、PmS服务层、数据文件层

  1.应用程序层
应用程序需要使用包管理服务时,调用ContextImpl类的getPackageManager()函数返回一个PackageManager对象,然后调用该对象所提供的各种API接口.(一般的服务调用是通过getSystemService("服务名")获得的,而PmS是提供了一个函数,但无本质区别).
  2.PmS服务层
和AmS,WmS等其他系统服务一样,PmS运行于SystemServer进程.PmS服务运行时,使用两个目录下的XML文件保存相关的信息.有关SystemServer,请点击链接http://blog.csdn.net/windskier/article/details/6417657
第一个目录是"/system/etc/permission",该目录下的所有XML文件用于permission的管理.包含两件事.一:定义了系统中包含哪些feature(特色,功能),应用程序可以在AndroidManifest.xml中使用<use-feature>标签声明程序需要哪些feature,比如:

1 <use-feature android:name="android.hardware.wifi" android:required="true" />

该标签的作用仅仅是"声明"或者"建议"设备是否具备指定的feature,而不会影响程序的安装,required(需要,必须的)的作用是如果没有改feature,程序不能运行.
设备都包含了哪些feature就是在该目录下声明的,因此,如果用户给系统添加了GPS或者BlueTooth,则必须在该目录下声明相关的XML文件,以便Framework知晓.

 例图 目录结构


代码结构


该目录下另外还有一个platform.xml文件,该文件中为一些特别的uid和gid分配了一些默认的权限.给uid分配权限使用<assign-permission>标签,给gid分配权限使用<permission>标签,如下
   

第二个目录是"/data/system/packages.xml",该文件保存了所有安装程序的基本包信息,有点像系统的"注册表".详细信息后面介绍.


除了PmS服务外,还有两个辅助系统服务用于程序安装.一个是DefaultContainerService,该服务主要用于把安装程序复制到程序目录中;另一个是Installer服务,该服务实际上并不是一个Binder,而是一个Socket客户端,PmS直接和该Socket客户端交互.Socket的服务端主要完成程序的文件解压工作及数据目录创建,比如从APK文件中提取出dex文件,删除dalvik-cache目录下的dex文件,创建程序专属的数据目录等.
3.数据应用层
  android程序中的程序文件分为三部分:   

第一部分,程序文件.所有的系统程序保存在/system/app目录下,所有的第三方应用程序保存在/data/app目录下.对于非系统程序在安装前可以保存在任意目录下,但在安装后,PmS会把APK文件存放到/data/app目录下.它与原始的APK文件唯一的区别是文件名不同,原始的APK可以任意命名,而该目录下的APK是以包名进行命名,并自动增加一个"-x"后缀,比如com.android.xxx.text-1.apk.当同样一个程序第二次安装时,就会变成com.android.xxx.text-2.apk.第三次安装时又会变成com.android.xxx.text-1.apk.
/data/dalvik-cache目录保存了程序中执行代码.一个APK实际上是一个jar压缩类型的文件,压缩包中包含了各种资源文件,资源索引文件,AndroidManifest文件及程序文件,当应用程序运行前,PmS会从APK文件中提取代码文件,也就是所谓的dex文件,并将该文件存储在该目录下,以便以后能够快速运行该程序.

第二部分,framework库文件.这些库文件存在于/system/framework目录下,库文件类型是APK或者Jar,系统开机后,dalvik虚拟机会加载这些库文件,而在PmS启动时,如果这些Jar或者APK文件还没有转换成dex文件,则PmS会将这些库文件转换成dex文件,并保存到/data/dalvik-cache目录下.


第三部分,应用程序所使用的数据文件.应用程序可以使用三种数据保存方式,分别为参数存储,数据库存储,文件存储.这三种存储方式对应的数据文件一般都保存在/data/data/xxx目录下,xxx代表程序包名.在2.2之后,系统还提供了额外三个目录,其中/data/secure用于保存加密数据,Framework将提供一种加密接口,所有的加密文件将存放到该目录下./data/drm目录主要用于存放包含有数字版权的数据文件,同样,Framework层将提供一种与Drm相关的类接口用于间接访问该目录中的文件./data/app-private目录目前和/data/drm的作用相同,Framework中似乎没有使用/data/drm,er临时使用/data/app-private代替.


-------------------------------------------------------------------- 

packages.xml文件格式


packagers.xml在/data/system目录下,该文件记录了系统汇总所有应用程序的包管理相关信息,PmS将根据这些信息进行包管理的各种操作.
last-platform-version:该标签记录了系统最后一次的版本号,一般和SDK版本号相同.标签中包含两个属性,一个是internal(内部的),另一个是external(外部的),internal是内部存储区上的程序被更新前的系统版本号,external是外部存储区程序更新前的系统版本号,一般情况下两者相同.(所谓程序更新,不是指应用程序有了新版本的更新,而是指系统升级后,需要重新为所有自己安装的程序设置访问权限,即重新建立包管理信息所需的XML文件)

permission:保存系统中所有的权限列表,包含Framework定义的权限以及应用程序自定义的权限,Framework中定义的权限在android/framework/base/core/res/rs/AndroidManifest.xml中.每个permission都有一个item标签标识,item标签中分别包含三个属性.
  1. name:权限名称.系统权限一般都以android.permission.开头,应用程序中自定义权限一般都以所属的包名开头,权限名称必须全局唯一.
  2. package:权限所在的包名,Framework对应的包名为android.
  3. protectionLevel:保护级别.一共有四种保护级别,分别为普通的,危险的,签名的,签名或系统的.具体参见http://developer.android.com/guide/topics/manifest/permission-element.html
cert:代表certifacation,即"证书"的意思,一个应用程序一般只包含一个证书.cert包含两个属性,分别是index和key.
  1. index:在PmS内部保存了所有的证书,每个证书对应一个索引,index表示的就是索引.
  2. key:该属性不是必需的,如果index对应的证书已经存在,则该key子标签可以没有,而如果index是首次出现,则key的值必须指定,其值为2390个16进制值,来源于对APK签名的证书文件.
从表面上可以修改cert的标签值来改变应用程序的签名.但实际是不可行的.因为在PmS每次启动时同时解析packages.xml和packages.list文件内容.如果发现uid不一致,会直接卸载程序,并重新扫描安装目录,根据读取信息重写packages.xml和packages.list文件.

sigs:代表signature,即"签名",一个应用程序只能有一个签名,但一个签名可以包含多个证书.签名标签只有一个count属性,表示包含多少个证书,sigs标签中必须包含count个cert子标签,用于表示具体的证书.

perms:代表permission,即"权限".一个应用程序可以申请多个权限,perms标签包含了所有这些权限的列表.perms标签中可以包含item子标签,用于表示每一个具体的权限.注意区分perms标签和permission标签,perms标签用于表示一个具体应用程序所使用的权限列表,该标签一般包含在package标签或者shared-user标签中,而permission标签却是表示系统中所有定义的权限列表,该列表是全局的.

package:包含一个应用程序包的相关信息,有如下属性
  1. name:程序包名称,比如com.android.xxx.xxx
  2. codePath:程序包所在路径,比如/system/app/xxx.apk,/data/app/com.xxx.xxx-1.apk.
  3. nativeLibrayPath:该程序所使用的native库文件路径.在一般情况下native库文件会被安装到程序数据文件路径下的lib子目录中,比如/data/data/com.xxx.xxx/lib.
  4. flags:用于标识应用程序类型,这些类型在ApplicationInfo.java中有定义,包括FLAG_SYSTEM,FLAG_DEBUGGABLE,FLAG_PERSISTENT等.
  5. it,ut:分别代表"首次安装的时间install time"和"最后升级时间update time".
  6. ft,ts:这两个标签的含义相同,代表最后一次修改该记录的时间,一般情况下,这个时间等于ut标签值.
  7. installStatus:改属性仅在packages-backup.xml文件中存在,其值一般为false,当值为true时,该属性一般不会再写到文件中.
  8. userId和sharedUserId:前者代表应用程序对应的Linux用户id值,后者代表该应用程序共享的Linux用户id,这两个属性是互斥的,即只能有一个属性.当存在sharedUserId时,该应用程序将以共享id的身份运行,但这并不是说所有共享id的程序运行在同一个进程中.
  9. installer:安装器的名称,一般是值应用程序调用PackageManager的installPackage()函数时,参数installerPackageName的值.
package标签中可以包含sigs和perms子标签,分别表示该应用程序所使用的签名信息及权限信息.如下
1 <package name="com.android.xxx" codePath="/system/app/xxx.apk" nativeLibraryPath="/data/data.com.android.xxx/lib" flags="1" ft="12dabe97198" it="12d805b2cd8" ut="12dabe97198" version="9" userId="10086">
2    <sigs count="1">
3       <cert index="0" key="3082"/>
4    </sigs>
5 </package>

shared-user:系统为每一个应用程序分配一个Linux用户id,一些native进程的用户id从1000开始,比如shell进程,log进程,phone进程等,java应用程序对应的用户id从10000开始.从某种角度讲,一个应用程序就是一个用户id,当然,应用程序申请使用共享用户id除外.
shared-user标签定义了共享用户id对应的签名和权限,它和package标签的含义本质是相同的.shared-user的属性包括name和userId,其意义和package标签的属性相同,包含的子标签也和package相同,包括sigs和perms标签.
--------------------------------------------------------------------  
各主要功能类的关系
Settings类:在PmS中,Settings基本上包含了所需的全部信息,该类主要包含几类变量.
1.包属性信息
 1 /*配置文件名称,指的就是packages.xml*/
 2 private final File mSettingsFilename;
 3 /*配置文件可以有一个backup文件,该backup文件用于系统以外关机后和原始配置文件进行对比,以检查系统的完整性*/
 4 private final File mBackupSettingsFilename;
 5 /*值得就是packages.list文件,保存了所有的应用程序列表,该文件中每一行对应一个应用程序,比如com.android.haiii.debugjar 10032 1 /data/data/com.android.haiii.debugjar
 6 
 7 在该记录中,第一项表示应用程序包名称;第二项代表该应用程序的Linux用户id,如果应用程序使用的共享用户id,则指的是共享用户id;第三项数字1代表该应用程序可以被debug,0代表不可以.第四项代表应用程序的数据文件的目录*/
 8 private final File mPackageListFilename;
 9 /*指的是文件packages-stopped.xml,这个文件记录的是系统中强制停止运行的Package*/
10 private final File mStoppedPackagesFilename;
11 /*packages-stopped.xml文件的备份*/
12 private final File mBackupStoppedPackagesFilename;
13 /*在PmS启动后,该变量将被填充为包管理信息,这些信息来源于pacaages.xml.注意该变量和PmS中的mPackages的区别,前者是从packages.xml读取的记录信息,而后者则是直接扫描程序目录下所有APK文件而生成的信息,并且前者的类型是PackageSetting,后者是PackageParse.Package*/
14 final HashMap<String, PackageSetting> mPackages =new HashMap<String, PackageSetting>();
15 /*该变量保存那些没有通过标准卸载方法删除的程序列表.如果使用标准卸载方法,PmS在卸载程序后,会清除该程序在packages.xml中对应的记录,而如果通过adb或者其他文件操作删除APK文件,那么packages.xml中对应的记录将不会被删除.每次系统启动时,PmS会检查packages.xml文件,并检查相应程序目录下的文件,从而判断是否被以外删除.如果删除,如果删除,则把相应的包信息存放到mDisabledSysPackage列表中,该变量的Sys不是指系统程序,指的是应用程序*/
16 private final HashMap<String, PackageSetting> mDisabledSysPackages = new HashMap<String, PackageSetting>();
17 /*保存packages.xml中last-platform-version标签中的值*/
18 int mInternalSdkPlatform;   
19 /*同上*/
20 int mExternalSdkPlatform;
用户id相关信息
/*该变量保存了所有共享id的信息,来源于packages.xml中的<shared-user>标签*/
final HashMap<String, SharedUserSetting> mSharedUsers = new HashMap<String, SharedUserSetting>();
/*所有用户id*/
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
/*当PmS解析packages.xml文件时,如果发现某个package标签中使用的是sharedUserId,则暂时把该package添加到mPendingPackages列表中,直到最后解析完毕shared-user标签后,在完善原来的package标签中的相关信息*/
private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>();
权限相关信息
/*保存了所有签名*/
private final ArrayList<Signature> mPastSignatures = new ArrayList<Signature>();
/*保存了所有的权限,该Map是从permission名称到permission信息的一个映射*/
final HashMap<String, BasePermission> mPermissions = new HashMap<String, BasePermission>();
/*对应packages.xml文件中的permission-tree标签.*/
final HashMap<String, BasePermission> mPermissionTrees = new HashMap<String, BasePermission>();
删除信息
/*保存的是packages.xml中的cleaning-package标签中包含的package列表,该列表来源于那些已经被卸载的应用程序,但其所包含的数据目录由于保存在外部存储区而没有被删除.因为PmS卸载程序时,如果该程序的数据保存在外部存储空间中,则其数据目录默认不会被删除.*/
final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();

PmS类中包含的重要变量 
 1 /*保存所有程序包信息,来源于扫描程序目录下所有程序文件*/ 
 2 final HashMap<String, PackageParser.Package> mPackages = new HashMap<String, PackageParser.Package>();
 3 /*Settings类*/
 4 final Settings mSettings
 5 /*一个feature本质上只是一段字符串描述,比如"android.hardwar.wifi"*/
 6 final HashMap<String, FeatureInfo> mAvailableFeatures = new HashMap<String, FeatureInfo>();
 7 /*系统中所有Linux用户id*/
 8 int[] mGlobalGids;
 9 /*系统中所有的权限名称*/
10 final SparseArray<HashSet<String>> mSystemPermissions = new SparseArray<HashSet<String>>();
11 /*系统所以来的共享Java库,其值来源于platform.xml中library标签中定义的值*/
12 final HashMap<String, String> mSharedLibraries = new HashMap<String, String>();
13 
14 // All available activities, for your resolving pleasure.
15 final ActivityIntentResolver mActivities = new ActivityIntentResolver();
16 
17 // All available receivers, for your resolving pleasure.
18 final ActivityIntentResolver mReceivers = new ActivityIntentResolver();
19 
20 // All available services, for your resolving pleasure.
21 final ServiceIntentResolver mServices = new ServiceIntentResolver();
22 
23 /*以上上个变量用于进行Intent-filter的匹配,并分别匹配到Activity,Receiver,Service对象.在PmS初始化时会便利程序目录下的全部的程序,并从其中包含的AndroidManifest.xml文件中提取所有的intent-filter数据,并将其保存到以上三个变量中.系统运行时,应用程序调用PackageManager的 queryIntentXXX()函数时,其内部正式通过以上三个变量查询相关的目标对象信息的*/
--------------------------------------------------------------------  
PmS主体启动过程
主体启动过程就是指PmS构造函数内部的启动流程.
1.创建一个Settings对象,在该对象的构造函数中,给成员变量静态赋值.
/*创建Settings对象*/
 mSettings = new Settings(context);

/*Settings对象构造函数*/
Settings(Context context, File dataDir) {
        mContext = context;
        mSystemDir = new File(dataDir, "system");
        mSystemDir.mkdirs();
        FileUtils.setPermissions(mSystemDir.toString(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG
                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                -1, -1);
        // 主要的三个变量
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        mPackageListFilename = new File(mSystemDir, "packages.list");
        // Deprecated: Needed for migration 如下变量还没有使用
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
    }

2.调用mSettings.addSharedUserLP()添加共享id
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM);

3.传递一个Installer对象,该对象将辅助程序的安装,比如完成从APK文件提取出dex文件,删除dex文件等操作.Installer对象内部其实包含一个LocalSocket对象,所有Installer提供的API接口内部其实会通过该LocalSocket发送一系列参数值给远程的SocketServer对象.
public final class Installer {
    private static final String TAG = "Installer";

    private static final boolean LOCAL_DEBUG = false;

    InputStream mIn;

    OutputStream mOut;

    LocalSocket mSocket;

    byte buf[] = new byte[1024];

    int buflen = 0;

    private boolean connect() {
        if (mSocket != null) {
            return true;
        }
        Slog.i(TAG, "connecting");
        try {
            mSocket = new LocalSocket();

            LocalSocketAddress address = new LocalSocketAddress("installd",
                    LocalSocketAddress.Namespace.RESERVED);

            mSocket.connect(address);

            mIn = mSocket.getInputStream();
            mOut = mSocket.getOutputStream();
        } catch (IOException ex) {
            disconnect();
            return false;
        }
        return true;
    }

    private void disconnect() {
        Slog.i(TAG, "disconnecting");
        try {
            if (mSocket != null)
                mSocket.close();
        } catch (IOException ex) {
        }
        try {
            if (mIn != null)
                mIn.close();
        } catch (IOException ex) {
        }
        try {
            if (mOut != null)
                mOut.close();
        } catch (IOException ex) {
        }
        mSocket = null;
        mIn = null;
        mOut = null;
    }

    private boolean readBytes(byte buffer[], int len) {
        int off = 0, count;
        if (len < 0)
            return false;
        while (off != len) {
            try {
                count = mIn.read(buffer, off, len - off);
                if (count <= 0) {
                    Slog.e(TAG, "read error " + count);
                    break;
                }
                off += count;
            } catch (IOException ex) {
                Slog.e(TAG, "read exception");
                break;
            }
        }
        if (LOCAL_DEBUG) {
            Slog.i(TAG, "read " + len + " bytes");
        }
        if (off == len)
            return true;
        disconnect();
        return false;
    }

    private boolean readReply() {
        int len;
        buflen = 0;
        if (!readBytes(buf, 2))
            return false;
        len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
        if ((len < 1) || (len > 1024)) {
            Slog.e(TAG, "invalid reply length (" + len + ")");
            disconnect();
            return false;
        }
        if (!readBytes(buf, len))
            return false;
        buflen = len;
        return true;
    }

    private boolean writeCommand(String _cmd) {
        byte[] cmd = _cmd.getBytes();
        int len = cmd.length;
        if ((len < 1) || (len > 1024))
            return false;
        buf[0] = (byte) (len & 0xff);
        buf[1] = (byte) ((len >> 8) & 0xff);
        try {
            mOut.write(buf, 0, 2);
            mOut.write(cmd, 0, len);
        } catch (IOException ex) {
            Slog.e(TAG, "write error");
            disconnect();
            return false;
        }
        return true;
    }

    private synchronized String transaction(String cmd) {
        if (!connect()) {
            Slog.e(TAG, "connection failed");
            return "-1";
        }

        if (!writeCommand(cmd)) {
            /*
             * If installd died and restarted in the background (unlikely but
             * possible) we'll fail on the next write (this one). Try to
             * reconnect and write the command one more time before giving up.
             
*/
            Slog.e(TAG, "write command failed? reconnect!");
            if (!connect() || !writeCommand(cmd)) {
                return "-1";
            }
        }
        if (LOCAL_DEBUG) {
            Slog.i(TAG, "send: '" + cmd + "'");
        }
        if (readReply()) {
            String s = new String(buf, 0, buflen);
            if (LOCAL_DEBUG) {
                Slog.i(TAG, "recv: '" + s + "'");
            }
            return s;
        } else {
            if (LOCAL_DEBUG) {
                Slog.i(TAG, "fail");
            }
            return "-1";
        }
    }

    private int execute(String cmd) {
        String res = transaction(cmd);
        try {
            return Integer.parseInt(res);
        } catch (NumberFormatException ex) {
            return -1;
        }
    }

    public int install(String name, int uid, int gid) {
        StringBuilder builder = new StringBuilder("install");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(uid);
        builder.append(' ');
        builder.append(gid);
        return execute(builder.toString());
    }

    public int dexopt(String apkPath, int uid, boolean isPublic) {
        StringBuilder builder = new StringBuilder("dexopt");
        builder.append(' ');
        builder.append(apkPath);
        builder.append(' ');
        builder.append(uid);
        builder.append(isPublic ? " 1" : " 0");
        return execute(builder.toString());
    }

    public int movedex(String srcPath, String dstPath) {
        StringBuilder builder = new StringBuilder("movedex");
        builder.append(' ');
        builder.append(srcPath);
        builder.append(' ');
        builder.append(dstPath);
        return execute(builder.toString());
    }

    public int rmdex(String codePath) {
        StringBuilder builder = new StringBuilder("rmdex");
        builder.append(' ');
        builder.append(codePath);
        return execute(builder.toString());
    }

    public int remove(String name, int userId) {
        StringBuilder builder = new StringBuilder("remove");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(userId);
        return execute(builder.toString());
    }

    public int rename(String oldname, String newname) {
        StringBuilder builder = new StringBuilder("rename");
        builder.append(' ');
        builder.append(oldname);
        builder.append(' ');
        builder.append(newname);
        return execute(builder.toString());
    }

    public int fixUid(String name, int uid, int gid) {
        StringBuilder builder = new StringBuilder("fixuid");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(uid);
        builder.append(' ');
        builder.append(gid);
        return execute(builder.toString());
    }

    public int deleteCacheFiles(String name, int userId) {
        StringBuilder builder = new StringBuilder("rmcache");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(userId);
        return execute(builder.toString());
    }

    public int createUserData(String name, int uid, int userId) {
        StringBuilder builder = new StringBuilder("mkuserdata");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(uid);
        builder.append(' ');
        builder.append(userId);
        return execute(builder.toString());
    }

    public int removeUserDataDirs(int userId) {
        StringBuilder builder = new StringBuilder("rmuser");
        builder.append(' ');
        builder.append(userId);
        return execute(builder.toString());
    }

    public int clearUserData(String name, int userId) {
        StringBuilder builder = new StringBuilder("rmuserdata");
        builder.append(' ');
        builder.append(name);
        builder.append(' ');
        builder.append(userId);
        return execute(builder.toString());
    }

    /**
     * Clone all the package data directories from srcUserId to targetUserId. If copyData is true,
     * some of the data is also copied, otherwise just empty directories are created with the
     * correct access rights.
     * 
@param srcUserId user to copy the data directories from
     * 
@param targetUserId user to copy the data directories to
     * 
@param copyData whether the data itself is to be copied. If false, empty directories are
     * created.
     * 
@return success/error code
     
*/
    public int cloneUserData(int srcUserId, int targetUserId, boolean copyData) {
        StringBuilder builder = new StringBuilder("cloneuserdata");
        builder.append(' ');
        builder.append(srcUserId);
        builder.append(' ');
        builder.append(targetUserId);
        builder.append(' ');
        builder.append(copyData ? '1' : '0');
        return execute(builder.toString());
    }

    public boolean ping() {
        if (execute("ping") < 0) {
            return false;
        } else {
            return true;
        }
    }

    public int freeCache(long freeStorageSize) {
        StringBuilder builder = new StringBuilder("freecache");
        builder.append(' ');
        builder.append(String.valueOf(freeStorageSize));
        return execute(builder.toString());
    }

    public int getSizeInfo(String pkgName, int persona, String apkPath, String fwdLockApkPath,
            String asecPath, PackageStats pStats) {
        StringBuilder builder = new StringBuilder("getsize");
        builder.append(' ');
        builder.append(pkgName);
        builder.append(' ');
        builder.append(persona);
        builder.append(' ');
        builder.append(apkPath);
        builder.append(' ');
        builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
        builder.append(' ');
        builder.append(asecPath != null ? asecPath : "!");

        String s = transaction(builder.toString());
        String res[] = s.split(" ");

        if ((res == null) || (res.length != 5)) {
            return -1;
        }
        try {
            pStats.codeSize = Long.parseLong(res[1]);
            pStats.dataSize = Long.parseLong(res[2]);
            pStats.cacheSize = Long.parseLong(res[3]);
            pStats.externalCodeSize = Long.parseLong(res[4]);
            return Integer.parseInt(res[0]);
        } catch (NumberFormatException e) {
            return -1;
        }
    }

    public int moveFiles() {
        return execute("movefiles");
    }

    /**
     * Links the native library directory in an application's directory to its
     * real location.
     *
     * 
@param dataPath data directory where the application is
     * 
@param nativeLibPath target native library path
     * 
@return -1 on error
     
*/
    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) {
        if (dataPath == null) {
            Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
            return -1;
        } else if (nativeLibPath == null) {
            Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
            return -1;
        }

        StringBuilder builder = new StringBuilder("linklib ");
        builder.append(dataPath);
        builder.append(' ');
        builder.append(nativeLibPath);
        builder.append(' ');
        builder.append(userId);

        return execute(builder.toString());
    }
}

4.给以下几个数据文件路径赋值
            File dataDir = Environment.getDataDirectory();
            mAppDataDir = new File(dataDir, "data");
            mAppInstallDir = new File(dataDir, "app");
            mAppLibInstallDir = new File(dataDir, "app-lib");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mUserAppDataDir = new File(dataDir, "user");
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

5.调用readPermission()函数,从/system/etc/permissions目录下读取全部XML文件,这些文件主要定义了两部分系统属性.第一是系统中所有的feature,第二是为一些native系统进程分配了一些特定的权限,读取出的属性值将保存到mSettings.mPermissions变量中.
6.调用mSettings对象的readLP()函数从/data/system/packages.xml文件中读取所有应用程序中和包管理相关的信息,这些信息将保存到mSettings.mPackages变量中.
7.对Java系统中的库文件进行dex提取(转换).在Android系统中,Java源码编译后的Class文件不能直接被执行,Android中的编译器会将程序中的多个Class文件转换成一个dex文件.转换后的文件和原始的Class文件相比有几点优势,比如节省了字节码,优化了内存分配,重新组织函数映射表等.而APK或者Jar文件本身是一个zip压缩包,其内部包含了真的dex文件,因此,在程序执行前,必须先从这些Jar/APK文件中提取出相应的dex文件.当然并不是说系统每次开机都会进行dex提取,它会调用dalvik.system.DexFile.isDexOptNeeded()函数进行判断,该函数内部会判断dex是否存在,并且内部版本号和原始APK/Jar是否相同.如果是,就不进行dex提取,否则,系统认为原来的dex文件已经过期,于是就会重新提取.
Java系统中的库文件包含以下三个部分.
  • Java Boot路径下的所有文件,Boot路径是指在Terminal下调用getProp("java.boot.class.path")获取的路径,获取的路径以冒号为分隔符.
  • 共享库路径:该路径是在platform.xml中使用library标签定义的Jar文件.
  • Frameworks目录下的所有APK和Jar文件,除了framework-res.apk之外,因为该文件内部不包含代码,所以不存在dex文件.
            // Set flag to monitor and not change apk file paths when
            
// scanning install directories.
            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
            if (mNoDexOpt) {
                Slog.w(TAG, "Running ENG build: no pre-dexopt!");
                scanMode |= SCAN_NO_DEX;
            }

            final HashSet<String> libFiles = new HashSet<String>();

            mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
            mDalvikCacheDir = new File(dataDir, "dalvik-cache");

            boolean didDexOpt = false;

            /**
             * Out of paranoia, ensure that everything in the boot class
             * path has been dexed.
             
*/
            String bootClassPath = System.getProperty("java.boot.class.path");
            if (bootClassPath != null) {
                String[] paths = splitString(bootClassPath, ':');
                for (int i=0; i<paths.length; i++) {
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
                            libFiles.add(paths[i]);
                            mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
                            didDexOpt = true;
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Boot class path not found: " + paths[i]);
                    } catch (IOException e) {
                        Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? "
                                + e.getMessage());
                    }
                }
            } else {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            /**
             * Also ensure all external libraries have had dexopt run on them.
             
*/
            if (mSharedLibraries.size() > 0) {
                Iterator<String> libs = mSharedLibraries.values().iterator();
                while (libs.hasNext()) {
                    String lib = libs.next();
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
                            libFiles.add(lib);
                            mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
                            didDexOpt = true;
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Library not found: " + lib);
                    } catch (IOException e) {
                        Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                + e.getMessage());
                    }
                }
            }

            // Gross hack for now: we know this file doesn't contain any
            
// code, so don't dexopt it to avoid the resulting log spew.
            libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");

            /**
             * And there are a number of commands implemented in Java, which
             * we currently need to do the dexopt on so that they can be
             * run from a non-root shell.
             
*/
            String[] frameworkFiles = mFrameworkDir.list();
            if (frameworkFiles != null) {
                for (int i=0; i<frameworkFiles.length; i++) {
                    File libPath = new File(mFrameworkDir, frameworkFiles[i]);
                    String path = libPath.getPath();
                    // Skip the file if we alrady did it.
                    if (libFiles.contains(path)) {
                        continue;
                    }
                    // Skip the file if it is not a type we want to dexopt.
                    if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
                        continue;
                    }
                    try {
                        if (dalvik.system.DexFile.isDexOptNeeded(path)) {
                            mInstaller.dexopt(path, Process.SYSTEM_UID, true);
                            didDexOpt = true;
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, "Jar not found: " + path);
                    } catch (IOException e) {
                        Slog.w(TAG, "Exception reading jar: " + path, e);
                    }
                }
            }

            if (didDexOpt) {
                // If we had to do a dexopt of one of the previous
                
// things, then something on the system has changed.
                
// Consider this significant, and wipe away all other
                
// existing dexopt files to ensure we don't leave any
                
// dangling around.
                String[] files = mDalvikCacheDir.list();
                if (files != null) {
                    for (int i=0; i<files.length; i++) {
                        String fn = files[i];
                        if (fn.startsWith("data@app@")
                                || fn.startsWith("data@app-private@")) {
                            Slog.i(TAG, "Pruning dalvik file: " + fn);
                            (new File(mDalvikCacheDir, fn)).delete();
                        }
                    }
                }
            }

8.为三个程序目录分别创建一个FileObserver,FileObserver对象内部会检测目录中添加、删除文件的事件,并当事件发生时执行相应的操作.比如,当目录中添加文件时,就会调用scanPackageLI(file,...)函数扫描添加的文件.
这三个目录如下
  • /system/framework:该目录保存了Framework内核相关的程序.
  • /system/app:系统程序,一般是指Android中自带的程序.
  • /vendor/app:第三方程序,一般是厂商开发的自定义程序.
9.调用scanDirLI()扫描(解析程序中AndroidManifest.xml)以上三个目录中的所有程序文件,并将扫描结果保存到PmS中的mPackages变量中.
            // Find base frameworks (resource packages without code).
            mFrameworkInstallObserver = new AppDirObserver(
                mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
            mFrameworkInstallObserver.startWatching();
            scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanMode | SCAN_NO_DEX, 0);

            // Collect all system packages.
            mSystemAppDir = new File(Environment.getRootDirectory(), "app");
            mSystemInstallObserver = new AppDirObserver(
                mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
            mSystemInstallObserver.startWatching();
            scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

            // Collect all vendor packages.
            mVendorAppDir = new File("/vendor/app");
            mVendorInstallObserver = new AppDirObserver(
                mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
            mVendorInstallObserver.startWatching();
            scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
        String[] files = dir.list();
        if (files == null) {
            Log.d(TAG, "No files in app dir " + dir);
            return;
        }

        if (DEBUG_PACKAGE_SCANNING) {
            Log.d(TAG, "Scanning app dir " + dir);
        }

        int i;
        for (i=0; i<files.length; i++) {
            File file = new File(dir, files[i]);
            if (!isPackageFilename(files[i])) {
                // Ignore entries which are not apk's
                continue;
            }
            PackageParser.Package pkg = scanPackageLI(file,
                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
            // Don't mess around with apps in system partition.
            if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                    mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
                // Delete the apk
                Slog.w(TAG, "Cleaning up failed install of " + file);
                file.delete();
            }
        }
    }

private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
            int parseFlags, int scanMode, long currentTime, UserHandle user) {
        File scanFile = new File(pkg.mScanPath);
        if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
                pkg.applicationInfo.publicSourceDir == null) {
            // Bail out. The resource and code paths haven't been set.
            Slog.w(TAG, " Code and resource paths haven't been set correctly");
            mLastScanError = PackageManager.INSTALL_FAILED_INVALID_APK;
            return null;
        }
        mScanningPath = scanFile;

        if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
        }

        if (pkg.packageName.equals("android")) {
            synchronized (mPackages) {
                if (mAndroidApplication != null) {
                    Slog.w(TAG, "*************************************************");
                    Slog.w(TAG, "Core android package being redefined.  Skipping.");
                    Slog.w(TAG, " file=" + mScanningPath);
                    Slog.w(TAG, "*************************************************");
                    mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
                    return null;
                }

                // Set up information for our fall-back user intent resolution
                
// activity.
                mPlatformPackage = pkg;
                pkg.mVersionCode = mSdkVersion;
                mAndroidApplication = pkg.applicationInfo;
                mResolveActivity.applicationInfo = mAndroidApplication;
                mResolveActivity.name = ResolverActivity.class.getName();
                mResolveActivity.packageName = mAndroidApplication.packageName;
                mResolveActivity.processName = "system:ui";
                mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
                mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
                mResolveActivity.exported = true;
                mResolveActivity.enabled = true;
                mResolveInfo.activityInfo = mResolveActivity;
                mResolveInfo.priority = 0;
                mResolveInfo.preferredOrder = 0;
                mResolveInfo.match = 0;
                mResolveComponentName = new ComponentName(
                        mAndroidApplication.packageName, mResolveActivity.name);
            }
        }

        if (DEBUG_PACKAGE_SCANNING) {
            if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                Log.d(TAG, "Scanning package " + pkg.packageName);
        }

        if (mPackages.containsKey(pkg.packageName)
                || mSharedLibraries.containsKey(pkg.packageName)) {
            Slog.w(TAG, "Application package " + pkg.packageName
                    + " already installed.  Skipping duplicate.");
            mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
            return null;
        }

        // Initialize package source and resource directories
        File destCodeFile = new File(pkg.applicationInfo.sourceDir);
        File destResourceFile = new File(pkg.applicationInfo.publicSourceDir);

        SharedUserSetting suid = null;
        PackageSetting pkgSetting = null;

        if (!isSystemApp(pkg)) {
            // Only system apps can use these features.
            pkg.mOriginalPackages = null;
            pkg.mRealPackage = null;
            pkg.mAdoptPermissions = null;
        }

        // writer
        synchronized (mPackages) {
            // Check all shared libraries and map to their actual file path.
            if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
                if (mTmpSharedLibraries == null ||
                        mTmpSharedLibraries.length < mSharedLibraries.size()) {
                    mTmpSharedLibraries = new String[mSharedLibraries.size()];
                }
                int num = 0;
                int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
                for (int i=0; i<N; i++) {
                    final String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
                    if (file == null) {
                        Slog.e(TAG, "Package " + pkg.packageName
                                + " requires unavailable shared library "
                                + pkg.usesLibraries.get(i) + "; failing!");
                        mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
                        return null;
                    }
                    mTmpSharedLibraries[num] = file;
                    num++;
                }
                N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
                for (int i=0; i<N; i++) {
                    final String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
                    if (file == null) {
                        Slog.w(TAG, "Package " + pkg.packageName
                                + " desires unavailable shared library "
                                + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
                    } else {
                        mTmpSharedLibraries[num] = file;
                        num++;
                    }
                }
                if (num > 0) {
                    pkg.usesLibraryFiles = new String[num];
                    System.arraycopy(mTmpSharedLibraries, 0,
                            pkg.usesLibraryFiles, 0, num);
                }
            }

            if (pkg.mSharedUserId != null) {
                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId,
                        pkg.applicationInfo.flags, true);
                if (suid == null) {
                    Slog.w(TAG, "Creating application package " + pkg.packageName
                            + " for shared user failed");
                    mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                    return null;
                }
                if (DEBUG_PACKAGE_SCANNING) {
                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                        Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
                                + "): packages=" + suid.packages);
                }
            }
            
            // Check if we are renaming from an original package name.
            PackageSetting origPackage = null;
            String realName = null;
            if (pkg.mOriginalPackages != null) {
                // This package may need to be renamed to a previously
                
// installed name.  Let's check on that
                final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
                if (pkg.mOriginalPackages.contains(renamed)) {
                    // This package had originally been installed as the
                    
// original name, and we have already taken care of
                    
// transitioning to the new one.  Just update the new
                    
// one to continue using the old name.
                    realName = pkg.mRealPackage;
                    if (!pkg.packageName.equals(renamed)) {
                        // Callers into this function may have already taken
                        
// care of renaming the package; only do it here if
                        
// it is not already done.
                        pkg.setPackageName(renamed);
                    }
                    
                } else {
                    for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
                        if ((origPackage = mSettings.peekPackageLPr(
                                pkg.mOriginalPackages.get(i))) != null) {
                            // We do have the package already installed under its
                            
// original name  should we use it?
                            if (!verifyPackageUpdateLPr(origPackage, pkg)) {
                                // New package is not compatible with original.
                                origPackage = null;
                                continue;
                            } else if (origPackage.sharedUser != null) {
                                // Make sure uid is compatible between packages.
                                if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
                                    Slog.w(TAG, "Unable to migrate data from " + origPackage.name
                                            + " to " + pkg.packageName + ": old uid "
                                            + origPackage.sharedUser.name
                                            + " differs from " + pkg.mSharedUserId);
                                    origPackage = null;
                                    continue;
                                }
                            } else {
                                if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
                                        + pkg.packageName + " to old name " + origPackage.name);
                            }
                            break;
                        }
                    }
                }
            }
            
            if (mTransferedPackages.contains(pkg.packageName)) {
                Slog.w(TAG, "Package " + pkg.packageName
                        + " was transferred to another, but its .apk remains");
            }
            
            // Just create the setting, don't add it yet. For already existing packages
            
// the PkgSetting exists already and doesn't have to be created.
            pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
                    destResourceFile, pkg.applicationInfo.nativeLibraryDir,
                    pkg.applicationInfo.flags, user, false);
            if (pkgSetting == null) {
                Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
                mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                return null;
            }
            
            if (pkgSetting.origPackage != null) {
                // If we are first transitioning from an original package,
                
// fix up the new package's name now.  We need to do this after
                
// looking up the package under its new name, so getPackageLP
                
// can take care of fiddling things correctly.
                pkg.setPackageName(origPackage.name);
                
                // File a report about this.
                String msg = "New package " + pkgSetting.realName
                        + " renamed to replace old package " + pkgSetting.name;
                reportSettingsProblem(Log.WARN, msg);
                
                // Make a note of it.
                mTransferedPackages.add(origPackage.name);
                
                // No longer need to retain this.
                pkgSetting.origPackage = null;
            }
            
            if (realName != null) {
                // Make a note of it.
                mTransferedPackages.add(pkg.packageName);
            }
            
            if (mSettings.isDisabledSystemPackageLPr(pkg.packageName)) {
                pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
            }

            pkg.applicationInfo.uid = pkgSetting.appId;
            pkg.mExtras = pkgSetting;

            if (!verifySignaturesLP(pkgSetting, pkg)) {
                if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                    return null;
                }
                // The signature has changed, but this package is in the system
                
// image  let's recover!
                pkgSetting.signatures.mSignatures = pkg.mSignatures;
                // However  if this package is part of a shared user, but it
                
// doesn't match the signature of the shared user, let's fail.
                
// What this means is that you can't change the signatures
                
// associated with an overall shared user, which doesn't seem all
                
// that unreasonable.
                if (pkgSetting.sharedUser != null) {
                    if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
                            pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
                        Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
                        mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
                        return null;
                    }
                }
                // File a report about this.
                String msg = "System package " + pkg.packageName
                        + " signature changed; retaining data.";
                reportSettingsProblem(Log.WARN, msg);
            }

            // Verify that this new package doesn't have any content providers
            
// that conflict with existing packages.  Only do this if the
            
// package isn't already installed, since we don't want to break
            
// things that are installed.
            if ((scanMode&SCAN_NEW_INSTALL) != 0) {
                final int N = pkg.providers.size();
                int i;
                for (i=0; i<N; i++) {
                    PackageParser.Provider p = pkg.providers.get(i);
                    if (p.info.authority != null) {
                        String names[] = p.info.authority.split(";");
                        for (int j = 0; j < names.length; j++) {
                            if (mProviders.containsKey(names[j])) {
                                PackageParser.Provider other = mProviders.get(names[j]);
                                Slog.w(TAG, "Can't install because provider name " + names[j] +
                                        " (in package " + pkg.applicationInfo.packageName +
                                        ") is already used by "
                                        + ((other != null && other.getComponentName() != null)
                                                ? other.getComponentName().getPackageName() : "?"));
                                mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
                                return null;
                            }
                        }
                    }
                }
            }

            if (pkg.mAdoptPermissions != null) {
                // This package wants to adopt ownership of permissions from
                
// another package.
                for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
                    final String origName = pkg.mAdoptPermissions.get(i);
                    final PackageSetting orig = mSettings.peekPackageLPr(origName);
                    if (orig != null) {
                        if (verifyPackageUpdateLPr(orig, pkg)) {
                            Slog.i(TAG, "Adopting permissions from " + origName + " to "
                                    + pkg.packageName);
                            mSettings.transferPermissionsLPw(origName, pkg.packageName);
                        }
                    }
                }
            }
        }

        final String pkgName = pkg.packageName;
        
        final long scanFileTime = scanFile.lastModified();
        final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
        pkg.applicationInfo.processName = fixProcessName(
                pkg.applicationInfo.packageName,
                pkg.applicationInfo.processName,
                pkg.applicationInfo.uid);

        File dataPath;
        if (mPlatformPackage == pkg) {
            // The system package is special.
            dataPath = new File (Environment.getDataDirectory(), "system");
            pkg.applicationInfo.dataDir = dataPath.getPath();
        } else {
            // This is a normal package, need to make its data directory.
            dataPath = getDataPathForPackage(pkg.packageName, 0);

            boolean uidError = false;

            if (dataPath.exists()) {
                int currentUid = 0;
                try {
                    StructStat stat = Libcore.os.stat(dataPath.getPath());
                    currentUid = stat.st_uid;
                } catch (ErrnoException e) {
                    Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
                }

                // If we have mismatched owners for the data path, we have a problem.
                if (currentUid != pkg.applicationInfo.uid) {
                    boolean recovered = false;
                    if (currentUid == 0) {
                        // The directory somehow became owned by root.  Wow.
                        
// This is probably because the system was stopped while
                        
// installd was in the middle of messing with its libs
                        
// directory.  Ask installd to fix that.
                        int ret = mInstaller.fixUid(pkgName, pkg.applicationInfo.uid,
                                pkg.applicationInfo.uid);
                        if (ret >= 0) {
                            recovered = true;
                            String msg = "Package " + pkg.packageName
                                    + " unexpectedly changed to uid 0; recovered to " +
                                    + pkg.applicationInfo.uid;
                            reportSettingsProblem(Log.WARN, msg);
                        }
                    }
                    if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
                            || (scanMode&SCAN_BOOTING) != 0)) {
                        // If this is a system app, we can at least delete its
                        
// current data so the application will still work.
                        int ret = removeDataDirsLI(pkgName);
                        if (ret >= 0) {
                            // TODO: Kill the processes first
                            
// Old data gone!
                            String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
                                    ? "System package " : "Third party package ";
                            String msg = prefix + pkg.packageName
                                    + " has changed from uid: "
                                    + currentUid + " to "
                                    + pkg.applicationInfo.uid + "; old data erased";
                            reportSettingsProblem(Log.WARN, msg);
                            recovered = true;

                            // And now re-install the app.
                            ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
                            if (ret == -1) {
                                // Ack should not happen!
                                msg = prefix + pkg.packageName
                                        + " could not have data directory re-created after delete.";
                                reportSettingsProblem(Log.WARN, msg);
                                mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                                return null;
                            }
                        }
                        if (!recovered) {
                            mHasSystemUidErrors = true;
                        }
                    } else if (!recovered) {
                        // If we allow this install to proceed, we will be broken.
                        
// Abort, abort!
                        mLastScanError = PackageManager.INSTALL_FAILED_UID_CHANGED;
                        return null;
                    }
                    if (!recovered) {
                        pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
                            + pkg.applicationInfo.uid + "/fs_"
                            + currentUid;
                        pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
                        String msg = "Package " + pkg.packageName
                                + " has mismatched uid: "
                                + currentUid + " on disk, "
                                + pkg.applicationInfo.uid + " in settings";
                        // writer
                        synchronized (mPackages) {
                            mSettings.mReadMessages.append(msg);
                            mSettings.mReadMessages.append('\n');
                            uidError = true;
                            if (!pkgSetting.uidError) {
                                reportSettingsProblem(Log.ERROR, msg);
                            }
                        }
                    }
                }
                pkg.applicationInfo.dataDir = dataPath.getPath();
            } else {
                if (DEBUG_PACKAGE_SCANNING) {
                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                        Log.v(TAG, "Want this data dir: " + dataPath);
                }
                //invoke installer to do the actual installation
                int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
                if (ret < 0) {
                    // Error from installer
                    mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                    return null;
                }

                if (dataPath.exists()) {
                    pkg.applicationInfo.dataDir = dataPath.getPath();
                } else {
                    Slog.w(TAG, "Unable to create data directory: " + dataPath);
                    pkg.applicationInfo.dataDir = null;
                }
            }

            /*
             * Set the data dir to the default "/data/data/<package name>/lib"
             * if we got here without anyone telling us different (e.g., apps
             * stored on SD card have their native libraries stored in the ASEC
             * container with the APK).
             *
             * This happens during an upgrade from a package settings file that
             * doesn't have a native library path attribute at all.
             
*/
            if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
                if (pkgSetting.nativeLibraryPathString == null) {
                    setInternalAppNativeLibraryPath(pkg, pkgSetting);
                } else {
                    pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
                }
            }

            pkgSetting.uidError = uidError;
        }

        String path = scanFile.getPath();
        /* Note: We don't want to unpack the native binaries for
         *        system applications, unless they have been updated
         *        (the binaries are already under /system/lib).
         *        Also, don't unpack libs for apps on the external card
         *        since they should have their libraries in the ASEC
         *        container already.
         *
         *        In other words, we're going to unpack the binaries
         *        only for non-system apps and system app upgrades.
         
*/
        if (pkg.applicationInfo.nativeLibraryDir != null) {
            try {
                File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
                final String dataPathString = dataPath.getCanonicalPath();

                if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
                    /*
                     * Upgrading from a previous version of the OS sometimes
                     * leaves native libraries in the /data/data/<app>/lib
                     * directory for system apps even when they shouldn't be.
                     * Recent changes in the JNI library search path
                     * necessitates we remove those to match previous behavior.
                     
*/
                    if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
                        Log.i(TAG, "removed obsolete native libraries for system package "
                                + path);
                    }
                } else {
                    if (!isForwardLocked(pkg) && !isExternal(pkg)) {
                        /*
                         * Update native library dir if it starts with
                         * /data/data
                         
*/
                        if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
                            setInternalAppNativeLibraryPath(pkg, pkgSetting);
                            nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
                        }

                        try {
                            if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
                                Slog.e(TAG, "Unable to copy native libraries");
                                mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                                return null;
                            }
                        } catch (IOException e) {
                            Slog.e(TAG, "Unable to copy native libraries", e);
                            mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                            return null;
                        }
                    }

                    if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
                    final int[] userIds = sUserManager.getUserIds();
                    synchronized (mInstallLock) {
                        for (int userId : userIds) {
                            if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
                                    pkg.applicationInfo.nativeLibraryDir, userId) < 0) {
                                Slog.w(TAG, "Failed linking native library dir (user=" + userId
                                        + ")");
                                mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                                return null;
                            }
                        }
                    }
                }
            } catch (IOException ioe) {
                Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
            }
        }
        pkg.mScanPath = path;

        if ((scanMode&SCAN_NO_DEX) == 0) {
            if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0)
                    == DEX_OPT_FAILED) {
                mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
                return null;
            }
        }

        if (mFactoryTest && pkg.requestedPermissions.contains(
                android.Manifest.permission.FACTORY_TEST)) {
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
        }

        // Request the ActivityManager to kill the process(only for existing packages)
        
// so that we do not end up in a confused state while the user is still using the older
        
// version of the application while the new one gets installed.
        if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
            killApplication(pkg.applicationInfo.packageName,
                        pkg.applicationInfo.uid);
        }

        // writer
        synchronized (mPackages) {
            // We don't expect installation to fail beyond this point,
            if ((scanMode&SCAN_MONITOR) != 0) {
                mAppDirs.put(pkg.mPath, pkg);
            }
            // Add the new setting to mSettings
            mSettings.insertPackageSettingLPw(pkgSetting, pkg);
            // Add the new setting to mPackages
            mPackages.put(pkg.applicationInfo.packageName, pkg);
            // Make sure we don't accidentally delete its data.
            final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
            while (iter.hasNext()) {
                PackageCleanItem item = iter.next();
                if (pkgName.equals(item.packageName)) {
                    iter.remove();
                }
            }

            // Take care of first install / last update times.
            if (currentTime != 0) {
                if (pkgSetting.firstInstallTime == 0) {
                    pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
                } else if ((scanMode&SCAN_UPDATE_TIME) != 0) {
                    pkgSetting.lastUpdateTime = currentTime;
                }
            } else if (pkgSetting.firstInstallTime == 0) {
                // We need *something*.  Take time time stamp of the file.
                pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
            } else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
                if (scanFileTime != pkgSetting.timeStamp) {
                    // A package on the system image has changed; consider this
                    
// to be an update.
                    pkgSetting.lastUpdateTime = scanFileTime;
                }
            }

            int N = pkg.providers.size();
            StringBuilder r = null;
            int i;
            for (i=0; i<N; i++) {
                PackageParser.Provider p = pkg.providers.get(i);
                p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        p.info.processName, pkg.applicationInfo.uid);
                mProvidersByComponent.put(new ComponentName(p.info.packageName,
                        p.info.name), p);
                p.syncable = p.info.isSyncable;
                if (p.info.authority != null) {
                    String names[] = p.info.authority.split(";");
                    p.info.authority = null;
                    for (int j = 0; j < names.length; j++) {
                        if (j == 1 && p.syncable) {
                            // We only want the first authority for a provider to possibly be
                            
// syncable, so if we already added this provider using a different
                            
// authority clear the syncable flag. We copy the provider before
                            
// changing it because the mProviders object contains a reference
                            
// to a provider that we don't want to change.
                            
// Only do this for the second authority since the resulting provider
                            
// object can be the same for all future authorities for this provider.
                            p = new PackageParser.Provider(p);
                            p.syncable = false;
                        }
                        if (!mProviders.containsKey(names[j])) {
                            mProviders.put(names[j], p);
                            if (p.info.authority == null) {
                                p.info.authority = names[j];
                            } else {
                                p.info.authority = p.info.authority + ";" + names[j];
                            }
                            if (DEBUG_PACKAGE_SCANNING) {
                                if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                                    Log.d(TAG, "Registered content provider: " + names[j]
                                            + ", className = " + p.info.name + ", isSyncable = "
                                            + p.info.isSyncable);
                            }
                        } else {
                            PackageParser.Provider other = mProviders.get(names[j]);
                            Slog.w(TAG, "Skipping provider name " + names[j] +
                                    " (in package " + pkg.applicationInfo.packageName +
                                    "): name already used by "
                                    + ((other != null && other.getComponentName() != null)
                                            ? other.getComponentName().getPackageName() : "?"));
                        }
                    }
                }
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(p.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Providers: " + r);
            }

            N = pkg.services.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Service s = pkg.services.get(i);
                s.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        s.info.processName, pkg.applicationInfo.uid);
                mServices.addService(s);
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(s.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Services: " + r);
            }

            N = pkg.receivers.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.receivers.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                mReceivers.addActivity(a, "receiver");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Receivers: " + r);
            }

            N = pkg.activities.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.activities.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                mActivities.addActivity(a, "activity");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Activities: " + r);
            }

            N = pkg.permissionGroups.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
                PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
                if (cur == null) {
                    mPermissionGroups.put(pg.info.name, pg);
                    if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                        if (r == null) {
                            r = new StringBuilder(256);
                        } else {
                            r.append(' ');
                        }
                        r.append(pg.info.name);
                    }
                } else {
                    Slog.w(TAG, "Permission group " + pg.info.name + " from package "
                            + pg.info.packageName + " ignored: original from "
                            + cur.info.packageName);
                    if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                        if (r == null) {
                            r = new StringBuilder(256);
                        } else {
                            r.append(' ');
                        }
                        r.append("DUP:");
                        r.append(pg.info.name);
                    }
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permission Groups: " + r);
            }

            N = pkg.permissions.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Permission p = pkg.permissions.get(i);
                HashMap<String, BasePermission> permissionMap =
                        p.tree ? mSettings.mPermissionTrees
                        : mSettings.mPermissions;
                p.group = mPermissionGroups.get(p.info.group);
                if (p.info.group == null || p.group != null) {
                    BasePermission bp = permissionMap.get(p.info.name);
                    if (bp == null) {
                        bp = new BasePermission(p.info.name, p.info.packageName,
                                BasePermission.TYPE_NORMAL);
                        permissionMap.put(p.info.name, bp);
                    }
                    if (bp.perm == null) {
                        if (bp.sourcePackage == null
                                || bp.sourcePackage.equals(p.info.packageName)) {
                            BasePermission tree = findPermissionTreeLP(p.info.name);
                            if (tree == null
                                    || tree.sourcePackage.equals(p.info.packageName)) {
                                bp.packageSetting = pkgSetting;
                                bp.perm = p;
                                bp.uid = pkg.applicationInfo.uid;
                                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                                    if (r == null) {
                                        r = new StringBuilder(256);
                                    } else {
                                        r.append(' ');
                                    }
                                    r.append(p.info.name);
                                }
                            } else {
                                Slog.w(TAG, "Permission " + p.info.name + " from package "
                                        + p.info.packageName + " ignored: base tree "
                                        + tree.name + " is from package "
                                        + tree.sourcePackage);
                            }
                        } else {
                            Slog.w(TAG, "Permission " + p.info.name + " from package "
                                    + p.info.packageName + " ignored: original from "
                                    + bp.sourcePackage);
                        }
                    } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                        if (r == null) {
                            r = new StringBuilder(256);
                        } else {
                            r.append(' ');
                        }
                        r.append("DUP:");
                        r.append(p.info.name);
                    }
                    if (bp.perm == p) {
                        bp.protectionLevel = p.info.protectionLevel;
                    }
                } else {
                    Slog.w(TAG, "Permission " + p.info.name + " from package "
                            + p.info.packageName + " ignored: no group "
                            + p.group);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Permissions: " + r);
            }

            N = pkg.instrumentation.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Instrumentation a = pkg.instrumentation.get(i);
                a.info.packageName = pkg.applicationInfo.packageName;
                a.info.sourceDir = pkg.applicationInfo.sourceDir;
                a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
                a.info.dataDir = pkg.applicationInfo.dataDir;
                a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
                mInstrumentation.put(a.getComponentName(), a);
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);
            }

            if (pkg.protectedBroadcasts != null) {
                N = pkg.protectedBroadcasts.size();
                for (i=0; i<N; i++) {
                    mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
                }
            }

            pkgSetting.setTimeStamp(scanFileTime);
        }

        return pkg;
    }
10.删除已经不存在程序对应的数据记录.mPackages保存了以上三个目录下程序文件的列表,mSettings.mPackages中保存了安装后的数据记录,因此,如果mPackages.contain()函数返回false,则意味着以上三个目录下的某个程序已经被手工删除,于是会删除对应的记录.
// Prune any system packages that no longer exist.
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * If this is not a system app, it can't be a
                     * disable system app.
                     
*/
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }

                    /*
                     * If the package is scanned, it's not erased.
                     
*/
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) {
                        /*
                         * If the system app is both scanned and in the
                         * disabled packages list, then it must have been
                         * added via OTA. Remove it from the currently
                         * scanned package so the previously user-installed
                         * application can be scanned.
                         
*/
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            Slog.i(TAG, "Expecting better updatd system app for " + ps.name
                                    + "; removing system app");
                            removePackageLI(ps, true);
                        }

                        continue;
                    }

                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        String msg = "System package " + ps.name
                                + " no longer exists; wiping its data";
                        reportSettingsProblem(Log.WARN, msg);
                        removeDataDirsLI(ps.name);
                    } else {
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }

11.清除没有安装成功的数据记录.调用mSettings的getListOfIncompleteInstallPackages()函数获取没有安装成功的程序包列表,然后使用for循环,调用cleanupInstallFailedPackage()逐个清除这些记录.
            //look for any incomplete package installations
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            //clean up list
            for(int i = 0; i < deletePkgsList.size(); i++) {
                //clean up here
                cleanupInstallFailedPackage(deletePkgsList.get(i));
            }
            //delete tmp files
            deleteTempPackageFiles();

 1 void cleanupInstallFailedPackage(PackageSetting ps) {
 2         Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
 3         removeDataDirsLI(ps.name);
 4         if (ps.codePath != null) {
 5             if (!ps.codePath.delete()) {
 6                 Slog.w(TAG, "Unable to remove old code file: " + ps.codePath);
 7             }
 8         }
 9         if (ps.resourcePath != null) {
10             if (!ps.resourcePath.delete() && !ps.resourcePath.equals(ps.codePath)) {
11                 Slog.w(TAG, "Unable to remove old code file: " + ps.resourcePath);
12             }
13         }
14         mSettings.removePackageLPw(ps.name);
15     }
12.调用deleteTemppackageFiles()删除/data/app目录下的以vmdl开头以及.tmp结尾的文件.
private void deleteTempPackageFiles() {
        final FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.startsWith("vmdl") && name.endsWith(".tmp");
            }
        };
        deleteTempPackageFilesInDirectory(mAppInstallDir, filter);
        deleteTempPackageFilesInDirectory(mDrmAppPrivateInstallDir, filter);
    }

    private static final void deleteTempPackageFilesInDirectory(File directory,
            FilenameFilter filter) {
        final String[] tmpFilesList = directory.list(filter);
        if (tmpFilesList == null) {
            return;
        }
        for (int i = 0; i < tmpFilesList.length; i++) {
            final File tmpFile = new File(directory, tmpFilesList[i]);
            tmpFile.delete();
        }
    }

13.为以下两个第三方程序目录分别添加FileObserver,并调用scanDirLI()解析目录下的所有应用程序,解析结果将保存到mPackages变量中.
/data/app:普通应用程序目录.
/data/app-private:暂时没有被使用

if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                mAppInstallObserver = new AppDirObserver(
                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
                mAppInstallObserver.startWatching();
                scanDirLI(mAppInstallDir, 0, scanMode, 0);
    
                mDrmAppInstallObserver = new AppDirObserver(
                    mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
                mDrmAppInstallObserver.startWatching();
                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                        scanMode, 0);

                /**
                 * Remove disable package settings for any updated system
                 * apps that were removed via an OTA. If they're not a
                 * previously-updated app, remove them completely.
                 * Otherwise, just revoke their system-level permissions.
                 
*/
                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                    String msg;
                    if (deletedPkg == null) {
                        msg = "Updated system package " + deletedAppName
                                + " no longer exists; wiping its data";
                        removeDataDirsLI(deletedAppName);
                    } else {
                        msg = "Updated system app + " + deletedAppName
                                + " no longer present; removing system privileges for "
                                + deletedAppName;

                        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

                        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                    }
                    reportSettingsProblem(Log.WARN, msg);
                }
            } else {
                mAppInstallObserver = null;
                mDrmAppInstallObserver = null;
            }

14.如果系统版本升级,调用upatePermissionLPw()重新为应用程序赋予权限.原因是升级可能会定义一些新的权限,为了保证已经安装过的程序保持原有权限,则需要重新赋予新的权限.
15.调用mSettings.writeLPr()将mSettings.mPackages中的数据重新写入packages.xml文件中.
            // If the platform SDK has changed since the last time we booted,
            
// we need to re-grant app permission to catch any new ones that
            
// appear.  This is really a hack, and means that apps can in some
            
// cases get permissions that the user didn't initially explicitly
            
// allow  it would be nice to have some better way to handle
            
// this situation.
            final boolean regrantPermissions = mSettings.mInternalSdkPlatform
                    != mSdkVersion;
            if (regrantPermissions) Slog.i(TAG, "Platform changed from "
                    + mSettings.mInternalSdkPlatform + " to " + mSdkVersion
                    + "; regranting permissions for internal storage");
            mSettings.mInternalSdkPlatform = mSdkVersion;
            
            updatePermissionsLPw(nullnull, UPDATE_PERMISSIONS_ALL
                    | (regrantPermissions
                            ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
                            : 0));

            // can downgrade to reader
            mSettings.writeLPr();

部分函数内部详情

readPermissions()

流程图

代码
void readPermissions() {
        // Read permissions from /etc/permission directory.
        File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
            Slog.w(TAG, "No directory " + libraryDir + ", skipping");
            return;
        }
        if (!libraryDir.canRead()) {
            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
            return;
        }

        // Iterate over the files in the directory and scan .xml files
        for (File f : libraryDir.listFiles()) {
            // We'll read platform.xml last
            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
                continue;
            }

            if (!f.getPath().endsWith(".xml")) {
                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
                continue;
            }
            if (!f.canRead()) {
                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
                continue;
            }

            readPermissionsFromXml(f);
        }

private void readPermissionsFromXml(File permFile) {
        FileReader permReader = null;
        try {
            permReader = new FileReader(permFile);
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
            return;
        }

        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(permReader);

            XmlUtils.beginDocument(parser, "permissions");

            while (true) {
                XmlUtils.nextElement(parser);
                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
                    break;
                }

                String name = parser.getName();
                if ("group".equals(name)) {
                    String gidStr = parser.getAttributeValue(null, "gid");
                    if (gidStr != null) {
                        int gid = Integer.parseInt(gidStr);
                        mGlobalGids = appendInt(mGlobalGids, gid);
                    } else {
                        Slog.w(TAG, "<group> without gid at "
                                + parser.getPositionDescription());
                    }

                    XmlUtils.skipCurrentTag(parser);
                    continue;
                } else if ("permission".equals(name)) {
                    String perm = parser.getAttributeValue(null, "name");
                    if (perm == null) {
                        Slog.w(TAG, "<permission> without name at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    perm = perm.intern();
                    readPermission(parser, perm);

                } else if ("assign-permission".equals(name)) {
                    String perm = parser.getAttributeValue(null, "name");
                    if (perm == null) {
                        Slog.w(TAG, "<assign-permission> without name at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    String uidStr = parser.getAttributeValue(null, "uid");
                    if (uidStr == null) {
                        Slog.w(TAG, "<assign-permission> without uid at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    int uid = Process.getUidForName(uidStr);
                    if (uid < 0) {
                        Slog.w(TAG, "<assign-permission> with unknown uid \""
                                + uidStr + "\" at "
                                + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    perm = perm.intern();
                    HashSet<String> perms = mSystemPermissions.get(uid);
                    if (perms == null) {
                        perms = new HashSet<String>();
                        mSystemPermissions.put(uid, perms);
                    }
                    perms.add(perm);
                    XmlUtils.skipCurrentTag(parser);

                } else if ("library".equals(name)) {
                    String lname = parser.getAttributeValue(null, "name");
                    String lfile = parser.getAttributeValue(null, "file");
                    if (lname == null) {
                        Slog.w(TAG, "<library> without name at "
                                + parser.getPositionDescription());
                    } else if (lfile == null) {
                        Slog.w(TAG, "<library> without file at "
                                + parser.getPositionDescription());
                    } else {
                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
                        mSharedLibraries.put(lname, lfile);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else if ("feature".equals(name)) {
                    String fname = parser.getAttributeValue(null, "name");
                    if (fname == null) {
                        Slog.w(TAG, "<feature> without name at "
                                + parser.getPositionDescription());
                    } else {
                        //Log.i(TAG, "Got feature " + fname);
                        FeatureInfo fi = new FeatureInfo();
                        fi.name = fname;
                        mAvailableFeatures.put(fname, fi);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } else {
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }

            }
            permReader.close();
        } catch (XmlPullParserException e) {
            Slog.w(TAG, "Got execption parsing permissions.", e);
        } catch (IOException e) {
            Slog.w(TAG, "Got execption parsing permissions.", e);
        }
    }

1.确保/ststem/etc/permissions目录存在
2.使用for()循环,读取目录下的每一个XML文件,并调用readPermissionFromXml()函数逐个解析每一个XML文件,for()循环读取中跳过platform.xml文件.一般情况下,除了platform.xml文件外,其他XML文件仅仅定义了一些系统feature,包括features.xml、handleheld_core_hardware.xml、android.hardware.wifi.xml等,平台设计人员可以在该目录下添加任意命名的XML文件描述平台所拥有的feature.这些feature的名称原理上是任意的,但是Android的Market会解析应用程序中所包含的feature,因此,feature命名建议遵守共同的约定.比如,以下为几个常见的feature名称.





备注:本文章中的代码仅为参考,版本为4.2.2,代码会与3.0之前的版本有所不同.功能没有太大变化,有部分新功能的加入,具体内容请遵照对应版本
参考资料
http://www.educity.cn/wenda/179359.html 

posted on 2016-03-02 11:49 ZC小栏 阅读(1490) 评论(0)  编辑  收藏 所属分类: 学习小记


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2025年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

统计

留言簿

文章分类

文章档案

搜索

最新评论