android系統啓動之package掃描

基於android5.1的源碼進行分析,源碼是上游廠商提供,所以和google源生的代碼會有一些差異.
下面先來點系統掃描的堆棧:

java.lang.Throwable
    at com.android.server.pm.PackageManagerService.<init>(PackageManagerService.java:1325)
    at com.android.server.pm.PackageManagerService.main(PackageManagerService.java:1287)
    at com.android.server.SystemServer.startBootstrapServices(SystemServer.java:376)
    at com.android.server.SystemServer.run(SystemServer.java:275)
    at com.android.server.SystemServer.main(SystemServer.java:191)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:947)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:742)
Created with Raphaël 2.1.0SystemServer.mainSystemServer.runSystemServer.startBootstrapServicesPackageManagerService.mainPackageManagerService()結束

我們先來看看下面都有一些什麼東西值得我們去留意的

private void run() {
         .............
         /*設置當前時間,如果當前時間不是EARLIEST_SUPPORTED_TIME之後的,則把當前時間設置成EARLIEST_SUPPORTED_TIME的*/
         if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
              Slog.w(TAG, "System clock is before 1970; setting to 1970.");
              SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
          }
      ..........

          // Create the system service manager.
          mSystemServiceManager = new SystemServiceManager(mSystemContext);
          LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

          // Start services.
          try {
              startBootstrapServices(); //這個是我們重點關注的地方,後面將圍繞這個來展開
              startCoreServices();
              startOtherServices();
          } catch (Throwable ex) {
              Slog.e("System", "******************************************");
              Slog.e("System", "************ Failure starting system services", ex);
              throw ex;
          }
    ......................
      }

現在我們來重點關注: startBootstrapServices()裏面最主要的內容仍然是PackageManagerService(),下面,我們來看下 PackageManagerService()這個裏面到底有什麼東西.我是因爲重啓機器後launcher3的桌面widget會被刪除纔來分析這個地方的,所以關注的點就在這裏,所以有一些地方可能沒有關注到,所以 爲看官到時候可以在評論裏給出一些建議.

好,下面我們正式對這個部分的重點進行分析(注:我們只是對關鍵的地方進行分析和說明,一些和解決問題不你的地方可能會被過濾掉):
public PackageManagerService(Context context, Installer installer,
              boolean factoryTest, boolean onlyCore) {
        ...
        //獲取當前的模式,盤對是不能在是模式當中
    String mode = SystemProperties.get("ro.bootmode", "mode");
    //獲取當前的開機方式,power鍵+上下鍵方式和正常開機方式所進入的界面是不一樣的
    mFactoryTest = factoryTest;
        engModeEnable = "engtest".equals(mode) ? true : false;
    ...
    //獲得當前 不 debug版本的狀態,debugh和 user版本的狀態是完全不一樣的
    mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
    // TODO: add a property to control this?
    //創建SharedUserSetting對象並添加到Settings的成員變量mSharedUsers中,在Android系統中,多個package通過設置sharedUserId屬性可以運行在同一個進程,共享同一個UID*
    mSettings = new Settings(context);
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                  ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                  ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                  ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                  ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                  ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                  ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
        long dexOptLRUThresholdInMinutes;
        if (mLazyDexOpt) {
            dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
        } else {
            dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
        }
        mDexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;

    //
        String separateProcesses = SystemProperties.get("debug.separate_processes");
          if (separateProcesses != null && separateProcesses.length() > 0) {
              if ("*".equals(separateProcesses)) {
                  mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
                  mSeparateProcesses = null;
                  Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
              } else {
                  mDefParseFlags = 0;
                  mSeparateProcesses = separateProcesses.split(",");
                  Slog.w(TAG, "Running with debug.separate_processes: "
                          + separateProcesses);
              }
          } else {
              mDefParseFlags = 0;
              mSeparateProcesses = null;
          }
    ...
    mInstaller = installer; //創建應用安裝器 
    ...
    //下面段代碼,我們知道,主要是掃描app-private這個目錄的,掃描更新service裏面的信息,在launcher3中掃描安裝widget的時候,對比包中就是使用這裏的信息進行對比 ,這個掃描更新的信息沒有存入到package數據庫裏面的話,widget將會刪除信息相應的widget.widget對比中之所以會被刪除,是因爲launcher的啓動速度比掃描服務來得更早和更快,所以造成package數據庫裏面有沒有相應的包信息.
    final File drmInstallDir = new File("/data/app-private/");
        new Thread("drmapp"){
             @Override
             public void run() {
                 long startTime = SystemClock.uptimeMillis();
                 scanDirLI(drmInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanFlags, 0);
                 mConnectedSignal2.countDown();
                  }
              }.start();
              //waitForLatch相當與一個延時的語句,延時等待掃描的完成 
              waitForLatch(mConnectedSignal2);

}

