am 165102f3: Merge "Wait for uncrypt to finish before rebooting" into mnc-dev

* commit '165102f350e08bd186b25b90dd8a42aad8975890':
  Wait for uncrypt to finish before rebooting
This commit is contained in:
Tao Bao
2015-05-28 21:51:44 +00:00
committed by Android Git Automerger
5 changed files with 170 additions and 20 deletions

View File

@@ -71,6 +71,7 @@ public class RecoverySystem {
/** Used to communicate with recovery. See bootable/recovery/recovery.c. */
private static File RECOVERY_DIR = new File("/cache/recovery");
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 String LAST_PREFIX = "last_";
@@ -333,8 +334,21 @@ public class RecoverySystem {
public static void installPackage(Context context, File packageFile)
throws IOException {
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 + " !!!");
// 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 localeArg = "--locale=" + Locale.getDefault().toString();
bootCommand(context, filenameArg, localeArg);

View File

@@ -413,6 +413,10 @@
<!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] -->
<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. -->
<string name="shutdown_progress">Shutting down\u2026</string>

View File

@@ -815,6 +815,8 @@
<java-symbol type="string" name="mobile_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="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_title" />
<java-symbol type="string" name="relationTypeAssistant" />

View File

@@ -2518,8 +2518,7 @@ public final class PowerManagerService extends SystemService
/**
* Low-level function to reboot the device. On success, this
* function doesn't return. If more than 20 seconds passes from
* the time a reboot is requested (120 seconds for reboot to
* recovery), this method returns.
* the time a reboot is requested, this method returns.
*
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
*/
@@ -2527,27 +2526,21 @@ public final class PowerManagerService extends SystemService
if (reason == null) {
reason = "";
}
long duration;
if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
// If we are rebooting to go into recovery, instead of
// setting sys.powerctl directly we'll start the
// pre-recovery service which will do some preparation for
// 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");
duration = 300 * 1000L;
} else {
SystemProperties.set("sys.powerctl", "reboot," + reason);
duration = 20 * 1000L;
}
try {
Thread.sleep(duration);
Thread.sleep(20 * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}
@Override // Watchdog.Monitor implementation

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.power;
import android.app.ActivityManagerNative;
@@ -44,6 +44,8 @@ import android.os.Vibrator;
import android.os.SystemVibrator;
import android.os.storage.IMountService;
import android.os.storage.IMountShutdownObserver;
import android.system.ErrnoException;
import android.system.Os;
import com.android.internal.telephony.ITelephony;
import com.android.server.pm.PackageManagerService;
@@ -51,6 +53,11 @@ import com.android.server.pm.PackageManagerService;
import android.util.Log;
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 {
// constants
private static final String TAG = "ShutdownThread";
@@ -59,14 +66,18 @@ public final class ShutdownThread extends Thread {
private static final int MAX_BROADCAST_TIME = 10*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_UNCRYPT_WAIT_TIME = 15*60*1000;
// length of vibration before shutting down
private static final int SHUTDOWN_VIBRATE_MS = 500;
// state tracking
private static Object sIsStartedGuard = new Object();
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 mRebootSafeMode;
private static String mRebootReason;
@@ -94,10 +105,11 @@ public final class ShutdownThread extends Thread {
private Handler mHandler;
private static AlertDialog sConfirmDialog;
private ProgressDialog mProgressDialog;
private ShutdownThread() {
}
/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
@@ -226,7 +238,11 @@ public final class ShutdownThread extends Thread {
// throw up an indeterminate system dialog to indicate radio is
// shutting down.
ProgressDialog pd = new ProgressDialog(context);
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
if (mRebootReason.equals(PowerManager.REBOOT_RECOVERY)) {
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.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
pd.setIndeterminate(true);
pd.setCancelable(false);
@@ -234,6 +250,7 @@ public final class ShutdownThread extends Thread {
pd.show();
sInstance.mProgressDialog = pd;
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -307,14 +324,14 @@ public final class ShutdownThread extends Thread {
}
Log.i(TAG, "Sending shutdown broadcast...");
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (!mActionDone) {
@@ -329,9 +346,9 @@ public final class ShutdownThread extends Thread {
}
}
}
Log.i(TAG, "Shutting down activity manager...");
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
@@ -390,9 +407,55 @@ public final class ShutdownThread extends Thread {
}
}
// If it's to reboot into recovery, invoke uncrypt via init service.
if (mRebootReason.equals(PowerManager.REBOOT_RECOVERY)) {
uncrypt();
}
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) {
// If a radio is wedged, disabling it may hang so we do this work in another thread,
// just in case.
@@ -537,4 +600,78 @@ public final class ShutdownThread extends Thread {
Log.i(TAG, "Performing low-level shutdown...");
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.");
}
}
}