在Android启动的过程当中,会扫描系统中特定的目录,以便对保存在里面的应用程序进行安装,例如/system/app,/data/app。这个主要是靠PackageManagerService来实现,PackageManagerService在安装一个应用程序的过程当中主要作两件事,一、解析这个应用程序的配置文件AndroidManifest.xml 以便获取安装信息,二、为这个应用程序分配Linux用户ID和Linux用户组ID,以便他能够运行在系统中得到权限java
Android系统中最后一步是启动一个HOME程序,用来显示系统中已经安装的应用程序,Android提供原声的程序是Launcher,应用程序在启动中,会请求PackageManagerService提供安装的应用程序信息,再将程序信息封装成一个快捷图标在屏幕中,这样用户就能够根据图标来启动对应的程序,
android
PackageManagerService在安装一个应用程序的时候,对AndroidManifest.xml进行解析,获取到组件信息,Android系统的每个应用程序都有一个Linux用户ID,这些ID是有PackageManagerService负责分配的,PackageManagerService在安装一个应用程序的时候,若是发现没有其余应用程序共享一个Linux用户ID,那么就会为它分配惟一的Linux用户ID,这样能够得到所需的权限,有了用户ID以外还有若干个Linux用户组ID,以便得到更多的资源,Linux用户组ID也是PackageManagerService来负责分配的,shell
在PackageManagerService.java中app
public static final IPackageManager main(Context context, boolean factoryTest, boolean onlyCore) { PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore); ServiceManager.addService("package", m); return m; }
首先将PackageManagerService启动起来,而后注册到ServiceManager中,这样系统经过ServiceManager来获取安装服务。ide
public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); if (mSdkVersion <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); } mContext = context; mFactoryTest = factoryTest; mOnlyCore = onlyCore; mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type")); mMetrics = new DisplayMetrics(); mSettings = new Settings(); mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.phone", MULTIPLE_APPLICATION_UIDS ? RADIO_UID : FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.log", MULTIPLE_APPLICATION_UIDS ? LOG_UID : FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.nfc", MULTIPLE_APPLICATION_UIDS ? NFC_UID : FIRST_APPLICATION_UID, ApplicationInfo.FLAG_SYSTEM); 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 = new Installer(); WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); Display d = wm.getDefaultDisplay(); d.getMetrics(mMetrics); synchronized (mInstallLock) { // writer synchronized (mPackages) { mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); File dataDir = Environment.getDataDirectory();//得到系统的数据目录/data mAppDataDir = new File(dataDir, "data"); mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private");//得到的是/data/app-private目录,主要是受DRM保护的私有应用程序,/data/app下面是本身安装的应用程序。 mUserManager = new UserManager(mInstaller, mUserAppDataDir); readPermissions(); mRestoredSettings = mSettings.readLPw();//恢复上一次应用程序的安装信息,接下来就扫描和安装保存在特定目录的应用程序 long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); // Set flag to monitor and not change apk file paths when // scanning install directories. int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX; 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");//得到的是/system/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(); } } } } // 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");//得到的是/system/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");//得到的是/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);//scanDieLI用来安装里面的应用程序。 if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands"); mInstaller.moveFiles(); // Prune any system packages that no longer exist. if (!mOnlyCore) { Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator(); while (psit.hasNext()) { PackageSetting ps = psit.next(); if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && !mPackages.containsKey(ps.name) && !mSettings.mDisabledSysPackages.containsKey(ps.name)) { psit.remove(); String msg = "System package " + ps.name + " no longer exists; wiping its data"; reportSettingsProblem(Log.WARN, msg); mInstaller.remove(ps.name, 0); mUserManager.removePackageForAllUsers(ps.name); } } } mAppInstallDir = new File(dataDir, "app"); //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(); 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); } else { mAppInstallObserver = null; mDrmAppInstallObserver = null; } EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); // 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(null, null, true, regrantPermissions, regrantPermissions); // can downgrade to reader mSettings.writeLPr(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); // Now after opening every single application zip, make sure they // are all flushed. Not really needed, but keeps things nice and // tidy. Runtime.getRuntime().gc(); mRequiredVerifierPackage = getRequiredVerifierLPr(); } // synchronized (mPackages) } // synchronized (mInstallLock)
未完善,oop