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

Commit 69dd849e authored by Tao Bao's avatar Tao Bao Committed by Android Git Automerger
Browse files

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

* commit '5f90a8c5':
  Wait for uncrypt to finish before rebooting
parents e6562d90 5f90a8c5
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.");
        }
    }
}