summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/PackageManager.java11
-rw-r--r--core/java/android/content/pm/PackageParser.java25
-rw-r--r--core/res/res/values/attrs_manifest.xml15
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java473
-rw-r--r--services/java/com/android/server/pm/Settings.java297
-rw-r--r--tests/SharedLibrary/client/Android.mk12
-rw-r--r--tests/SharedLibrary/client/AndroidManifest.xml29
-rw-r--r--tests/SharedLibrary/client/res/values/strings.xml19
-rw-r--r--tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java35
-rw-r--r--tests/SharedLibrary/lib/Android.mk10
-rw-r--r--tests/SharedLibrary/lib/AndroidManifest.xml29
-rw-r--r--tests/SharedLibrary/lib/res/values/strings.xml22
-rw-r--r--tests/SharedLibrary/lib/src/com/google/android/test/shared_library/ActivityMain.java32
-rw-r--r--tests/SharedLibrary/lib/src/com/google/android/test/shared_library/SharedLibraryMain.java87
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();
+ }
+}