diff options
14 files changed, 885 insertions, 211 deletions
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index c507245..0d463ee 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -691,6 +691,17 @@ public abstract class PackageManager { public static final int DELETE_ALL_USERS = 0x00000002; /** + * Flag parameter for {@link #deletePackage} to indicate that, if you are calling + * uninstall on a system that has been updated, then don't do the normal process + * of uninstalling the update and rolling back to the older system version (which + * needs to happen for all users); instead, just mark the app as uninstalled for + * the current user. + * + * @hide + */ + public static final int DELETE_SYSTEM_APP = 0x00000004; + + /** * Return code for when package deletion succeeds. This is passed to the * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system * succeeded in deleting the package. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index e1887bc..5eac903 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1941,6 +1941,28 @@ public class PackageParser { return false; } + } else if (tagName.equals("library")) { + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + com.android.internal.R.styleable.AndroidManifestLibrary_name); + + sa.recycle(); + + if (lname != null) { + if (owner.libraryNames == null) { + owner.libraryNames = new ArrayList<String>(); + } + if (!owner.libraryNames.contains(lname)) { + owner.libraryNames.add(lname.intern()); + } + } + + XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("uses-library")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestUsesLibrary); @@ -3182,7 +3204,8 @@ public class PackageParser { public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>(); public ArrayList<String> protectedBroadcasts; - + + public ArrayList<String> libraryNames = null; public ArrayList<String> usesLibraries = null; public ArrayList<String> usesOptionalLibraries = null; public String[] usesLibraryFiles = null; diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index d899e9d..f1d8c03 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1065,6 +1065,21 @@ <attr name="maxSdkVersion" format="integer" /> </declare-styleable> + <!-- The <code>library</code> tag declares that this apk is providing itself + as a shared library for other applications to use. It can only be used + with apks that are built in to the system image. Other apks can link to + it with the {@link #AndroidManifestUsesLibrary uses-library} tag. + + <p>This appears as a child tag of the + {@link #AndroidManifestApplication application} tag. --> + <declare-styleable name="AndroidManifestLibrary" parent="AndroidManifest"> + <!-- Required public name of the library, which other components and + packages will use when referring to this library. This is a string using + Java-style scoping to ensure it is unique. The name should typically + be the same as the apk's package name. --> + <attr name="name" /> + </declare-styleable> + <!-- The <code>uses-libraries</code> specifies a shared library that this package requires to be linked against. Specifying this flag tells the system to include this library's code in your class loader. diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 51f001f..2d12a77 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -170,7 +170,7 @@ adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests c public class PackageManagerService extends IPackageManager.Stub { static final String TAG = "PackageManager"; static final boolean DEBUG_SETTINGS = false; - static final boolean DEBUG_PREFERRED = true; + static final boolean DEBUG_PREFERRED = false; static final boolean DEBUG_UPGRADE = false; private static final boolean DEBUG_INSTALL = false; private static final boolean DEBUG_REMOVE = false; @@ -339,9 +339,20 @@ public class PackageManagerService extends IPackageManager.Stub { final SparseArray<HashSet<String>> mSystemPermissions = new SparseArray<HashSet<String>>(); + static final class SharedLibraryEntry { + final String path; + final String apk; + + SharedLibraryEntry(String _path, String _apk) { + path = _path; + apk = _apk; + } + } + // These are the built-in shared libraries that were read from the // etc/permissions.xml file. - final HashMap<String, String> mSharedLibraries = new HashMap<String, String>(); + final HashMap<String, SharedLibraryEntry> mSharedLibraries + = new HashMap<String, SharedLibraryEntry>(); // Temporary for building the final shared libraries for an .apk. String[] mTmpSharedLibraries = null; @@ -390,8 +401,7 @@ public class PackageManagerService extends IPackageManager.Stub { final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<PackageVerificationState>(); - final ArrayList<PackageParser.Package> mDeferredDexOpt = - new ArrayList<PackageParser.Package>(); + HashSet<PackageParser.Package> mDeferredDexOpt = null; /** Token for keys in mPendingVerification. */ private int mPendingVerificationToken = 0; @@ -514,10 +524,9 @@ public class PackageManagerService extends IPackageManager.Stub { void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { - if (DEBUG_INSTALL) Slog.i(TAG, "init_copy"); HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); - if (DEBUG_INSTALL) Slog.i(TAG, "idx=" + idx); + if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); // If a bind was already initiated we dont really // need to do anything. The pending install // will be processed later on. @@ -1071,9 +1080,12 @@ public class PackageManagerService extends IPackageManager.Stub { * Also ensure all external libraries have had dexopt run on them. */ if (mSharedLibraries.size() > 0) { - Iterator<String> libs = mSharedLibraries.values().iterator(); + Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator(); while (libs.hasNext()) { - String lib = libs.next(); + String lib = libs.next().path; + if (lib == null) { + continue; + } try { if (dalvik.system.DexFile.isDexOptNeeded(lib)) { libFiles.add(lib); @@ -1277,6 +1289,10 @@ public class PackageManagerService extends IPackageManager.Stub { mDrmAppInstallObserver = null; } + // Now that we know all of the shared libraries, update all clients to have + // the correct library paths. + updateAllSharedLibrariesLPw(); + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " @@ -1517,7 +1533,7 @@ public class PackageManagerService extends IPackageManager.Stub { + parser.getPositionDescription()); } else { //Log.i(TAG, "Got library " + lname + " in " + lfile); - mSharedLibraries.put(lname, lfile); + mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null)); } XmlUtils.skipCurrentTag(parser); continue; @@ -3249,6 +3265,7 @@ public class PackageManagerService extends IPackageManager.Stub { int parseFlags, int scanMode, long currentTime, UserHandle user) { mLastScanError = PackageManager.INSTALL_SUCCEEDED; String scanPath = scanFile.getPath(); + if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath); parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(scanPath); pp.setSeparateProcesses(mSeparateProcesses); @@ -3278,6 +3295,7 @@ public class PackageManagerService extends IPackageManager.Stub { // 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); + if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg); } // First check if this is a system package that may involve an update if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { @@ -3285,6 +3303,7 @@ public class PackageManagerService extends IPackageManager.Stub { // 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 (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath); if (pkg.mVersionCode < ps.versionCode) { // The system package has been updated and the code path does not match // Ignore entry. Skip it. @@ -3298,6 +3317,7 @@ public class PackageManagerService extends IPackageManager.Stub { updatedPkg.codePath = scanFile; updatedPkg.codePathString = scanFile.toString(); } + updatedPkg.pkg = pkg; mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; return null; } else { @@ -3353,6 +3373,7 @@ public class PackageManagerService extends IPackageManager.Stub { */ if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { + if (DEBUG_INSTALL) Slog.d(TAG, "Signature mismatch!"); deletePackageLI(pkg.packageName, null, true, 0, null, false); ps = null; } else { @@ -3484,28 +3505,28 @@ public class PackageManagerService extends IPackageManager.Stub { } public void performBootDexOpt() { - ArrayList<PackageParser.Package> pkgs = null; + HashSet<PackageParser.Package> pkgs = null; synchronized (mPackages) { - if (mDeferredDexOpt.size() > 0) { - pkgs = new ArrayList<PackageParser.Package>(mDeferredDexOpt); - mDeferredDexOpt.clear(); - } + pkgs = mDeferredDexOpt; + mDeferredDexOpt = null; } if (pkgs != null) { - for (int i=0; i<pkgs.size(); i++) { + int i = 0; + for (PackageParser.Package pkg : pkgs) { if (!isFirstBoot()) { + i++; try { ActivityManagerNative.getDefault().showBootMessage( mContext.getResources().getString( com.android.internal.R.string.android_upgrading_apk, - i+1, pkgs.size()), true); + i, pkgs.size()), true); } catch (RemoteException e) { } } - PackageParser.Package p = pkgs.get(i); + PackageParser.Package p = pkg; synchronized (mInstallLock) { if (!p.mDidDexOpt) { - performDexOptLI(p, false, false); + performDexOptLI(p, false, false, true); } } } @@ -3527,7 +3548,27 @@ public class PackageManagerService extends IPackageManager.Stub { } } synchronized (mInstallLock) { - return performDexOptLI(p, false, false) == DEX_OPT_PERFORMED; + return performDexOptLI(p, false, false, true) == DEX_OPT_PERFORMED; + } + } + + private void performDexOptLibsLI(ArrayList<String> libs, boolean forceDex, boolean defer, + HashSet<String> done) { + for (int i=0; i<libs.size(); i++) { + PackageParser.Package libPkg; + String libName; + synchronized (mPackages) { + libName = libs.get(i); + SharedLibraryEntry lib = mSharedLibraries.get(libName); + if (lib != null && lib.apk != null) { + libPkg = mPackages.get(lib.apk); + } else { + libPkg = null; + } + } + if (libPkg != null && !done.contains(libName)) { + performDexOptLI(libPkg, forceDex, defer, done); + } } } @@ -3536,14 +3577,27 @@ public class PackageManagerService extends IPackageManager.Stub { static final int DEX_OPT_DEFERRED = 2; static final int DEX_OPT_FAILED = -1; - private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer) { + private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer, + HashSet<String> done) { boolean performed = false; + if (done != null) { + done.add(pkg.packageName); + if (pkg.usesLibraries != null) { + performDexOptLibsLI(pkg.usesLibraries, forceDex, defer, done); + } + if (pkg.usesOptionalLibraries != null) { + performDexOptLibsLI(pkg.usesOptionalLibraries, forceDex, defer, done); + } + } if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { String path = pkg.mScanPath; int ret = 0; try { if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) { if (!forceDex && defer) { + if (mDeferredDexOpt == null) { + mDeferredDexOpt = new HashSet<PackageParser.Package>(); + } mDeferredDexOpt.add(pkg); return DEX_OPT_DEFERRED; } else { @@ -3576,6 +3630,19 @@ public class PackageManagerService extends IPackageManager.Stub { return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED; } + private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer, + boolean inclDependencies) { + HashSet<String> done; + boolean performed = false; + if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) { + done = new HashSet<String>(); + done.add(pkg.packageName); + } else { + done = null; + } + return performDexOptLI(pkg, forceDex, defer, done); + } + private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) { if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { Slog.w(TAG, "Unable to update from " + oldPkg.name @@ -3646,6 +3713,113 @@ public class PackageManagerService extends IPackageManager.Stub { return res; } + private int addSharedLibraryLPw(final SharedLibraryEntry file, int num, + PackageParser.Package changingLib) { + if (file.path != null) { + mTmpSharedLibraries[num] = file.path; + return num+1; + } + PackageParser.Package p = mPackages.get(file.apk); + if (changingLib != null && changingLib.packageName.equals(file.apk)) { + // If we are doing this while in the middle of updating a library apk, + // then we need to make sure to use that new apk for determining the + // dependencies here. (We haven't yet finished committing the new apk + // to the package manager state.) + if (p == null || p.packageName.equals(changingLib.packageName)) { + p = changingLib; + } + } + if (p != null) { + String path = p.mPath; + for (int i=0; i<num; i++) { + if (mTmpSharedLibraries[i].equals(path)) { + return num; + } + } + mTmpSharedLibraries[num] = p.mPath; + return num+1; + } + return num; + } + + private boolean updateSharedLibrariesLPw(PackageParser.Package pkg, + PackageParser.Package changingLib) { + 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 SharedLibraryEntry 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 false; + } + num = addSharedLibraryLPw(file, num, changingLib); + } + N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0; + for (int i=0; i<N; i++) { + final SharedLibraryEntry 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 { + num = addSharedLibraryLPw(file, num, changingLib); + } + } + if (num > 0) { + pkg.usesLibraryFiles = new String[num]; + System.arraycopy(mTmpSharedLibraries, 0, + pkg.usesLibraryFiles, 0, num); + } else { + pkg.usesLibraryFiles = null; + } + } + return true; + } + + private static boolean hasString(List<String> list, List<String> which) { + if (list == null) { + return false; + } + for (int i=list.size()-1; i>=0; i--) { + for (int j=which.size()-1; j>=0; j--) { + if (which.get(j).equals(list.get(i))) { + return true; + } + } + } + return false; + } + + private void updateAllSharedLibrariesLPw() { + for (PackageParser.Package pkg : mPackages.values()) { + updateSharedLibrariesLPw(pkg, null); + } + } + + private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw( + PackageParser.Package changingPkg) { + ArrayList<PackageParser.Package> res = null; + for (PackageParser.Package pkg : mPackages.values()) { + if (hasString(pkg.usesLibraries, changingPkg.libraryNames) + || hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)) { + if (res == null) { + res = new ArrayList<PackageParser.Package>(); + } + res.add(pkg); + updateSharedLibrariesLPw(pkg, changingPkg); + } + } + return res; + } + private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, long currentTime, UserHandle user) { File scanFile = new File(pkg.mScanPath); @@ -3725,42 +3899,14 @@ public class PackageManagerService extends IPackageManager.Stub { // 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 ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + // Check all shared libraries and map to their actual file path. + // We only do this here for apps not on a system dir, because those + // are the only ones that can fail an install due to this. We + // will take care of the system apps by updating all of their + // library paths after the scan is done. + if (!updateSharedLibrariesLPw(pkg, null)) { + return null; } } @@ -4166,7 +4312,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.mScanPath = path; if ((scanMode&SCAN_NO_DEX) == 0) { - if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0) + if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) { mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT; return null; @@ -4178,6 +4324,80 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST; } + ArrayList<PackageParser.Package> clientLibPkgs = null; + + // writer + synchronized (mPackages) { + if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + // Only system apps can add new shared libraries. + if (pkg.libraryNames != null) { + for (int i=0; i<pkg.libraryNames.size(); i++) { + String name = pkg.libraryNames.get(i); + boolean allowed = false; + if (isUpdatedSystemApp(pkg)) { + // New library entries can only be added through the + // system image. This is important to get rid of a lot + // of nasty edge cases: for example if we allowed a non- + // system update of the app to add a library, then uninstalling + // the update would make the library go away, and assumptions + // we made such as through app install filtering would now + // have allowed apps on the device which aren't compatible + // with it. Better to just have the restriction here, be + // conservative, and create many fewer cases that can negatively + // impact the user experience. + final PackageSetting sysPs = mSettings + .getDisabledSystemPkgLPr(pkg.packageName); + if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) { + for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) { + if (name.equals(sysPs.pkg.libraryNames.get(j))) { + allowed = true; + allowed = true; + break; + } + } + } + } else { + allowed = true; + } + if (allowed) { + if (!mSharedLibraries.containsKey(name)) { + mSharedLibraries.put(name, new SharedLibraryEntry(null, + pkg.packageName)); + } else if (!name.equals(pkg.packageName)) { + Slog.w(TAG, "Package " + pkg.packageName + " library " + + name + " already exists; skipping"); + } + } else { + Slog.w(TAG, "Package " + pkg.packageName + " declares lib " + + name + " that is not declared on system image; skipping"); + } + } + if ((scanMode&SCAN_BOOTING) == 0) { + // If we are not booting, we need to update any applications + // that are clients of our shared library. If we are booting, + // this will all be done once the scan is complete. + clientLibPkgs = updateAllSharedLibrariesLPw(pkg); + } + } + } + } + + // We also need to dexopt any apps that are dependent on this library. Note that + // if these fail, we should abort the install since installing the library will + // result in some apps being broken. + if (clientLibPkgs != null) { + if ((scanMode&SCAN_NO_DEX) == 0) { + for (int i=0; i<clientLibPkgs.size(); i++) { + PackageParser.Package clientPkg = clientLibPkgs.get(i); + if (performDexOptLI(clientPkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false) + == DEX_OPT_FAILED) { + mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT; + return null; + } + } + } + } + // 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. @@ -4186,6 +4406,15 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.uid); } + // Also need to kill any apps that are dependent on the library. + if (clientLibPkgs != null) { + for (int i=0; i<clientLibPkgs.size(); i++) { + PackageParser.Package clientPkg = clientLibPkgs.get(i); + killApplication(clientPkg.applicationInfo.packageName, + clientPkg.applicationInfo.uid); + } + } + // writer synchronized (mPackages) { // We don't expect installation to fail beyond this point, @@ -4591,7 +4820,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } } - if (chatty) { + if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { @@ -4627,7 +4856,7 @@ public class PackageManagerService extends IPackageManager.Stub { for (i=0; i<N; i++) { PackageParser.Activity a = pkg.receivers.get(i); mReceivers.removeActivity(a, "receiver"); - if (chatty) { + if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { @@ -4645,7 +4874,7 @@ public class PackageManagerService extends IPackageManager.Stub { for (i=0; i<N; i++) { PackageParser.Activity a = pkg.activities.get(i); mActivities.removeActivity(a, "activity"); - if (chatty) { + if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { @@ -4668,7 +4897,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (bp != null && bp.perm == p) { bp.perm = null; - if (chatty) { + if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { @@ -4687,7 +4916,7 @@ public class PackageManagerService extends IPackageManager.Stub { for (i=0; i<N; i++) { PackageParser.Instrumentation a = pkg.instrumentation.get(i); mInstrumentation.remove(a.getComponentName()); - if (chatty) { + if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { @@ -4699,6 +4928,31 @@ public class PackageManagerService extends IPackageManager.Stub { if (r != null) { if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r); } + + r = null; + if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + // Only system apps can hold shared libraries. + if (pkg.libraryNames != null) { + for (i=0; i<pkg.libraryNames.size(); i++) { + String name = pkg.libraryNames.get(i); + SharedLibraryEntry cur = mSharedLibraries.get(name); + if (cur != null && cur.apk != null && cur.apk.equals(pkg.packageName)) { + mSharedLibraries.remove(name); + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(name); + } + } + } + } + } + if (r != null) { + if (DEBUG_REMOVE) Log.d(TAG, " Libraries: " + r); + } } private static final boolean isPackageFilename(String name) { @@ -4860,7 +5114,23 @@ public class PackageManagerService extends IPackageManager.Stub { if (origGp.grantedPermissions.contains(perm)) { allowed = true; } else { + // The system apk may have been updated with an older + // version of the one on the data partition, but which + // granted a new system permission that it didn't have + // before. In this case we do want to allow the app to + // now get the new permission, because it is allowed by + // the system image. allowed = false; + if (sysPs.pkg != null) { + for (int j=0; + j<sysPs.pkg.requestedPermissions.size(); j++) { + if (perm.equals( + sysPs.pkg.requestedPermissions.get(j))) { + allowed = true; + break; + } + } + } } } else { allowed = true; @@ -5557,6 +5827,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if ((event&REMOVE_EVENTS) != 0) { if (ps != null) { + if (DEBUG_REMOVE) Slog.d(TAG, "Package disappeared: " + ps); removePackageLI(ps, true); removedPackage = ps.name; removedAppId = ps.appId; @@ -5565,6 +5836,7 @@ public class PackageManagerService extends IPackageManager.Stub { if ((event&ADD_EVENTS) != 0) { if (p == null) { + if (DEBUG_INSTALL) Slog.d(TAG, "New file appeared: " + fullPath); p = scanPackageLI(fullPath, (mIsRom ? PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR: 0) | @@ -6126,7 +6398,7 @@ public class PackageManagerService extends IPackageManager.Stub { final boolean startCopy() { boolean res; try { - if (DEBUG_INSTALL) Slog.i(TAG, "startCopy"); + if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); if (++mRetries > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); @@ -6170,6 +6442,13 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override + public String toString() { + return "MeasureParams{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + mStats.packageName + "}"; + } + + @Override void handleStartCopy() throws RemoteException { synchronized (mInstallLock) { mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats); @@ -6258,6 +6537,13 @@ public class PackageManagerService extends IPackageManager.Stub { this.encryptionParams = encryptionParams; } + @Override + public String toString() { + return "InstallParams{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + mPackageURI + "}"; + } + public ManifestDigest getManifestDigest() { if (verificationParams == null) { return null; @@ -6671,6 +6957,13 @@ public class PackageManagerService extends IPackageManager.Stub { } } + @Override + public String toString() { + return "MoveParams{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + packageName + "}"; + } + public void handleStartCopy() throws RemoteException { mRet = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; // Check for storage space on target medium @@ -7582,6 +7875,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; + if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg); boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists(); synchronized(mPackages) { if (mSettings.mRenamedPackages.containsKey(pkgName)) { @@ -7638,6 +7932,7 @@ public class PackageManagerService extends IPackageManager.Stub { // First find the old package info and check signatures synchronized(mPackages) { oldPackage = mPackages.get(pkgName); + if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage); if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { Slog.w(TAG, "New package has a different signature: " + pkgName); @@ -7663,6 +7958,8 @@ public class PackageManagerService extends IPackageManager.Stub { boolean deletedPkg = true; boolean updatedSettings = false; + if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old=" + + deletedPackage); long origUpdateTime; if (pkg.mExtras != null) { origUpdateTime = ((PackageSetting)pkg.mExtras).lastUpdateTime; @@ -7700,6 +7997,7 @@ public class PackageManagerService extends IPackageManager.Stub { // scanPackageLocked, unless those directories existed before we even tried to // install. if(updatedSettings) { + if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, rolling pack: " + pkgName); deletePackageLI( pkgName, null, true, PackageManager.DELETE_KEEP_DATA, @@ -7708,6 +8006,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Since we failed to install the new package we need to restore the old // package that we deleted. if(deletedPkg) { + if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage); File restoreFile = new File(deletedPackage.mPath); // Parse old package boolean oldOnSd = isExternal(deletedPackage); @@ -7737,6 +8036,8 @@ public class PackageManagerService extends IPackageManager.Stub { private void replaceSystemPackageLI(PackageParser.Package deletedPackage, PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user, String installerPackageName, PackageInstalledInfo res) { + if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg + + ", old=" + deletedPackage); PackageParser.Package newPackage = null; boolean updatedSettings = false; parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING | @@ -7859,7 +8160,7 @@ public class PackageManagerService extends IPackageManager.Stub { return; } - Log.d(TAG, "New package installed in " + newPackage.mPath); + if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.mPath); synchronized (mPackages) { updatePermissionsLPw(newPackage.packageName, newPackage, @@ -7889,6 +8190,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Result object to be returned res.returnCode = PackageManager.INSTALL_SUCCEEDED; + if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile); // Retrieve PackageSettings and parse package int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) @@ -7950,14 +8252,18 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.setPackageName(oldName); pkgName = pkg.packageName; replace = true; + if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName=" + + oldName + " pkgName=" + pkgName); } else if (mPackages.containsKey(pkgName)) { // This package, under its official name, already exists // on the device; we should replace it. replace = true; + if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); } } PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { + if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); oldCodePath = mSettings.mPackages.get(pkgName).codePathString; if (ps.pkg != null && ps.pkg.applicationInfo != null) { systemApp = (ps.pkg.applicationInfo.flags & @@ -8104,6 +8410,7 @@ public class PackageManagerService extends IPackageManager.Stub { return; } + if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId); // Queue up an async operation since the package deletion may take a little while. mHandler.post(new Runnable() { public void run() { @@ -8151,6 +8458,7 @@ public class PackageManagerService extends IPackageManager.Stub { boolean removedForAllUsers = false; boolean systemUpdate = false; synchronized (mInstallLock) { + if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId); res = deletePackageLI(packageName, (flags & PackageManager.DELETE_ALL_USERS) != 0 ? UserHandle.ALL : new UserHandle(userId), @@ -8159,6 +8467,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (res && !systemUpdate && mPackages.get(packageName) == null) { removedForAllUsers = true; } + if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate + + " removedForAllUsers=" + removedForAllUsers); } if (res) { @@ -8234,6 +8544,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void removePackageDataLI(PackageSetting ps, PackageRemovedInfo outInfo, int flags, boolean writeSettings) { String packageName = ps.name; + if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps); removePackageLI(ps, (flags&REMOVE_CHATTY) != 0); // Retrieve object to delete permissions for shared user later on final PackageSetting deletedPs; @@ -8289,11 +8600,13 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name); } + if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + newPs + + " disabledPs=" + disabledPs); if (disabledPs == null) { Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name); return false; - } else { - Log.i(TAG, "Deleting system pkg from data partition"); + } else if (DEBUG_REMOVE) { + Slog.d(TAG, "Deleting system pkg from data partition"); } // Delete the updated package outInfo.isRemovedPackageSystemUpdate = true; @@ -8317,6 +8630,7 @@ public class PackageManagerService extends IPackageManager.Stub { NativeLibraryHelper.removeNativeBinariesLI(newPs.nativeLibraryPathString); } // Install the system package + if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); PackageParser.Package newPkg = scanPackageLI(disabledPs.codePath, PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM, SCAN_MONITOR | SCAN_NO_PATHS, 0, null); @@ -8366,6 +8680,7 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Attempt to delete null packageName."); return false; } + if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user); PackageSetting ps; boolean dataOnly = false; int removeUser = -1; @@ -8376,11 +8691,14 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Package named '" + packageName + "' doesn't exist."); return false; } - if (user != null + if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null && user.getIdentifier() != UserHandle.USER_ALL) { // The caller is asking that the package only be deleted for a single // user. To do this, we just mark its uninstalled state and delete - // its data. + // its data. If this is a system app, we only allow this to happen if + // they have set the special DELETE_SYSTEM_APP which requests different + // semantics than normal for uninstalling system apps. + if (DEBUG_REMOVE) Slog.d(TAG, "Only deleting for single user"); ps.setUserState(user.getIdentifier(), COMPONENT_ENABLED_STATE_DEFAULT, false, //installed @@ -8392,12 +8710,14 @@ public class PackageManagerService extends IPackageManager.Stub { // Other user still have this package installed, so all // we need to do is clear this user's data and save that // it is uninstalled. + if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users"); removeUser = user.getIdentifier(); appId = ps.appId; mSettings.writePackageRestrictionsLPr(removeUser); } else { // We need to set it back to 'installed' so the uninstall // broadcasts will be sent correctly. + if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete"); ps.setInstalled(true, user.getIdentifier()); } } else { @@ -8405,6 +8725,7 @@ public class PackageManagerService extends IPackageManager.Stub { // other users still have this package installed, so all // we need to do is clear this user's data and save that // it is uninstalled. + if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app"); removeUser = user.getIdentifier(); appId = ps.appId; mSettings.writePackageRestrictionsLPr(removeUser); @@ -8415,6 +8736,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (removeUser >= 0) { // From above, we determined that we are deleting this only // for a single user. Continue the work here. + if (DEBUG_REMOVE) Slog.d(TAG, "Updating install state for user: " + removeUser); if (outInfo != null) { outInfo.removedPackage = packageName; outInfo.removedAppId = appId; @@ -8427,17 +8749,18 @@ public class PackageManagerService extends IPackageManager.Stub { if (dataOnly) { // Delete application data first + if (DEBUG_REMOVE) Slog.d(TAG, "Removing package data only"); removePackageDataLI(ps, outInfo, flags, writeSettings); return true; } boolean ret = false; if (isSystemApp(ps)) { - Log.i(TAG, "Removing system package:" + ps.name); + if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name); // When an updated system application is deleted we delete the existing resources as well and // fall back to existing code in system partition ret = deleteSystemPackageLI(ps, flags, outInfo, writeSettings); } else { - Log.i(TAG, "Removing non-system package:" + ps.name); + if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name); // Kill application pre-emptively especially for apps on sd. killApplication(packageName, ps.appId); ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, outInfo, @@ -9408,7 +9731,15 @@ public class PackageManagerService extends IPackageManager.Stub { pw.print(" "); pw.print(name); pw.print(" -> "); - pw.println(mSharedLibraries.get(name)); + SharedLibraryEntry ent = mSharedLibraries.get(name); + if (ent.path != null) { + pw.print("(jar) "); + pw.print(ent.path); + } else { + pw.print("(apk) "); + pw.print(ent.apk); + } + pw.println(); } } diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 13f514b..e645078 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -32,7 +32,6 @@ import android.util.LogPrinter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; -import com.android.server.IntentResolver; import com.android.server.pm.PackageManagerService.DumpState; import org.xmlpull.v1.XmlPullParser; @@ -2657,6 +2656,162 @@ final class Settings { ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE", }; + void dumpPackageLPr(PrintWriter pw, String prefix, PackageSetting ps, SimpleDateFormat sdf, + Date date, List<UserInfo> users) { + pw.print(prefix); pw.print("Package ["); + pw.print(ps.realName != null ? ps.realName : ps.name); + pw.print("] ("); + pw.print(Integer.toHexString(System.identityHashCode(ps))); + pw.println("):"); + + if (ps.realName != null) { + pw.print(prefix); pw.print(" compat name="); + pw.println(ps.name); + } + + pw.print(prefix); pw.print(" userId="); pw.print(ps.appId); + pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids)); + if (ps.sharedUser != null) { + pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser); + } + pw.print(prefix); pw.print(" pkg="); pw.println(ps.pkg); + pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString); + pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString); + pw.print(prefix); pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); + pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode); + if (ps.pkg != null) { + pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion); + } + pw.println(); + if (ps.pkg != null) { + pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName); + pw.print(prefix); pw.print(" applicationInfo="); + pw.println(ps.pkg.applicationInfo.toString()); + pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, + FLAG_DUMP_SPEC); pw.println(); + pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); + if (ps.pkg.mOperationPending) { + pw.print(prefix); pw.println(" mOperationPending=true"); + } + pw.print(prefix); pw.print(" supportsScreens=["); + boolean first = true; + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("small"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("medium"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("large"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("xlarge"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("resizeable"); + } + if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + if (!first) + pw.print(", "); + first = false; + pw.print("anyDensity"); + } + pw.println("]"); + if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) { + pw.print(prefix); pw.println(" libraries:"); + for (int i=0; i<ps.pkg.libraryNames.size(); i++) { + pw.print(prefix); pw.print(" "); pw.println(ps.pkg.libraryNames.get(i)); + } + } + if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) { + pw.print(prefix); pw.println(" usesLibraries:"); + for (int i=0; i<ps.pkg.usesLibraries.size(); i++) { + pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraries.get(i)); + } + } + if (ps.pkg.usesOptionalLibraries != null + && ps.pkg.usesOptionalLibraries.size() > 0) { + pw.print(prefix); pw.println(" usesOptionalLibraries:"); + for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) { + pw.print(prefix); pw.print(" "); + pw.println(ps.pkg.usesOptionalLibraries.get(i)); + } + } + if (ps.pkg.usesLibraryFiles != null + && ps.pkg.usesLibraryFiles.length > 0) { + pw.print(prefix); pw.println(" usesLibraryFiles:"); + for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) { + pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraryFiles[i]); + } + } + } + pw.print(prefix); pw.print(" timeStamp="); + date.setTime(ps.timeStamp); + pw.println(sdf.format(date)); + pw.print(prefix); pw.print(" firstInstallTime="); + date.setTime(ps.firstInstallTime); + pw.println(sdf.format(date)); + pw.print(prefix); pw.print(" lastUpdateTime="); + date.setTime(ps.lastUpdateTime); + pw.println(sdf.format(date)); + if (ps.installerPackageName != null) { + pw.print(prefix); pw.print(" installerPackageName="); + pw.println(ps.installerPackageName); + } + pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures); + pw.print(prefix); pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed); + pw.print(" haveGids="); pw.print(ps.haveGids); + pw.print(" installStatus="); pw.println(ps.installStatus); + pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC); + pw.println(); + for (UserInfo user : users) { + pw.print(prefix); pw.print(" User "); pw.print(user.id); pw.print(": "); + pw.print(" installed="); + pw.print(ps.getInstalled(user.id)); + pw.print(" stopped="); + pw.print(ps.getStopped(user.id)); + pw.print(" notLaunched="); + pw.print(ps.getNotLaunched(user.id)); + pw.print(" enabled="); + pw.println(ps.getEnabled(user.id)); + HashSet<String> cmp = ps.getDisabledComponents(user.id); + if (cmp != null && cmp.size() > 0) { + pw.print(prefix); pw.println(" disabledComponents:"); + for (String s : cmp) { + pw.print(prefix); pw.print(" "); pw.println(s); + } + } + cmp = ps.getEnabledComponents(user.id); + if (cmp != null && cmp.size() > 0) { + pw.print(prefix); pw.println(" enabledComponents:"); + for (String s : cmp) { + pw.print(prefix); pw.print(" "); pw.println(s); + } + } + } + if (ps.grantedPermissions.size() > 0) { + pw.print(prefix); pw.println(" grantedPermissions:"); + for (String s : ps.grantedPermissions) { + pw.print(prefix); pw.print(" "); pw.println(s); + } + } + } + void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) { final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); final Date date = new Date(); @@ -2678,123 +2833,7 @@ final class Settings { pw.println("Packages:"); printedSomething = true; } - pw.print(" Package ["); - pw.print(ps.realName != null ? ps.realName : ps.name); - pw.print("] ("); - pw.print(Integer.toHexString(System.identityHashCode(ps))); - pw.println("):"); - - if (ps.realName != null) { - pw.print(" compat name="); - pw.println(ps.name); - } - - pw.print(" userId="); pw.print(ps.appId); - pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids)); - pw.print(" sharedUser="); pw.println(ps.sharedUser); - pw.print(" pkg="); pw.println(ps.pkg); - pw.print(" codePath="); pw.println(ps.codePathString); - pw.print(" resourcePath="); pw.println(ps.resourcePathString); - pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); - pw.print(" versionCode="); pw.println(ps.versionCode); - if (ps.pkg != null) { - pw.print(" applicationInfo="); pw.println(ps.pkg.applicationInfo.toString()); - pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, FLAG_DUMP_SPEC); pw.println(); - pw.print(" versionName="); pw.println(ps.pkg.mVersionName); - pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); - pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion); - if (ps.pkg.mOperationPending) { - pw.println(" mOperationPending=true"); - } - pw.print(" supportsScreens=["); - boolean first = true; - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { - if (!first) - pw.print(", "); - first = false; - pw.print("small"); - } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { - if (!first) - pw.print(", "); - first = false; - pw.print("medium"); - } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - if (!first) - pw.print(", "); - first = false; - pw.print("large"); - } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { - if (!first) - pw.print(", "); - first = false; - pw.print("xlarge"); - } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { - if (!first) - pw.print(", "); - first = false; - pw.print("resizeable"); - } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { - if (!first) - pw.print(", "); - first = false; - pw.print("anyDensity"); - } - pw.println("]"); - } - pw.print(" timeStamp="); - date.setTime(ps.timeStamp); - pw.println(sdf.format(date)); - pw.print(" firstInstallTime="); - date.setTime(ps.firstInstallTime); - pw.println(sdf.format(date)); - pw.print(" lastUpdateTime="); - date.setTime(ps.lastUpdateTime); - pw.println(sdf.format(date)); - if (ps.installerPackageName != null) { - pw.print(" installerPackageName="); pw.println(ps.installerPackageName); - } - pw.print(" signatures="); pw.println(ps.signatures); - pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed); - pw.print(" haveGids="); pw.print(ps.haveGids); - pw.print(" installStatus="); pw.println(ps.installStatus); - pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC); - pw.println(); - for (UserInfo user : users) { - pw.print(" User "); pw.print(user.id); pw.print(": "); - pw.print(" installed="); - pw.print(ps.getInstalled(user.id)); - pw.print(" stopped="); - pw.print(ps.getStopped(user.id)); - pw.print(" notLaunched="); - pw.print(ps.getNotLaunched(user.id)); - pw.print(" enabled="); - pw.println(ps.getEnabled(user.id)); - HashSet<String> cmp = ps.getDisabledComponents(user.id); - if (cmp != null && cmp.size() > 0) { - pw.println(" disabledComponents:"); - for (String s : cmp) { - pw.print(" "); pw.println(s); - } - } - cmp = ps.getEnabledComponents(user.id); - if (cmp != null && cmp.size() > 0) { - pw.println(" enabledComponents:"); - for (String s : cmp) { - pw.print(" "); pw.println(s); - } - } - } - if (ps.grantedPermissions.size() > 0) { - pw.println(" grantedPermissions:"); - for (String s : ps.grantedPermissions) { - pw.print(" "); pw.println(s); - } - } + dumpPackageLPr(pw, " ", ps, sdf, date, users); } printedSomething = false; @@ -2830,27 +2869,7 @@ final class Settings { pw.println("Hidden system packages:"); printedSomething = true; } - pw.print(" Package ["); - pw.print(ps.realName != null ? ps.realName : ps.name); - pw.print("] ("); - pw.print(Integer.toHexString(System.identityHashCode(ps))); - pw.println("):"); - if (ps.realName != null) { - pw.print(" compat name="); - pw.println(ps.name); - } - if (ps.pkg != null && ps.pkg.applicationInfo != null) { - pw.print(" applicationInfo="); - pw.println(ps.pkg.applicationInfo.toString()); - } - pw.print(" userId="); - pw.println(ps.appId); - pw.print(" sharedUser="); - pw.println(ps.sharedUser); - pw.print(" codePath="); - pw.println(ps.codePathString); - pw.print(" resourcePath="); - pw.println(ps.resourcePathString); + dumpPackageLPr(pw, " ", ps, sdf, date, users); } } } diff --git a/tests/SharedLibrary/client/Android.mk b/tests/SharedLibrary/client/Android.mk new file mode 100644 index 0000000..60ef92a --- /dev/null +++ b/tests/SharedLibrary/client/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_APK_LIBRARIES := SharedLibrary + +LOCAL_PACKAGE_NAME := SharedLibraryClient + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/SharedLibrary/client/AndroidManifest.xml b/tests/SharedLibrary/client/AndroidManifest.xml new file mode 100644 index 0000000..c6a43c0 --- /dev/null +++ b/tests/SharedLibrary/client/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.test.lib_client"> + <application android:label="@string/app_title"> + <uses-library android:name="android.test.runner" /> + <uses-library android:name="com.google.android.test.shared_library" /> + <activity android:name="ActivityMain"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/SharedLibrary/client/res/values/strings.xml b/tests/SharedLibrary/client/res/values/strings.xml new file mode 100644 index 0000000..3757a25 --- /dev/null +++ b/tests/SharedLibrary/client/res/values/strings.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_title">SharedLibrary client</string> +</resources> diff --git a/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java new file mode 100644 index 0000000..d6121a5 --- /dev/null +++ b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.lib_client; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; +import com.google.android.test.shared_library.SharedLibraryMain; + +public class ActivityMain extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + TextView content = new TextView(this); + content.setText("Library version: " + SharedLibraryMain.getVersion(this) + "!"); + + SharedLibraryMain.ensureVersion(this, SharedLibraryMain.VERSION_BASE); + setContentView(content); + } +} diff --git a/tests/SharedLibrary/lib/Android.mk b/tests/SharedLibrary/lib/Android.mk new file mode 100644 index 0000000..c19e23a --- /dev/null +++ b/tests/SharedLibrary/lib/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := SharedLibrary + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/SharedLibrary/lib/AndroidManifest.xml b/tests/SharedLibrary/lib/AndroidManifest.xml new file mode 100644 index 0000000..31fac20 --- /dev/null +++ b/tests/SharedLibrary/lib/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.test.shared_library" + android:versionCode="2"> + <application android:label="SharedLibrary"> + <library android:name="com.google.android.test.shared_library" /> + <activity android:name="ActivityMain"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/SharedLibrary/lib/res/values/strings.xml b/tests/SharedLibrary/lib/res/values/strings.xml new file mode 100644 index 0000000..bbfb0b4 --- /dev/null +++ b/tests/SharedLibrary/lib/res/values/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="upgrade_title">Upgrade required</string> + <string name="upgrade_body"><xliff:g id="app">%1$s</xliff:g> requires a newer version + of <xliff:g id="lib">%2$s</xliff:g> to run.</string> + <string name="upgrade_button">Upgrade</string> +</resources> diff --git a/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/ActivityMain.java b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/ActivityMain.java new file mode 100644 index 0000000..895aced --- /dev/null +++ b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/ActivityMain.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.shared_library; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +public class ActivityMain extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + TextView content = new TextView(this); + content.setText("Dummy main entry for this apk; not really needed..."); + setContentView(content); + } +} diff --git a/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/SharedLibraryMain.java b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/SharedLibraryMain.java new file mode 100644 index 0000000..c1cd925 --- /dev/null +++ b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/SharedLibraryMain.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.shared_library; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; + +public class SharedLibraryMain { + private static String LIBRARY_PACKAGE = "com.google.android.test.shared_library"; + + /** + * Base version of the library. + */ + public static int VERSION_BASE = 1; + + /** + * The second version of the library. + */ + public static int VERSION_SECOND = 2; + + public static int getVersion(Context context) { + PackageInfo pi = null; + try { + pi = context.getPackageManager().getPackageInfo(LIBRARY_PACKAGE, 0); + return pi.versionCode; + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalStateException("Can't find my package!", e); + } + } + + public static void ensureVersion(Activity activity, int minVersion) { + if (getVersion(activity) >= minVersion) { + return; + } + + // The current version of the library does not meet the required version. Show + // a dialog to inform the user and have them update to the current version. + // Note that updating the library will be necessity mean killing the current + // application (so it can be re-started with the new version, so there is no + // reason to return a result here. + final Context context; + try { + context = activity.createPackageContext(LIBRARY_PACKAGE, 0); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalStateException("Can't find my package!", e); + } + + // Display the dialog. Note that we don't need to deal with activity lifecycle + // stuff because if the activity gets recreated, it will first call through to + // ensureVersion(), causing us to either re-display the dialog if needed or let + // it now proceed. + final Resources res = context.getResources(); + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(res.getText(R.string.upgrade_title)); + builder.setMessage(res.getString(R.string.upgrade_body, + activity.getApplicationInfo().loadLabel(activity.getPackageManager()), + context.getApplicationInfo().loadLabel(context.getPackageManager()))); + builder.setPositiveButton(res.getText(R.string.upgrade_button), + new Dialog.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // Launch play store. + } + }); + builder.show(); + } +} |