Merge "Wait for uncrypt to finish before rebooting"
This commit is contained in:
@@ -71,6 +71,7 @@ public class RecoverySystem {
|
|||||||
/** Used to communicate with recovery. See bootable/recovery/recovery.c. */
|
/** Used to communicate with recovery. See bootable/recovery/recovery.c. */
|
||||||
private static File RECOVERY_DIR = new File("/cache/recovery");
|
private static File RECOVERY_DIR = new File("/cache/recovery");
|
||||||
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
|
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
|
||||||
|
private static File UNCRYPT_FILE = new File(RECOVERY_DIR, "uncrypt_file");
|
||||||
private static File LOG_FILE = new File(RECOVERY_DIR, "log");
|
private static File LOG_FILE = new File(RECOVERY_DIR, "log");
|
||||||
private static String LAST_PREFIX = "last_";
|
private static String LAST_PREFIX = "last_";
|
||||||
|
|
||||||
@@ -333,8 +334,21 @@ public class RecoverySystem {
|
|||||||
public static void installPackage(Context context, File packageFile)
|
public static void installPackage(Context context, File packageFile)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String filename = packageFile.getCanonicalPath();
|
String filename = packageFile.getCanonicalPath();
|
||||||
|
|
||||||
|
FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE);
|
||||||
|
try {
|
||||||
|
uncryptFile.write(filename + "\n");
|
||||||
|
} finally {
|
||||||
|
uncryptFile.close();
|
||||||
|
}
|
||||||
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
|
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
|
||||||
|
|
||||||
|
// If the package is on the /data partition, write the block map file
|
||||||
|
// into COMMAND_FILE instead.
|
||||||
|
if (filename.startsWith("/data/")) {
|
||||||
|
filename = "@/cache/recovery/block.map";
|
||||||
|
}
|
||||||
|
|
||||||
final String filenameArg = "--update_package=" + filename;
|
final String filenameArg = "--update_package=" + filename;
|
||||||
final String localeArg = "--locale=" + Locale.getDefault().toString();
|
final String localeArg = "--locale=" + Locale.getDefault().toString();
|
||||||
bootCommand(context, filenameArg, localeArg);
|
bootCommand(context, filenameArg, localeArg);
|
||||||
|
|||||||
@@ -393,6 +393,10 @@
|
|||||||
<!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] -->
|
<!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] -->
|
||||||
<string name="silent_mode_ring">Ringer on</string>
|
<string name="silent_mode_ring">Ringer on</string>
|
||||||
|
|
||||||
|
<!-- Reboot to Recovery Progress Dialog. This is shown before it reboots to recovery. -->
|
||||||
|
<string name="reboot_to_recovery_title">Prepare for update</string>
|
||||||
|
<string name="reboot_to_recovery_progress">Processing the update package\u2026</string>
|
||||||
|
|
||||||
<!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
|
<!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
|
||||||
<string name="shutdown_progress">Shutting down\u2026</string>
|
<string name="shutdown_progress">Shutting down\u2026</string>
|
||||||
|
|
||||||
|
|||||||
@@ -780,6 +780,8 @@
|
|||||||
<java-symbol type="string" name="mobile_provisioning_url" />
|
<java-symbol type="string" name="mobile_provisioning_url" />
|
||||||
<java-symbol type="string" name="mobile_redirected_provisioning_url" />
|
<java-symbol type="string" name="mobile_redirected_provisioning_url" />
|
||||||
<java-symbol type="string" name="quick_contacts_not_available" />
|
<java-symbol type="string" name="quick_contacts_not_available" />
|
||||||
|
<java-symbol type="string" name="reboot_to_recovery_progress" />
|
||||||
|
<java-symbol type="string" name="reboot_to_recovery_title" />
|
||||||
<java-symbol type="string" name="reboot_safemode_confirm" />
|
<java-symbol type="string" name="reboot_safemode_confirm" />
|
||||||
<java-symbol type="string" name="reboot_safemode_title" />
|
<java-symbol type="string" name="reboot_safemode_title" />
|
||||||
<java-symbol type="string" name="relationTypeAssistant" />
|
<java-symbol type="string" name="relationTypeAssistant" />
|
||||||
|
|||||||
@@ -2357,8 +2357,7 @@ public final class PowerManagerService extends SystemService
|
|||||||
/**
|
/**
|
||||||
* Low-level function to reboot the device. On success, this
|
* Low-level function to reboot the device. On success, this
|
||||||
* function doesn't return. If more than 20 seconds passes from
|
* function doesn't return. If more than 20 seconds passes from
|
||||||
* the time a reboot is requested (120 seconds for reboot to
|
* the time a reboot is requested, this method returns.
|
||||||
* recovery), this method returns.
|
|
||||||
*
|
*
|
||||||
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
|
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
|
||||||
*/
|
*/
|
||||||
@@ -2366,27 +2365,21 @@ public final class PowerManagerService extends SystemService
|
|||||||
if (reason == null) {
|
if (reason == null) {
|
||||||
reason = "";
|
reason = "";
|
||||||
}
|
}
|
||||||
long duration;
|
|
||||||
if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
|
if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
|
||||||
// If we are rebooting to go into recovery, instead of
|
// If we are rebooting to go into recovery, instead of
|
||||||
// setting sys.powerctl directly we'll start the
|
// setting sys.powerctl directly we'll start the
|
||||||
// pre-recovery service which will do some preparation for
|
// pre-recovery service which will do some preparation for
|
||||||
// recovery and then reboot for us.
|
// recovery and then reboot for us.
|
||||||
//
|
|
||||||
// This preparation can take more than 20 seconds if
|
|
||||||
// there's a very large update package, so lengthen the
|
|
||||||
// timeout. We have seen 750MB packages take 3-4 minutes
|
|
||||||
SystemProperties.set("ctl.start", "pre-recovery");
|
SystemProperties.set("ctl.start", "pre-recovery");
|
||||||
duration = 300 * 1000L;
|
|
||||||
} else {
|
} else {
|
||||||
SystemProperties.set("sys.powerctl", "reboot," + reason);
|
SystemProperties.set("sys.powerctl", "reboot," + reason);
|
||||||
duration = 20 * 1000L;
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Thread.sleep(duration);
|
Thread.sleep(20 * 1000L);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
|
Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // Watchdog.Monitor implementation
|
@Override // Watchdog.Monitor implementation
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ import android.os.Vibrator;
|
|||||||
import android.os.SystemVibrator;
|
import android.os.SystemVibrator;
|
||||||
import android.os.storage.IMountService;
|
import android.os.storage.IMountService;
|
||||||
import android.os.storage.IMountShutdownObserver;
|
import android.os.storage.IMountShutdownObserver;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.Os;
|
||||||
|
|
||||||
import com.android.internal.telephony.ITelephony;
|
import com.android.internal.telephony.ITelephony;
|
||||||
import com.android.server.pm.PackageManagerService;
|
import com.android.server.pm.PackageManagerService;
|
||||||
@@ -50,6 +52,11 @@ import com.android.server.pm.PackageManagerService;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public final class ShutdownThread extends Thread {
|
public final class ShutdownThread extends Thread {
|
||||||
// constants
|
// constants
|
||||||
private static final String TAG = "ShutdownThread";
|
private static final String TAG = "ShutdownThread";
|
||||||
@@ -58,6 +65,7 @@ public final class ShutdownThread extends Thread {
|
|||||||
private static final int MAX_BROADCAST_TIME = 10*1000;
|
private static final int MAX_BROADCAST_TIME = 10*1000;
|
||||||
private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
|
private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
|
||||||
private static final int MAX_RADIO_WAIT_TIME = 12*1000;
|
private static final int MAX_RADIO_WAIT_TIME = 12*1000;
|
||||||
|
private static final int MAX_UNCRYPT_WAIT_TIME = 15*60*1000;
|
||||||
|
|
||||||
// length of vibration before shutting down
|
// length of vibration before shutting down
|
||||||
private static final int SHUTDOWN_VIBRATE_MS = 500;
|
private static final int SHUTDOWN_VIBRATE_MS = 500;
|
||||||
@@ -66,6 +74,9 @@ public final class ShutdownThread extends Thread {
|
|||||||
private static Object sIsStartedGuard = new Object();
|
private static Object sIsStartedGuard = new Object();
|
||||||
private static boolean sIsStarted = false;
|
private static boolean sIsStarted = false;
|
||||||
|
|
||||||
|
// uncrypt status file
|
||||||
|
private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
|
||||||
|
|
||||||
private static boolean mReboot;
|
private static boolean mReboot;
|
||||||
private static boolean mRebootSafeMode;
|
private static boolean mRebootSafeMode;
|
||||||
private static String mRebootReason;
|
private static String mRebootReason;
|
||||||
@@ -93,6 +104,7 @@ public final class ShutdownThread extends Thread {
|
|||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
|
|
||||||
private static AlertDialog sConfirmDialog;
|
private static AlertDialog sConfirmDialog;
|
||||||
|
private ProgressDialog mProgressDialog;
|
||||||
|
|
||||||
private ShutdownThread() {
|
private ShutdownThread() {
|
||||||
}
|
}
|
||||||
@@ -220,7 +232,11 @@ public final class ShutdownThread extends Thread {
|
|||||||
// throw up an indeterminate system dialog to indicate radio is
|
// throw up an indeterminate system dialog to indicate radio is
|
||||||
// shutting down.
|
// shutting down.
|
||||||
ProgressDialog pd = new ProgressDialog(context);
|
ProgressDialog pd = new ProgressDialog(context);
|
||||||
|
if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
|
||||||
|
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_recovery_title));
|
||||||
|
} else {
|
||||||
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
|
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
|
||||||
|
}
|
||||||
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
|
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
|
||||||
pd.setIndeterminate(true);
|
pd.setIndeterminate(true);
|
||||||
pd.setCancelable(false);
|
pd.setCancelable(false);
|
||||||
@@ -228,6 +244,7 @@ public final class ShutdownThread extends Thread {
|
|||||||
|
|
||||||
pd.show();
|
pd.show();
|
||||||
|
|
||||||
|
sInstance.mProgressDialog = pd;
|
||||||
sInstance.mContext = context;
|
sInstance.mContext = context;
|
||||||
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
||||||
|
|
||||||
@@ -384,9 +401,55 @@ public final class ShutdownThread extends Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it's to reboot into recovery, invoke uncrypt via init service.
|
||||||
|
if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
|
||||||
|
uncrypt();
|
||||||
|
}
|
||||||
|
|
||||||
rebootOrShutdown(mContext, mReboot, mRebootReason);
|
rebootOrShutdown(mContext, mReboot, mRebootReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void prepareUncryptProgress() {
|
||||||
|
// Reset the dialog message to show the decrypt process.
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mProgressDialog != null) {
|
||||||
|
mProgressDialog.dismiss();
|
||||||
|
}
|
||||||
|
// It doesn't work to change the style of the existing
|
||||||
|
// one. Have to create a new one.
|
||||||
|
ProgressDialog pd = new ProgressDialog(mContext);
|
||||||
|
|
||||||
|
pd.setTitle(mContext.getText(
|
||||||
|
com.android.internal.R.string.reboot_to_recovery_title));
|
||||||
|
pd.setMessage(mContext.getText(
|
||||||
|
com.android.internal.R.string.reboot_to_recovery_progress));
|
||||||
|
pd.setIndeterminate(false);
|
||||||
|
pd.setMax(100);
|
||||||
|
pd.setCancelable(false);
|
||||||
|
pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
|
||||||
|
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
pd.setProgressNumberFormat(null);
|
||||||
|
pd.setProgress(0);
|
||||||
|
|
||||||
|
mProgressDialog = pd;
|
||||||
|
mProgressDialog.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUncryptProgress(final int progress) {
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mProgressDialog != null) {
|
||||||
|
mProgressDialog.setProgress(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void shutdownRadios(int timeout) {
|
private void shutdownRadios(int timeout) {
|
||||||
// If a radio is wedged, disabling it may hang so we do this work in another thread,
|
// If a radio is wedged, disabling it may hang so we do this work in another thread,
|
||||||
// just in case.
|
// just in case.
|
||||||
@@ -531,4 +594,78 @@ public final class ShutdownThread extends Thread {
|
|||||||
Log.i(TAG, "Performing low-level shutdown...");
|
Log.i(TAG, "Performing low-level shutdown...");
|
||||||
PowerManagerService.lowLevelShutdown();
|
PowerManagerService.lowLevelShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void uncrypt() {
|
||||||
|
Log.i(TAG, "Calling uncrypt and monitoring the progress...");
|
||||||
|
|
||||||
|
// Update the ProcessDialog message and style.
|
||||||
|
sInstance.prepareUncryptProgress();
|
||||||
|
|
||||||
|
final boolean[] done = new boolean[1];
|
||||||
|
done[0] = false;
|
||||||
|
Thread t = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Create the status pipe file to communicate with /system/bin/uncrypt.
|
||||||
|
new File(UNCRYPT_STATUS_FILE).delete();
|
||||||
|
try {
|
||||||
|
Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
Log.w(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE +
|
||||||
|
"\": " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemProperties.set("ctl.start", "uncrypt");
|
||||||
|
|
||||||
|
// Read the status from the pipe.
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new FileReader(UNCRYPT_STATUS_FILE))) {
|
||||||
|
|
||||||
|
int last_status = Integer.MIN_VALUE;
|
||||||
|
while (true) {
|
||||||
|
String str = reader.readLine();
|
||||||
|
try {
|
||||||
|
int status = Integer.parseInt(str);
|
||||||
|
|
||||||
|
// Avoid flooding the log with the same message.
|
||||||
|
if (status == last_status && last_status != Integer.MIN_VALUE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
last_status = status;
|
||||||
|
|
||||||
|
if (status >= 0 && status < 100) {
|
||||||
|
// Update status
|
||||||
|
Log.d(TAG, "uncrypt read status: " + status);
|
||||||
|
sInstance.setUncryptProgress(status);
|
||||||
|
} else if (status == 100) {
|
||||||
|
Log.d(TAG, "uncrypt successfully finished.");
|
||||||
|
sInstance.setUncryptProgress(status);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Error in /system/bin/uncrypt. Or it's rebooting to recovery
|
||||||
|
// to perform other operations (e.g. factory reset).
|
||||||
|
Log.d(TAG, "uncrypt failed with status: " + status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException unused) {
|
||||||
|
Log.d(TAG, "uncrypt invalid status received: " + str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException unused) {
|
||||||
|
Log.w(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
|
||||||
|
}
|
||||||
|
done[0] = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
t.join(MAX_UNCRYPT_WAIT_TIME);
|
||||||
|
} catch (InterruptedException unused) {
|
||||||
|
}
|
||||||
|
if (!done[0]) {
|
||||||
|
Log.w(TAG, "Timed out waiting for uncrypt.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user