【AndroidFramewok】AndroidManifest中Original Package標籤
<original-package android:name="com.android.packageinstaller" />
最近看到系統app的AndroidManifest中有個標籤,不是很懂什麼含義。
original-package 作用
通過原始碼搜尋original-package,在原始碼中找到兩處。
frameworks/base/core/java/android/content/pm/PackageParser.java:1274
frameworks/base/services/java/com/android/server/BackupManagerService.java:3918:
我們先來看PackageParser.java類
else if (tagName.equals("original-package")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestOriginalPackage); String orig =sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); if (!pkg.packageName.equals(orig)) { if (pkg.mOriginalPackages == null) { pkg.mOriginalPackages = new ArrayList<String>(); pkg.mRealPackage = pkg.packageName; } pkg.mOriginalPackages.add(orig); } sa.recycle(); XmlUtils.skipCurrentTag(parser); } String orig =sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); if (!pkg.packageName.equals(orig)) { if (pkg.mOriginalPackages == null) { pkg.mOriginalPackages = new ArrayList<String>(); pkg.mRealPackage = pkg.packageName; } pkg.mOriginalPackages.add(orig); } sa.recycle(); XmlUtils.skipCurrentTag(parser); }
AndroidManifestOriginalPackage 的定義,在 attrs_manifest.xml 檔案中:
<p>This appears as a child tag of the root {@link #AndroidManifest manifest} tag. --> <declare-styleable name="AndroidManifestOriginalPackage" parent="AndroidManifest"> <attr name="name" /> </declare-styleable>
google翻譯一下
用於宣告此程式包所在的原始程式包名稱的私有標記基於。 僅用於系統映像中安裝的軟體包。 如果給定的,不同於實際的包名和給定的原始軟體包以前安裝在裝置上但是新的一個不是,那麼舊的資料將被重新命名為對於新應用。
官方的解釋很清楚了:之前安裝的應用是系統應用,並且包名不同,之前應用的資料就會以新安裝應用的名字保留下來。
上面 parsePackage() 方法中的 mOriginalPackages,查原始碼可知對 mOriginalPackages 的其餘處理只在 PackageManagerServerice 中了。我們來看PMS的scanPackageLI方法
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; } } } }
我們看到有英文提示,當mOriginalPackages!=null並與原來名字一樣的時候 ,會賦值realName = pkg.mRealPackage;
然後呼叫Settings.java(frameworks\base\services\java\com\android\server\pm)的getPackageLPw(),看下這個方法
if (origPackage != null) { // We are consuming the data from an existing package. p = new PackageSetting(origPackage.name, name, codePath, resourcePath, nativeLibraryPathString, vc, pkgFlags); if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + name + " is adopting original package " + origPackage.name); // Note that we will retain the new package's signature so // that we can keep its data. PackageSignatures s = p.signatures; p.copyFrom(origPackage); p.signatures = s; p.sharedUser = origPackage.sharedUser; p.appId = origPackage.appId; p.origPackage = origPackage; mRenamedPackages.put(name, origPackage.name); name = origPackage.name; // Update new package state. p.setTimeStamp(codePath.lastModified()); } else { p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, vc, pkgFlags); p.setTimeStamp(codePath.lastModified()); p.sharedUser = sharedUser; // If this is not a system app, it starts out stopped. if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { if (DEBUG_STOPPED) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); Slog.i(PackageManagerService.TAG, "Stopping package " + name, e); } List<UserInfo> users = getAllUsers(); if (users != null && allowInstall) { for (UserInfo user : users) { // By default we consider this app to be installed // for the user if no user has been specified (which // means to leave it at its original value, and the // original default value is true), or we are being // asked to install for all users, or this is the // user we are installing for. final boolean installed = installUser == null || installUser.getIdentifier() == UserHandle.USER_ALL || installUser.getIdentifier() == user.id; p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT, installed, true, // stopped, true, // notLaunched false, // blocked null, null, null); writePackageRestrictionsLPr(user.id); } } }
使用現有應用的資料,實現資料共享。
我們總算找到這個標籤的作用了。恭喜!