Loading core/java/android/os/RecoverySystem.java +14 −0 Original line number Diff line number Diff line Loading @@ -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_"; Loading Loading @@ -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); Loading core/res/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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> Loading core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading services/core/java/com/android/server/power/PowerManagerService.java +3 −10 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 Loading services/core/java/com/android/server/power/ShutdownThread.java +147 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading @@ -59,6 +66,7 @@ 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; Loading @@ -67,6 +75,9 @@ public final class ShutdownThread extends Thread { 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; Loading Loading @@ -94,6 +105,7 @@ public final class ShutdownThread extends Thread { private Handler mHandler; private static AlertDialog sConfirmDialog; private ProgressDialog mProgressDialog; private ShutdownThread() { } Loading Loading @@ -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); 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); Loading @@ -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); Loading Loading @@ -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. Loading Loading @@ -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."); } } } Loading
core/java/android/os/RecoverySystem.java +14 −0 Original line number Diff line number Diff line Loading @@ -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_"; Loading Loading @@ -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); Loading
core/res/res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -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> Loading
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading
services/core/java/com/android/server/power/PowerManagerService.java +3 −10 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 Loading
services/core/java/com/android/server/power/ShutdownThread.java +147 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading @@ -59,6 +66,7 @@ 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; Loading @@ -67,6 +75,9 @@ public final class ShutdownThread extends Thread { 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; Loading Loading @@ -94,6 +105,7 @@ public final class ShutdownThread extends Thread { private Handler mHandler; private static AlertDialog sConfirmDialog; private ProgressDialog mProgressDialog; private ShutdownThread() { } Loading Loading @@ -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); 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); Loading @@ -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); Loading Loading @@ -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. Loading Loading @@ -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."); } } }