Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 165102f3 authored by Tao Bao's avatar Tao Bao Committed by Android (Google) Code Review
Browse files

Merge "Wait for uncrypt to finish before rebooting" into mnc-dev

parents 4573dddc 90237f7b
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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);
+4 −0
Original line number Diff line number Diff line
@@ -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>

+2 −0
Original line number Diff line number Diff line
@@ -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" />
+3 −10
Original line number Diff line number Diff line
@@ -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
+147 −10
Original line number Diff line number Diff line
@@ -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,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;
@@ -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;
@@ -94,6 +105,7 @@ public final class ShutdownThread extends Thread {
    private Handler mHandler;

    private static AlertDialog sConfirmDialog;
    private ProgressDialog mProgressDialog;

    private ShutdownThread() {
    }
@@ -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);
@@ -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);

@@ -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.");
        }
    }
}