Fix installing applications from non-primary users.
We also now send the correct broadcasts to each user.
You no longer need to be running the shell as root
to be able to create/remove users.
Also added some more man page material to the pm command, and
got rid of a bunch of showUsage() calls that now make error
messages completely buried because of how large the usage info
has become.
And the package manager now shows the user each historical broadcast
was sent to.
Change-Id: Iab42498e1352a0c023069139c80fc04d2d69ab4b
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2b4f8b1..5921d88 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9404,9 +9404,15 @@
boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
boolean needSep = false;
-
+ boolean onlyHistory = false;
+
+ if ("history".equals(dumpPackage)) {
+ onlyHistory = true;
+ dumpPackage = null;
+ }
+
pw.println("ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)");
- if (dumpAll) {
+ if (!onlyHistory && dumpAll) {
if (mRegisteredReceivers.size() > 0) {
boolean printed = false;
Iterator it = mRegisteredReceivers.values().iterator();
@@ -9439,7 +9445,7 @@
needSep = true;
- if (mStickyBroadcasts != null && dumpPackage == null) {
+ if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
if (needSep) {
pw.println();
}
@@ -9471,7 +9477,7 @@
needSep = true;
}
- if (dumpAll) {
+ if (!onlyHistory && dumpAll) {
pw.println();
for (BroadcastQueue queue : mBroadcastQueues) {
pw.println(" mBroadcastsScheduled [" + queue.mQueueName + "]="
@@ -10982,7 +10988,7 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, receivers, null, 0, null, null,
- false, true, true, false);
+ false, true, true, false, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
@@ -11288,7 +11294,7 @@
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
registeredReceivers, resultTo, resultCode, resultData, map,
- ordered, sticky, false, onlySendToCaller);
+ ordered, sticky, false, onlySendToCaller, userId);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
@@ -11378,7 +11384,7 @@
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
receivers, resultTo, resultCode, resultData, map, ordered,
- sticky, false, onlySendToCaller);
+ sticky, false, onlySendToCaller, userId);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 799b609..87f1111 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -45,6 +45,7 @@
final boolean sticky; // originated from existing sticky data?
final boolean initialSticky; // initial broadcast from register to sticky?
final boolean onlySendToCaller; // only allow receipt by sender's components?
+ final int userId; // user id this broadcast was for
final String requiredPermission; // a permission the caller has required
final List receivers; // contains BroadcastFilter and ResolveInfo
IIntentReceiver resultTo; // who receives final result if non-null
@@ -80,7 +81,7 @@
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
- pw.print(prefix); pw.println(this);
+ pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
pw.print(prefix); pw.println(intent);
if (sticky) {
Bundle bundle = intent.getExtras();
@@ -141,14 +142,15 @@
pw.println(curReceiver.applicationInfo.sourceDir);
}
}
- String stateStr = " (?)";
- switch (state) {
- case IDLE: stateStr=" (IDLE)"; break;
- case APP_RECEIVE: stateStr=" (APP_RECEIVE)"; break;
- case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break;
- case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+ if (state != IDLE) {
+ String stateStr = " (?)";
+ switch (state) {
+ case APP_RECEIVE: stateStr=" (APP_RECEIVE)"; break;
+ case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break;
+ case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+ }
+ pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
}
- pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
final int N = receivers != null ? receivers.size() : 0;
String p2 = prefix + " ";
PrintWriterPrinter printer = new PrintWriterPrinter(pw);
@@ -168,7 +170,8 @@
int _callingPid, int _callingUid, String _requiredPermission,
List _receivers, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized,
- boolean _sticky, boolean _initialSticky, boolean _onlySendToCaller) {
+ boolean _sticky, boolean _initialSticky, boolean _onlySendToCaller,
+ int _userId) {
queue = _queue;
intent = _intent;
callerApp = _callerApp;
@@ -185,6 +188,7 @@
sticky = _sticky;
initialSticky = _initialSticky;
onlySendToCaller = _onlySendToCaller;
+ userId = _userId;
nextReceiver = 0;
state = IDLE;
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 0345df1..65d1882 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -704,20 +704,56 @@
res.removedInfo.sendBroadcast(false, true);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
+ // Determine the set of users who are adding this
+ // package for the first time vs. those who are seeing
+ // an update.
+ int[] firstUsers;
+ int[] updateUsers = new int[0];
+ if (res.origUsers == null || res.origUsers.length == 0) {
+ firstUsers = res.newUsers;
+ } else {
+ firstUsers = new int[0];
+ for (int i=0; i<res.newUsers.length; i++) {
+ int user = res.newUsers[i];
+ boolean isNew = true;
+ for (int j=0; j<res.origUsers.length; j++) {
+ if (res.origUsers[j] == user) {
+ isNew = false;
+ break;
+ }
+ }
+ if (isNew) {
+ int[] newFirst = new int[firstUsers.length+1];
+ System.arraycopy(firstUsers, 0, newFirst, 0,
+ firstUsers.length);
+ newFirst[firstUsers.length] = user;
+ firstUsers = newFirst;
+ } else {
+ int[] newUpdate = new int[updateUsers.length+1];
+ System.arraycopy(updateUsers, 0, newUpdate, 0,
+ updateUsers.length);
+ newUpdate[updateUsers.length] = user;
+ updateUsers = newUpdate;
+ }
+ }
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ res.pkg.applicationInfo.packageName,
+ extras, null, null, firstUsers);
final boolean update = res.removedInfo.removedPackage != null;
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
- extras, null, null, res.users);
+ extras, null, null, updateUsers);
if (update) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
res.pkg.applicationInfo.packageName,
- extras, null, null, res.users);
+ extras, null, null, updateUsers);
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null, null,
- res.pkg.applicationInfo.packageName, null, res.users);
+ res.pkg.applicationInfo.packageName, null, updateUsers);
}
if (res.removedInfo.args != null) {
// Remove the replaced package's older resources safely now
@@ -5337,8 +5373,10 @@
public void onEvent(int event, String path) {
String removedPackage = null;
int removedUid = -1;
+ int[] removedUsers = null;
String addedPackage = null;
int addedUid = -1;
+ int[] addedUsers = null;
// TODO post a message to the handler to obtain serial ordering
synchronized (mInstallLock) {
@@ -5367,6 +5405,15 @@
// reader
synchronized (mPackages) {
p = mAppDirs.get(fullPathStr);
+ if (p != null) {
+ PackageSetting ps = mSettings.mPackages.get(p.applicationInfo.packageName);
+ if (ps != null) {
+ removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+ } else {
+ removedUsers = sUserManager.getUserIds();
+ }
+ }
+ addedUsers = sUserManager.getUserIds();
}
if ((event&REMOVE_EVENTS) != 0) {
if (p != null) {
@@ -5384,7 +5431,7 @@
PackageParser.PARSE_CHATTY |
PackageParser.PARSE_MUST_BE_APK,
SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
- System.currentTimeMillis(), null);
+ System.currentTimeMillis(), UserHandle.ALL);
if (p != null) {
/*
* TODO this seems dangerous as the package may have
@@ -5413,13 +5460,13 @@
extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
- extras, null, null, null);
+ extras, null, null, removedUsers);
}
if (addedPackage != null) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, addedUid);
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
- extras, null, null, null);
+ extras, null, null, addedUsers);
}
}
@@ -5462,7 +5509,7 @@
if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
- user = Process.myUserHandle();
+ user = new UserHandle(UserHandle.getUserId(uid));
}
final int filteredFlags;
@@ -7205,7 +7252,10 @@
class PackageInstalledInfo {
String name;
int uid;
- int[] users;
+ // The set of users that originally had this package installed.
+ int[] origUsers;
+ // The set of users that now have this package installed.
+ int[] newUsers;
PackageParser.Package pkg;
int returnCode;
PackageRemovedInfo removedInfo;
@@ -7355,7 +7405,7 @@
int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE
| SCAN_UPDATE_TIME;
if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode,
- origUpdateTime, user) == null) {
+ origUpdateTime, null) == null) {
Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
return;
}
@@ -7504,10 +7554,6 @@
UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
? UPDATE_PERMISSIONS_ALL : 0));
res.name = pkgName;
- PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- res.users = ps.getInstalledUsers(sUserManager.getUserIds());
- }
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
@@ -7605,6 +7651,7 @@
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
+ res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
@@ -7627,12 +7674,12 @@
installerPackageName, res);
} else {
installNewPackageLI(pkg, parseFlags, scanMode, args.user,
- installerPackageName,res);
+ installerPackageName, res);
}
synchronized (mPackages) {
- PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
- res.users = ps.getInstalledUsers(sUserManager.getUserIds());
+ res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
}
@@ -7858,7 +7905,8 @@
if (outInfo != null) {
outInfo.removedPackage = packageName;
outInfo.removedUsers = deletedPs != null
- ? deletedPs.getInstalledUsers(sUserManager.getUserIds()) : null;
+ ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)
+ : null;
}
}
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index 6d31f0e..d8f7345 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -210,17 +210,17 @@
return false;
}
- int[] getInstalledUsers(int[] users) {
+ int[] queryInstalledUsers(int[] users, boolean installed) {
int num = 0;
for (int user : users) {
- if (getInstalled(user)) {
+ if (getInstalled(user) == installed) {
num++;
}
}
int[] res = new int[num];
num = 0;
for (int user : users) {
- if (getInstalled(user)) {
+ if (getInstalled(user) == installed) {
res[num] = user;
num++;
}