Android——Framework之Packamanager深析

今天我们来介绍下,同为Framework层的Packagemanager类(基于Android2.3.3源码分析),首先我们也先来看一下他的框架结构,之后再进行分析。

                      

                                                         上图为Packagemanager框架图.‘

Pacakgemanager是一个抽象类,

源码:

public abstract class PackageManager { }

实现PackageManager抽象类的是ContextImpl类,在ContextImpl类中有一个静态子类ApplicationPackageManage继承自PackageManager.

代码:static final class ApplicationPackageManager extends PackageManager

所以我们在程序中通过getPackageManager获取的对象是ApplicationPackageManager。ApplicationPackageManager又通过对

IPackageManager的封装调用来实现的。

源码:

@Override
    public PackageInfo getPackageInfo(String packageName, int flags)
            throws NameNotFoundException {
        try {
            PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId());
            if (pi != null) {
                return pi;
            }
        } catch (RemoteException e) {
            throw new RuntimeException("Package manager has died", e);
        throw new NameNotFoundException(packageName);
    }

 private final IPackageManager mPM;

PackageManager框架中也利用了Proxy模式,即IPackageManager接口定义了所有PackageManager框架的操作,

IPackageManager.Stub.Proxy实现了接口IPackageManager,但并不真正实现这些方法,它只是一个代理类,

真正动作的执行为IPackageManager.Stub类的子类PackageManagerService,

这样我们就理顺了,PackageManager框架的流程结构。

下面来介绍下 PackageManager常用方法:

        public abstract PackageManager getPackageManager()

               功能:获得一个PackageManger对象

        public abstract Drawable    getApplicationIcon(String packageName)

               参数: packageName 包名

               功能:返回给定包名的图标,否则返回null

        public abstract ApplicationInfo getApplicationInfo(String packageName, int flags)

               参数:packagename 包名

                     flags 该ApplicationInfo是此flags标记,通常可以直接赋予常数0即可

               功能:返回该ApplicationInfo对象

        public abstract List<ApplicationInfo>  getInstalledApplications(int flags)

               参数:flag为一般为GET_UNINSTALLED_PACKAGES,那么此时会返回所有ApplicationInfo。我们可以对ApplicationInfo的flags过滤,得到我们需要的。

               功能:返回给定条件的所有PackageInfo

       public abstract  List<ResolveInfo>  queryIntentActivities(Intent intent, int flags)

               参数:intent 查寻条件,Activity所配置的action和category

                    flags: MATCH_DEFAULT_ONLY:Category必须带有CATEGORY_DEFAULT的Activity,才匹配

                    GET_INTENT_FILTERS :匹配Intent条件即可

                    GET_RESOLVED_FILTER    :匹配Intent条件即可

               功能 :返回给定条件的所有ResolveInfo对象(本质上是Activity),集合对象

以上是一些PackageManager的方法,这里面还牵扯到PackageItemInfo类,AcitivityInfo类等,我们就不一一说了,有兴趣的同学可以自己看看。现在具体说一下最后一个方法,从而引出PackageManagerService,我们先来看看源码:

public List<ResolveInfo> queryIntentActivities(Intent intent,int flags) {
           try {
                   return mPM.queryIntentActivities(//mPM是IPackageManager.Stub.Proxy对象
                   intent,intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                   flags);
           } catch (RemoteException e) {

               throw new RuntimeException("Package manager has died", e);
           }
       }

前面我们讲过了,这个方法的具体的执行操作其实是由PackageManagerService来完成的。PackageManagerService是一个很重要的工具类。PackageManagerService的启动流程分析:

PackageManagerService的构建:在system_process进程加载时,PackageManagerService就被创建了。在SystemServer.ServerThread.run中有如下一段代码:

 pm = PackageManagerService.main(context,factoryTest != SystemServer.FACTORY_TEST_OFF);//启动PackageManagerService
它就是加载  PackageManagerService的,在 PackageManagerService中有一个静态方法:main()函数:
    源代码:

           public static final IPackageManager main(Context context, boolean factoryTest) {
                      PackageManagerService m = new PackageManagerService(context, factoryTest);
                      ServiceManager.addService("package", m);
                      return m;
           }

这个方法生成一个IPackageManager接口,也就是PackageManagerService。

在PackageManagerService初始化的时候,会建立 java 层的 installer 与 c 层的 installd 的 socket 联接,使得在上层的 install,remove,dexopt等功能最终由 installd 在底层实现。