//下面這個函數定義就是掃描目錄的一個具體的實現方式,在這個過程中,我們可以看到目錄的增加和刪除都在這裏面進行,這個函數的//作用我們能看得出來,這裏調用了一個關鍵的方法對掃描行爲做更進一步的處理.  scanPackageLI
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
          final File[] files = dir.listFiles();
          if (ArrayUtils.isEmpty(files)) {
              Log.d(TAG, "No files in app dir " + dir);
              return;
          }

          if (DEBUG_PACKAGE_SCANNING) {
              Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
                      + " flags=0x" + Integer.toHexString(parseFlags));
          }

          for (File file : files) {
              final boolean isPackage = (isApkFile(file) || file.isDirectory())
                      && !PackageInstallerService.isStageName(file.getName());
              if (!isPackage) {
                  // Ignore entries which are not packages
                  continue;
              }
              try {
                  scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                          scanFlags, currentTime, null);
              } catch (PackageManagerException e) {
                  Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());

                  // Delete invalid userdata apps
                  if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                          e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                      logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                      if (file.isDirectory()) {
                          FileUtils.deleteContents(file);
                      }
                      file.delete();
                  }
              }
          }
      }
/*===========================================================*/
/* @} */
      /*
       *  Scan a package and return the newly parsed package.
       *  Returns null in case of errors and the error code is stored in mLastScanError
       */
      private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,long currentTime, UserHandle user) throws PackageManagerException {
          ...
          final PackageParser.Package pkg;
          try {
              pkg = pp.parsePackage(scanFile, parseFlags); //獲取pack的info信息
          } catch (PackageParserException e) {
              throw PackageManagerException.from(e);
          }
          if(isPreloadOrVitalApp(scanFile.getParent()) && mDeleteRecord.exists()){
              if(isDeleteApp(pkg.packageName))return pkg;
          }

        ...

          synchronized (mPackages) {
          ...
              String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
              if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
                  ps = mSettings.peekPackageLPr(oldName);
              }

              if (ps == null) {
                  ps = mSettings.peekPackageLPr(pkg.packageName);
              }
              // Check to see if this package could be hiding/updating a system
              // package.  Must look for it either under the original or real
              // package name depending on our state.
              updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);

          }
          boolean updatedPkgBetter = false;
          // First check if this is a system package that may involve an update
          if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
              // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
              // it needs to drop FLAG_PRIVILEGED.
         ...
              if (ps != null && !ps.codePath.equals(scanFile)) {
                  // The path has changed from what was last scanned...  check the
                  // version of the new path against what we have stored to determine
                  // what to do.
                  if (pkg.mVersionCode <= ps.versionCode) {
                   ...
              updatedPkg.codePath = scanFile;
                          updatedPkg.codePathString = scanFile.toString();
                      }
                      updatedPkg.pkg = pkg;
                      throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
                  } else {
                      // The current app on the system partition is better than
                      // what we have updated to on the data partition; switch
                      // back to the system partition version.
                      // At this point, its safely assumed that package installation for
                      // apps in system partition will go through. If not there won't be a working
                      // version of the app
                      // writer
                      synchronized (mPackages) {
                          // Just remove the loaded entries from package lists.
                          mPackages.remove(ps.name);
                      }

                      InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                              ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
                              getAppDexInstructionSets(ps));
                      synchronized (mInstallLock) {
                          args.cleanUpResourcesLI();
                      }
                      synchronized (mPackages) {
                          mSettings.enableSystemPackageLPw(ps.name);
                      }
                      updatedPkgBetter = true;
                  }
              }
          }

         ...
          // Verify certificates against what was last scanned
          collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);

          /*
           * A new system app appeared, but we already had a non-system one of the
           * same name installed earlier.
           */
          boolean shouldHideSystemApp = false;
          if (updatedPkg == null && ps != null
                  && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
              /*
               * Check to make sure the signatures match first. If they don't,
               * wipe the installed application and its data.
               */
              if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
                      != PackageManager.SIGNATURE_MATCH) {

                  deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
                  ps = null;
              } else {
                  /*
                   * If the newly-added system app is an older version than the
                   * already installed version, hide it. It will be scanned later
                   * and re-added like an update.
                   */
                  if (pkg.mVersionCode <= ps.versionCode) {
                      shouldHideSystemApp = true;

                  } else {
                      /*
                       * The newly found system app is a newer version that the
                       * one previously installed. Simply remove the
                       * already-installed application and replace it with our own
* already-installed application and replace it with our own
                       * while keeping the application data.
                       */
                      ...
                      InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                              ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,getAppDexInstructionSets(ps));
                      synchronized (mInstallLock) {
                          args.cleanUpResourcesLI();
                      }
                  }
              }
          }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章