Implement issue #2071750: add a pre-boot upgrade step.

Change-Id: I7133a03a6bf302dbac00c5f8b0420071d2453f89
This commit is contained in:
Dianne Hackborn
2009-08-25 00:27:12 -07:00
parent 1e09e9e0d0
commit 9acc030be4
2 changed files with 177 additions and 42 deletions

View File

@@ -1696,7 +1696,6 @@ public class Intent implements Parcelable {
public static final String ACTION_REBOOT = public static final String ACTION_REBOOT =
"android.intent.action.REBOOT"; "android.intent.action.REBOOT";
/** /**
* Broadcast Action: a remote intent is to be broadcasted. * Broadcast Action: a remote intent is to be broadcasted.
* *
@@ -1711,6 +1710,18 @@ public class Intent implements Parcelable {
public static final String ACTION_REMOTE_INTENT = public static final String ACTION_REMOTE_INTENT =
"android.intent.action.REMOTE_INTENT"; "android.intent.action.REMOTE_INTENT";
/**
* Broadcast Action: hook for permforming cleanup after a system update.
*
* The broadcast is sent when the system is booting, before the
* BOOT_COMPLETED broadcast. It is only sent to receivers in the system
* image. A receiver for this should do its work and then disable itself
* so that it does not get run again at the next boot.
* @hide
*/
public static final String ACTION_PRE_BOOT_COMPLETED =
"android.intent.action.PRE_BOOT_COMPLETED";
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Standard intent categories (see addCategory()). // Standard intent categories (see addCategory()).
@@ -2251,6 +2262,13 @@ public class Intent implements Parcelable {
* @hide * @hide
*/ */
public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000; public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000;
/**
* Set when this broadcast is for a boot upgrade, a special mode that
* allows the broadcast to be sent before the system is ready and launches
* the app process with no providers running in it.
* @hide
*/
public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x10000000;
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// --------------------------------------------------------------------- // ---------------------------------------------------------------------

View File

@@ -755,6 +755,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String mTopData; String mTopData;
boolean mSystemReady = false; boolean mSystemReady = false;
boolean mBooting = false; boolean mBooting = false;
boolean mWaitingUpdate = false;
boolean mDidUpdate = false;
Context mContext; Context mContext;
@@ -972,6 +974,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
res.set(0); res.set(0);
} }
} }
ensureBootCompleted();
} break; } break;
case SHOW_NOT_RESPONDING_MSG: { case SHOW_NOT_RESPONDING_MSG: {
synchronized (ActivityManagerService.this) { synchronized (ActivityManagerService.this) {
@@ -992,13 +996,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
proc.anrDialog = d; proc.anrDialog = d;
} }
ensureScreenEnabled(); ensureBootCompleted();
} break; } break;
case SHOW_FACTORY_ERROR_MSG: { case SHOW_FACTORY_ERROR_MSG: {
Dialog d = new FactoryErrorDialog( Dialog d = new FactoryErrorDialog(
mContext, msg.getData().getCharSequence("msg")); mContext, msg.getData().getCharSequence("msg"));
d.show(); d.show();
enableScreenAfterBoot(); ensureBootCompleted();
} break; } break;
case UPDATE_CONFIGURATION_MSG: { case UPDATE_CONFIGURATION_MSG: {
final ContentResolver resolver = mContext.getContentResolver(); final ContentResolver resolver = mContext.getContentResolver();
@@ -1843,12 +1847,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
startProcessLocked(r.processName, r.info.applicationInfo, true, 0, startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent()); "activity", r.intent.getComponent(), false);
} }
private final ProcessRecord startProcessLocked(String processName, private final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags, ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName) { String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
ProcessRecord app = getProcessRecordLocked(processName, info.uid); ProcessRecord app = getProcessRecordLocked(processName, info.uid);
// We don't have to do anything more if: // We don't have to do anything more if:
// (1) There is an existing application record; and // (1) There is an existing application record; and
@@ -1901,7 +1905,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If the system is not ready yet, then hold off on starting this // If the system is not ready yet, then hold off on starting this
// process until it is. // process until it is.
if (!mSystemReady if (!mSystemReady
&& (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { && !isAllowedWhileBooting(info)
&& !allowWhileBooting) {
if (!mProcessesOnHold.contains(app)) { if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app); mProcessesOnHold.add(app);
} }
@@ -1912,6 +1917,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return (app.pid != 0) ? app : null; return (app.pid != 0) ? app : null;
} }
boolean isAllowedWhileBooting(ApplicationInfo ai) {
return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
}
private final void startProcessLocked(ProcessRecord app, private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) { String hostingType, String hostingNameStr) {
if (app.pid > 0 && app.pid != MY_PID) { if (app.pid > 0 && app.pid != MY_PID) {
@@ -5085,7 +5094,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
List providers = generateApplicationProvidersLocked(app); boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
if (!normalMode) {
Log.i(TAG, "Launching preboot mode app: " + app);
}
if (localLOGV) Log.v( if (localLOGV) Log.v(
TAG, "New app record " + app TAG, "New app record " + app
@@ -5102,12 +5116,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mWaitForDebugger = mOrigWaitForDebugger; mWaitForDebugger = mOrigWaitForDebugger;
} }
} }
// If the app is being launched for restore or full backup, set it up specially // If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false; boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName)) { if (mBackupTarget != null && mBackupAppName.equals(processName)) {
isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE) isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL); || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
} }
ensurePackageDexOpt(app.instrumentationInfo != null ensurePackageDexOpt(app.instrumentationInfo != null
? app.instrumentationInfo.packageName ? app.instrumentationInfo.packageName
: app.info.packageName); : app.info.packageName);
@@ -5118,7 +5134,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
? app.instrumentationInfo : app.info, providers, ? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode, app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode, mConfiguration, getCommonServicesLocked()); isRestrictedBackupMode || !normalMode,
mConfiguration, getCommonServicesLocked());
updateLRUListLocked(app, false); updateLRUListLocked(app, false);
app.lastRequestedGc = SystemClock.uptimeMillis(); app.lastRequestedGc = SystemClock.uptimeMillis();
} catch (Exception e) { } catch (Exception e) {
@@ -5284,6 +5301,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
void enableScreenAfterBoot() { void enableScreenAfterBoot() {
EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot(); mWindowManager.enableScreenAfterBoot();
} }
@@ -5394,26 +5413,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
if (booting) { if (booting) {
// Ensure that any processes we had put on hold are now started finishBooting();
// up.
final int NP = mProcessesOnHold.size();
if (NP > 0) {
ArrayList<ProcessRecord> procs =
new ArrayList<ProcessRecord>(mProcessesOnHold);
for (int ip=0; ip<NP; ip++) {
this.startProcessLocked(procs.get(ip), "on-hold", null);
}
}
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
// Tell anyone interested that we are done booting!
synchronized (this) {
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_BOOT_COMPLETED, null),
null, null, 0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
false, false, MY_PID, Process.SYSTEM_UID);
}
}
} }
trimApplications(); trimApplications();
@@ -5421,22 +5421,48 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
//mWindowManager.dump(); //mWindowManager.dump();
if (enableScreen) { if (enableScreen) {
EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
enableScreenAfterBoot(); enableScreenAfterBoot();
} }
} }
final void ensureScreenEnabled() { final void finishBooting() {
// Ensure that any processes we had put on hold are now started
// up.
final int NP = mProcessesOnHold.size();
if (NP > 0) {
ArrayList<ProcessRecord> procs =
new ArrayList<ProcessRecord>(mProcessesOnHold);
for (int ip=0; ip<NP; ip++) {
this.startProcessLocked(procs.get(ip), "on-hold", null);
}
}
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
// Tell anyone interested that we are done booting!
synchronized (this) {
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_BOOT_COMPLETED, null),
null, null, 0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
false, false, MY_PID, Process.SYSTEM_UID);
}
}
}
final void ensureBootCompleted() {
boolean booting;
boolean enableScreen; boolean enableScreen;
synchronized (this) { synchronized (this) {
booting = mBooting;
mBooting = false;
enableScreen = !mBooted; enableScreen = !mBooted;
mBooted = true; mBooted = true;
} }
if (booting) {
finishBooting();
}
if (enableScreen) { if (enableScreen) {
EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
enableScreenAfterBoot(); enableScreenAfterBoot();
} }
} }
@@ -5588,6 +5614,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
throw new IllegalArgumentException("File descriptors passed in Intent"); throw new IllegalArgumentException("File descriptors passed in Intent");
} }
if (type == INTENT_SENDER_BROADCAST) {
if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
throw new IllegalArgumentException(
"Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
}
}
synchronized(this) { synchronized(this) {
int callingUid = Binder.getCallingUid(); int callingUid = Binder.getCallingUid();
try { try {
@@ -7398,7 +7431,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ProcessRecord proc = startProcessLocked(cpi.processName, ProcessRecord proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider", cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName, new ComponentName(cpi.applicationInfo.packageName,
cpi.name)); cpi.name), false);
if (proc == null) { if (proc == null) {
Log.w(TAG, "Unable to launch app " Log.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.packageName + "/"
@@ -8125,17 +8158,93 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mSystemReady) { if (mSystemReady) {
return; return;
} }
// Check to see if there are any update receivers to run.
if (!mDidUpdate) {
if (mWaitingUpdate) {
return;
}
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
List<ResolveInfo> ris = null;
try {
ris = ActivityThread.getPackageManager().queryIntentReceivers(
intent, null, 0);
} catch (RemoteException e) {
}
if (ris != null) {
for (int i=ris.size()-1; i>=0; i--) {
if ((ris.get(i).activityInfo.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) == 0) {
ris.remove(i);
}
}
intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
for (int i=0; i<ris.size(); i++) {
ActivityInfo ai = ris.get(i).activityInfo;
intent.setComponent(new ComponentName(ai.packageName, ai.name));
IIntentReceiver finisher = null;
if (i == 0) {
finisher = new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered)
throws RemoteException {
synchronized (ActivityManagerService.this) {
mDidUpdate = true;
}
systemReady();
}
};
}
Log.i(TAG, "Sending system update to: " + intent.getComponent());
broadcastIntentLocked(null, null, intent, null, finisher,
0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
if (i == 0) {
mWaitingUpdate = true;
}
}
}
if (mWaitingUpdate) {
return;
}
mDidUpdate = true;
}
mSystemReady = true; mSystemReady = true;
if (!mStartRunning) { if (!mStartRunning) {
return; return;
} }
} }
ArrayList<ProcessRecord> procsToKill = null;
synchronized(mPidsSelfLocked) {
for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
ProcessRecord proc = mPidsSelfLocked.valueAt(i);
if (!isAllowedWhileBooting(proc.info)){
if (procsToKill == null) {
procsToKill = new ArrayList<ProcessRecord>();
}
procsToKill.add(proc);
}
}
}
if (procsToKill != null) {
synchronized(this) {
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Log.i(TAG, "Removing system update proc: " + proc);
removeProcessLocked(proc, true);
}
}
}
if (Config.LOGD) Log.d(TAG, "Start running!"); if (Config.LOGD) Log.d(TAG, "Start running!");
EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY, EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
SystemClock.uptimeMillis()); SystemClock.uptimeMillis());
synchronized(this) { synchronized(this) {
// Make sure we have no pre-ready processes sitting around.
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
ResolveInfo ri = mContext.getPackageManager() ResolveInfo ri = mContext.getPackageManager()
.resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST), .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
@@ -8193,6 +8302,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
} }
// Start up initial activity.
mBooting = true;
try { try {
if (ActivityThread.getPackageManager().hasSystemUidErrors()) { if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
Message msg = Message.obtain(); Message msg = Message.obtain();
@@ -8202,8 +8314,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) { } catch (RemoteException e) {
} }
// Start up initial activity.
mBooting = true;
resumeTopActivityLocked(null); resumeTopActivityLocked(null);
} }
} }
@@ -10128,7 +10238,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Not running -- get it started, and enqueue this service record // Not running -- get it started, and enqueue this service record
// to be executed when the app comes up. // to be executed when the app comes up.
if (startProcessLocked(appName, r.appInfo, true, intentFlags, if (startProcessLocked(appName, r.appInfo, true, intentFlags,
"service", r.name) == null) { "service", r.name, false) == null) {
Log.w(TAG, "Unable to launch app " Log.w(TAG, "Unable to launch app "
+ r.appInfo.packageName + "/" + r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service " + r.appInfo.uid + " for service "
@@ -10930,7 +11040,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName); ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
// startProcessLocked() returns existing proc's record if it's already running // startProcessLocked() returns existing proc's record if it's already running
ProcessRecord proc = startProcessLocked(app.processName, app, ProcessRecord proc = startProcessLocked(app.processName, app,
false, 0, "backup", hostingName); false, 0, "backup", hostingName, false);
if (proc == null) { if (proc == null) {
Log.e(TAG, "Unable to start backup agent process " + r); Log.e(TAG, "Unable to start backup agent process " + r);
return false; return false;
@@ -11467,10 +11577,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
synchronized(this) { synchronized(this) {
int flags = intent.getFlags();
if (!mSystemReady) { if (!mSystemReady) {
// if the caller really truly claims to know what they're doing, go // if the caller really truly claims to know what they're doing, go
// ahead and allow the broadcast without launching any receivers // ahead and allow the broadcast without launching any receivers
int flags = intent.getFlags();
if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
intent = new Intent(intent); intent = new Intent(intent);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -11481,6 +11592,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
} }
if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
throw new IllegalArgumentException(
"Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
}
final ProcessRecord callerApp = getRecordForAppLocked(caller); final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid(); final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid();
@@ -12075,12 +12191,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// restart the application. // restart the application.
} }
// Not running -- get it started, and enqueue this history record // Not running -- get it started, to be executed when the app comes up.
// to be executed when the app comes up.
if ((r.curApp=startProcessLocked(targetProcess, if ((r.curApp=startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true, info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent)) == null) { "broadcast", r.curComponent,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
== null) {
// Ah, this recipient is unavailable. Finish it if necessary, // Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next. // and mark the broadcast record as ready for the next.
Log.w(TAG, "Unable to launch app " Log.w(TAG, "Unable to launch app "