源码: //建立 installer 与 installd 的 socket 联接 

             Installer installer = new Installer(); 
             installer.ping() && Process.supportsProcesses(); 
             installd 完成以下一些命令 
             struct cmdinfo cmds[] = { 
                 { "ping",             0, do_ping }, 
                 { "install",          3, do_install }, 
                 { "dexopt",          3, do_dexopt }, 
                 { "movedex",          2, do_move_dex }, 
                 { "rmdex",            1, do_rm_dex }, 
                 { "remove",           1, do_remove }, 
                 { "rename",          2, do_rename }, 
                 { "freecache",       1, do_free_cache }, 
                 { "rmcache",               1, do_rm_cache }, 
                 { "protect",               2, do_protect }, 
                 { "getsize",               3, do_get_size }, 
                 { "rmuserdata",           1, do_rm_user_data }, 
                 { "movefiles",         0, do_movefiles }, 
           }; 

接下来会建立PackageHandler。 用 于 处 理 外 部 的 apk 安 装 请 求 消 息 , 如 adbinstall,packageinstaller 安装 apk 时会发送消息 。

            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());

处理的消息:

    static final int SEND_PENDING_BROADCAST = 1;

    static final int MCS_BOUND = 3;

    static final int END_COPY = 4;

    static final int INIT_COPY = 5;

          static final int MCS_UNBIND = 6;
      
          static final int START_CLEANING_PACKAGE = 7;
      
          static final int FIND_INSTALL_LOC = 8;
      
          static final int POST_INSTALL = 9;
      
          static final int MCS_RECONNECT = 10;
      
          static final int MCS_GIVE_UP = 11;
      
          static final int UPDATED_MEDIA_STATUS = 12;
      
          static final int WRITE_SETTINGS = 13;

 再继续就是解析/system/etc/permission 下 xml 文件(framework/base/data/etc/),

源码:

       // 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);

这里面包括platform.xml和系统支持的各种硬件模块的feature.主要工作:

(1) 建立底层 user ids 和 group ids 同上层 permissions 之间的映射;可以指定一个权限与几个组 ID 对应。当一个 APK 被授予这个权限时,它也同时属于这几个组。

(2) 给一些底层用户分配权限,如给 shell 授予各种 permission 权限;把一个权限赋予一个UID,当进程使用这个 UID 运行时,就具备了这个权限。 

(3) library,系统增加的一些应用需要 link 的扩展 jar 库; 

(4) feature, 系 统 每 增 加 一 个 硬 件 , 都 要 添 加 相 应 的 feature. 将 解 析 结 果mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures  等几个集合中供系统查询和权限配置使用。 

接下来这行代码mSettings.readLP():

会判断/data/system/packages.xml 文件是否存在,如果不存在则返回 false,如果存在则进行解析,在系统第一次启动时 packages.xml 文件是不存在的,由 writeLP()创建该文件,文件里面记录了系统的permissions,以及每个apk的name,codePath,flags,ts,version,uesrid等信息,这些信息主要通过apk的AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk升级,安装或删除时会更新这个文件。解析的过程即是按照 xml定义的标签,将对应的属性和值添加到全局列表中。

再继续就是检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt。

检查BootClassPath是否需要dexopt,如果需要先将文件添加到 libFiles 里,同时 进 行 dexopt

源码:

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, "Exception reading boot class path: " + paths[i], e);
                        }
                    }
                } else {
                    Slog.w(TAG, "No BOOTCLASSPATH found!");
                }

检查mSharedLibraries是否需要dexopt,如果需要先将文件添加到 libFiles 里,同时 进 行 dexopt

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, "Exception reading library: " + lib, e);
                     }
                 }
              }

对 framework-res.apk 不进行 dexopt 直接添加到 libFiles 
           libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk"); 
     再继续启动 AppDirObserver 线程监测/system/framework,/system/app,/data/app,/data/app-private 目录的事件,目录监听底层通过inotify 机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。

mFrameworkInstallObserver = new AppDirObserver(mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
           mFrameworkInstallObserver.startWatching();

再继续就是对以上几个目录下的apk进行逐个解析:调用 scanDirLI 解析,该函数是包管理服务的重要函数。

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 (false) {
                 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);
               // 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();
            }
        }
    }

//对于不存在的 system apk 调用以下函数删除掉 

Iterator psit = mSettings.mPackages.values().iterator(); 

 PackageSetting ps = psit.next(); 

      if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 
                         &&!mPackages.containsKey(ps.name) 
                         && !mSettings.mDisabledSysPackages.containsKey(ps.name)) 
      { 
           psit.remove(); 
           mInstaller.remove(ps.name); 
      }

最后是解析完以上目录下的 apk 后,更新应用的权限 。

updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions); 

mSettings.writeLP(); 会 生 成 packages.xml 和 packages.list 文 件 ,packages.list 的 数 据 格 式 是 :pkgName,userId,debugFlag,dataPath(包的数据路径),packages.xml 保存了每个已经安 装 apk 的详尽的信息 。

 以上就是PackageManagerService从系统启动时所做的全部工作,下面再给大家贴一张整体流程的图:







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值