diff options
author | Dianne Hackborn <hackbod@google.com> | 2012-10-09 14:00:30 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2012-10-09 17:57:14 -0700 |
commit | c0bd747b0605af251ff136277f14220a5a4c9818 (patch) | |
tree | 42c57d29d70cb1a8db3ad34da224ac3882481029 | |
parent | 840590dd642719f402491092944a12475d6d6a8e (diff) | |
download | frameworks_base-c0bd747b0605af251ff136277f14220a5a4c9818.zip frameworks_base-c0bd747b0605af251ff136277f14220a5a4c9818.tar.gz frameworks_base-c0bd747b0605af251ff136277f14220a5a4c9818.tar.bz2 |
Further work on issue #7307399: Framework needs a new pre-user-shutdown...
...phase & callback API
I realized there were a few things wrong with what was there. The new
ACTION_USER_STARTING was not being sent for the first user at boot, and
there was an existing problem where ACTION_USER_STARTED was sent every
time there was a user switch.
Also improved some debug output of broadcasts to make it easier to see
what is going on in this stuff, and better reporting of why a service
couldn't be started.
Change-Id: Id8a536defbbad1f73d94a37d13762436b822fbe3
6 files changed, 131 insertions, 50 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 3df88bb..add7a23 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -415,6 +415,10 @@ public class Am { ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId); if (cn == null) { System.err.println("Error: Not found; no service started."); + } else if (cn.getPackageName().equals("!")) { + System.err.println("Error: Requires permission " + cn.getClassName()); + } else if (cn.getPackageName().equals("!!")) { + System.err.println("Error: " + cn.getClassName()); } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index c324da9..3e1e358 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1352,10 +1352,16 @@ class ContextImpl extends Context { ComponentName cn = ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier()); - if (cn != null && cn.getPackageName().equals("!")) { - throw new SecurityException( - "Not allowed to start service " + service - + " without permission " + cn.getClassName()); + if (cn != null) { + if (cn.getPackageName().equals("!")) { + throw new SecurityException( + "Not allowed to start service " + service + + " without permission " + cn.getClassName()); + } else if (cn.getPackageName().equals("!!")) { + throw new SecurityException( + "Unable to start service " + service + + ": " + cn.getClassName()); + } } return cn; } catch (RemoteException e) { diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 7e3fdbd..35999ea 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -248,8 +248,9 @@ public class ActiveServices { synchronized (r.stats.getBatteryStats()) { r.stats.startRunningLocked(); } - if (!bringUpServiceLocked(r, service.getFlags(), false)) { - return new ComponentName("!", "Service process is bad"); + String error = bringUpServiceLocked(r, service.getFlags(), false); + if (error != null) { + return new ComponentName("!!", error); } return r.name; } @@ -518,7 +519,7 @@ public class ActiveServices { if ((flags&Context.BIND_AUTO_CREATE) != 0) { s.lastActivity = SystemClock.uptimeMillis(); - if (!bringUpServiceLocked(s, service.getFlags(), false)) { + if (bringUpServiceLocked(s, service.getFlags(), false) != null) { return 0; } } @@ -964,19 +965,19 @@ public class ActiveServices { return true; } - private final boolean bringUpServiceLocked(ServiceRecord r, + private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean whileRestarting) { //Slog.i(TAG, "Bring up service:"); //r.dump(" "); if (r.app != null && r.app.thread != null) { sendServiceArgsLocked(r, false); - return true; + return null; } if (!whileRestarting && r.restartDelay > 0) { // If waiting for a restart, then do nothing. - return true; + return null; } if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent); @@ -988,12 +989,13 @@ public class ActiveServices { // Make sure that the user who owns this service is started. If not, // we don't want to allow it to run. if (mAm.mStartedUsers.get(r.userId) == null) { - Slog.w(TAG, "Unable to launch app " + String msg = "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " - + r.intent.getIntent() + ": user " + r.userId + " is stopped"); + + r.intent.getIntent() + ": user " + r.userId + " is stopped"; + Slog.w(TAG, msg); bringDownServiceLocked(r, true); - return false; + return msg; } // Service is now being launched, its package can't be stopped. @@ -1018,7 +1020,7 @@ public class ActiveServices { try { app.addPackage(r.appInfo.packageName); realStartServiceLocked(r, app); - return true; + return null; } catch (RemoteException e) { Slog.w(TAG, "Exception when starting service " + r.shortName, e); } @@ -1041,12 +1043,13 @@ public class ActiveServices { if (app == null) { if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated)) == null) { - Slog.w(TAG, "Unable to launch app " + String msg = "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " - + r.intent.getIntent() + ": process is bad"); + + r.intent.getIntent() + ": process is bad"; + Slog.w(TAG, msg); bringDownServiceLocked(r, true); - return false; + return msg; } if (isolated) { r.isolatedProc = app; @@ -1057,7 +1060,7 @@ public class ActiveServices { mPendingServices.add(r); } - return true; + return null; } private final void requestServiceBindingsLocked(ServiceRecord r) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 6b7e29c..daed0a2 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3739,7 +3739,8 @@ public final class ActivityManagerService extends ActivityManagerNative private void forceStopUserLocked(int userId) { forceStopPackageLocked(null, -1, false, false, true, false, userId); Intent intent = new Intent(Intent.ACTION_USER_STOPPED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, @@ -7904,6 +7905,19 @@ public final class ActivityManagerService extends ActivityManagerNative broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId); + intent = new Intent(Intent.ACTION_USER_STARTING); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId); + broadcastIntentLocked(null, null, intent, + null, new IIntentReceiver.Stub() { + @Override + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean ordered, boolean sticky, int sendingUser) + throws RemoteException { + } + }, 0, null, null, + android.Manifest.permission.INTERACT_ACROSS_USERS, + false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); } @@ -8879,7 +8893,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" [-a] [-c] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); pw.println(" a[ctivities]: activity stack state"); - pw.println(" b[roadcasts] [PACKAGE_NAME]: broadcast state"); + pw.println(" b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state"); pw.println(" i[ntents] [PACKAGE_NAME]: pending intent state"); pw.println(" p[rocesses] [PACKAGE_NAME]: process state"); pw.println(" o[om]: out of memory management"); @@ -9713,6 +9727,9 @@ public final class ActivityManagerService extends ActivityManagerNative boolean onlyHistory = false; if ("history".equals(dumpPackage)) { + if (opti < args.length && "-s".equals(args[opti])) { + dumpAll = false; + } onlyHistory = true; dumpPackage = null; } @@ -14112,11 +14129,14 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.startFreezingScreen(R.anim.screen_user_exit, R.anim.screen_user_enter); + boolean needStart = false; + // If the user we are switching to is not currently started, then // we need to start it now. if (mStartedUsers.get(userId) == null) { mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false)); updateStartedUserArrayLocked(); + needStart = true; } mCurrentUserId = userId; @@ -14141,11 +14161,13 @@ public final class ActivityManagerService extends ActivityManagerNative // the almost-dead. uss.mState = UserStartedState.STATE_RUNNING; updateStartedUserArrayLocked(); + needStart = true; } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) { // This means ACTION_SHUTDOWN has been sent, so we will // need to treat this as a new boot of the user. uss.mState = UserStartedState.STATE_BOOTING; updateStartedUserArrayLocked(); + needStart = true; } mHandler.removeMessages(REPORT_USER_SWITCH_MSG); @@ -14154,17 +14176,19 @@ public final class ActivityManagerService extends ActivityManagerNative oldUserId, userId, uss)); mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG, oldUserId, userId, uss), USER_SWITCH_TIMEOUT); - Intent intent = new Intent(Intent.ACTION_USER_STARTED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY - | Intent.FLAG_RECEIVER_FOREGROUND); - intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - broadcastIntentLocked(null, null, intent, - null, null, 0, null, null, null, - false, false, MY_PID, Process.SYSTEM_UID, userId); + if (needStart) { + Intent intent = new Intent(Intent.ACTION_USER_STARTED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + broadcastIntentLocked(null, null, intent, + null, null, 0, null, null, null, + false, false, MY_PID, Process.SYSTEM_UID, userId); + } if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) { if (userId != 0) { - intent = new Intent(Intent.ACTION_USER_INITIALIZE); + Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntentLocked(null, null, intent, null, new IIntentReceiver.Stub() { @@ -14188,6 +14212,21 @@ public final class ActivityManagerService extends ActivityManagerNative getUserManagerLocked().userForeground(userId); sendUserSwitchBroadcastsLocked(oldUserId, userId); + if (needStart) { + Intent intent = new Intent(Intent.ACTION_USER_STARTING); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + broadcastIntentLocked(null, null, intent, + null, new IIntentReceiver.Stub() { + @Override + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean ordered, boolean sticky, int sendingUser) + throws RemoteException { + } + }, 0, null, null, + android.Manifest.permission.INTERACT_ACROSS_USERS, + false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + } } } finally { Binder.restoreCallingIdentity(ident); @@ -14225,19 +14264,6 @@ public final class ActivityManagerService extends ActivityManagerNative null, null, 0, null, null, android.Manifest.permission.MANAGE_USERS, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); - intent = new Intent(Intent.ACTION_USER_STARTING); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId); - broadcastIntentLocked(null, null, intent, - null, new IIntentReceiver.Stub() { - @Override - public void performReceive(Intent intent, int resultCode, String data, - Bundle extras, boolean ordered, boolean sticky, int sendingUser) - throws RemoteException { - } - }, 0, null, null, - android.Manifest.permission.INTERACT_ACROSS_USERS, - false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index 95c22ec..f9630ae 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -54,6 +54,7 @@ public class BroadcastQueue { static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU; static final int MAX_BROADCAST_HISTORY = 25; + static final int MAX_BROADCAST_SUMMARY_HISTORY = 100; final ActivityManagerService mService; @@ -93,6 +94,12 @@ public class BroadcastQueue { = new BroadcastRecord[MAX_BROADCAST_HISTORY]; /** + * Summary of historical data of past broadcasts, for debugging. + */ + final Intent[] mBroadcastSummaryHistory + = new Intent[MAX_BROADCAST_SUMMARY_HISTORY]; + + /** * Set when we current have a BROADCAST_INTENT_MSG in flight. */ boolean mBroadcastsScheduled = false; @@ -922,6 +929,9 @@ public class BroadcastQueue { MAX_BROADCAST_HISTORY-1); r.finishTime = SystemClock.uptimeMillis(); mBroadcastHistory[0] = r; + System.arraycopy(mBroadcastSummaryHistory, 0, mBroadcastSummaryHistory, 1, + MAX_BROADCAST_SUMMARY_HISTORY-1); + mBroadcastSummaryHistory[0] = r.intent; } final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) { @@ -1006,8 +1016,9 @@ public class BroadcastQueue { } } + int i; boolean printed = false; - for (int i=0; i<MAX_BROADCAST_HISTORY; i++) { + for (i=0; i<MAX_BROADCAST_HISTORY; i++) { BroadcastRecord r = mBroadcastHistory[i]; if (r == null) { break; @@ -1028,11 +1039,44 @@ public class BroadcastQueue { pw.print(i); pw.println(":"); r.dump(pw, " "); } else { - if (i >= 50) { + pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r); + pw.print(" "); + pw.println(r.intent.toShortString(false, true, true, false)); + Bundle bundle = r.intent.getExtras(); + if (bundle != null) { + pw.print(" extras: "); pw.println(bundle.toString()); + } + } + } + + if (dumpPackage == null) { + if (dumpAll) { + i = 0; + printed = false; + } + for (; i<MAX_BROADCAST_SUMMARY_HISTORY; i++) { + Intent intent = mBroadcastSummaryHistory[i]; + if (intent == null) { + break; + } + if (!printed) { + if (needSep) { + pw.println(); + } + needSep = true; + pw.println(" Historical broadcasts summary [" + mQueueName + "]:"); + printed = true; + } + if (!dumpAll && i >= 50) { pw.println(" ..."); break; } - pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r); + pw.print(" #"); pw.print(i); pw.print(": "); + pw.println(intent.toShortString(false, true, true, false)); + Bundle bundle = intent.getExtras(); + if (bundle != null) { + pw.print(" extras: "); pw.println(bundle.toString()); + } } } diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java index 85ec328..1cf5b9c 100644 --- a/services/java/com/android/server/am/BroadcastRecord.java +++ b/services/java/com/android/server/am/BroadcastRecord.java @@ -81,12 +81,10 @@ class BroadcastRecord extends Binder { final long now = SystemClock.uptimeMillis(); 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(); - if (bundle != null) { - pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString()); - } + pw.print(prefix); pw.println(intent.toInsecureString()); + Bundle bundle = intent.getExtras(); + if (bundle != null) { + pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString()); } pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.print(" "); pw.print(callerApp != null ? callerApp.toShortString() : "null"); |