Distinguish user-requested shutdown from power-related ones
With this patch, when the user requested shutdown,
PowerManagerService sets sys.powerctl is set to
"shutdown,userrequested", and init runs fsck on shutdown.
When shutdown is triggered due to a low power state etc.,
the service sets the property to "shutdown,", and init
immediately shuts down the system without running the
command.
This is a follow-up CL for http://r.android.com/158525.
Bug: 21853106
Change-Id: Iae72990130fe9aa479c802f77301438190dbbfb3
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index da8586c..e11d278 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -93,7 +93,7 @@
} else if ("shutdown".equals(args[1])) {
try {
// no confirm, wait till device is off
- pm.shutdown(false, true);
+ pm.shutdown(false, null, true);
} catch (RemoteException e) {
System.err.println("Failed to shutdown.");
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2fe727c..cafccbf 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2018,7 +2018,9 @@
/**
* Activity Action: Start this activity to request system shutdown.
* The optional boolean extra field {@link #EXTRA_KEY_CONFIRM} can be set to true
- * to request confirmation from the user before shutting down.
+ * to request confirmation from the user before shutting down. The optional boolean
+ * extra field {@link #EXTRA_USER_REQUESTED_SHUTDOWN} can be set to true to
+ * indicate that the shutdown is requested by the user.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -3229,6 +3231,15 @@
public static final String EXTRA_KEY_CONFIRM = "android.intent.extra.KEY_CONFIRM";
/**
+ * Set to true in {@link #ACTION_REQUEST_SHUTDOWN} to indicate that the shutdown is
+ * requested by the user.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_USER_REQUESTED_SHUTDOWN =
+ "android.intent.extra.USER_REQUESTED_SHUTDOWN";
+
+ /**
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} or
* {@link android.content.Intent#ACTION_PACKAGE_CHANGED} intents to override the default action
* of restarting the application.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 16dac7d..4d6241b 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -45,7 +45,7 @@
boolean setPowerSaveMode(boolean mode);
void reboot(boolean confirm, String reason, boolean wait);
- void shutdown(boolean confirm, boolean wait);
+ void shutdown(boolean confirm, String reason, boolean wait);
void crash(String message);
void setStayOnSetting(int val);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index d52dd30..4b284ce 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -367,7 +367,13 @@
* @hide
*/
public static final String REBOOT_RECOVERY = "recovery";
-
+
+ /**
+ * The value to pass as the 'reason' argument to android_reboot().
+ * @hide
+ */
+ public static final String SHUTDOWN_USER_REQUESTED = "userrequested";
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -838,13 +844,14 @@
* Turn off the device.
*
* @param confirm If true, shows a shutdown confirmation dialog.
+ * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
* @param wait If true, this call waits for the shutdown to complete and does not return.
*
* @hide
*/
- public void shutdown(boolean confirm, boolean wait) {
+ public void shutdown(boolean confirm, String reason, boolean wait) {
try {
- mService.shutdown(confirm, wait);
+ mService.shutdown(confirm, reason, wait);
} catch (RemoteException e) {
}
}
diff --git a/core/java/com/android/internal/app/ShutdownActivity.java b/core/java/com/android/internal/app/ShutdownActivity.java
index 97521cf..745d28f 100644
--- a/core/java/com/android/internal/app/ShutdownActivity.java
+++ b/core/java/com/android/internal/app/ShutdownActivity.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.IPowerManager;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
@@ -30,6 +31,7 @@
private static final String TAG = "ShutdownActivity";
private boolean mReboot;
private boolean mConfirm;
+ private boolean mUserRequested;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -38,6 +40,7 @@
Intent intent = getIntent();
mReboot = Intent.ACTION_REBOOT.equals(intent.getAction());
mConfirm = intent.getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ mUserRequested = intent.getBooleanExtra(Intent.EXTRA_USER_REQUESTED_SHUTDOWN, false);
Slog.i(TAG, "onCreate(): confirm=" + mConfirm);
Thread thr = new Thread("ShutdownActivity") {
@@ -49,7 +52,9 @@
if (mReboot) {
pm.reboot(mConfirm, null, false);
} else {
- pm.shutdown(mConfirm, false);
+ pm.shutdown(mConfirm,
+ mUserRequested ? PowerManager.SHUTDOWN_USER_REQUESTED : null,
+ false);
}
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 32c0fb8..01e36e1 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2180,7 +2180,7 @@
public void run() {
synchronized (this) {
if (shutdown) {
- ShutdownThread.shutdown(mContext, confirm);
+ ShutdownThread.shutdown(mContext, reason, confirm);
} else {
ShutdownThread.reboot(mContext, reason, confirm);
}
@@ -2349,9 +2349,14 @@
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
+ *
+ * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
*/
- public static void lowLevelShutdown() {
- SystemProperties.set("sys.powerctl", "shutdown");
+ public static void lowLevelShutdown(String reason) {
+ if (reason == null) {
+ reason = "";
+ }
+ SystemProperties.set("sys.powerctl", "shutdown," + reason);
}
/**
@@ -3056,12 +3061,12 @@
* @param wait If true, this call waits for the shutdown to complete and does not return.
*/
@Override // Binder call
- public void shutdown(boolean confirm, boolean wait) {
+ public void shutdown(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
final long ident = Binder.clearCallingIdentity();
try {
- shutdownOrRebootInternal(true, confirm, null, wait);
+ shutdownOrRebootInternal(true, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 4c14c47..8f041a5 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -87,7 +87,7 @@
private static boolean mReboot;
private static boolean mRebootSafeMode;
private static boolean mRebootUpdate;
- private static String mRebootReason;
+ private static String mReason;
// Provides shutdown assurance in case the system_server is killed
public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
@@ -123,11 +123,13 @@
* is shown.
*
* @param context Context used to display the shutdown progress dialog.
+ * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
* @param confirm true if user confirmation is needed before shutting down.
*/
- public static void shutdown(final Context context, boolean confirm) {
+ public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false;
mRebootSafeMode = false;
+ mReason = reason;
shutdownInner(context, confirm);
}
@@ -211,7 +213,7 @@
mReboot = true;
mRebootSafeMode = false;
mRebootUpdate = false;
- mRebootReason = reason;
+ mReason = reason;
shutdownInner(context, confirm);
}
@@ -226,7 +228,7 @@
mReboot = true;
mRebootSafeMode = true;
mRebootUpdate = false;
- mRebootReason = null;
+ mReason = null;
shutdownInner(context, confirm);
}
@@ -243,18 +245,18 @@
ProgressDialog pd = new ProgressDialog(context);
// Path 1: Reboot to recovery and install the update
- // Condition: mRebootReason == REBOOT_RECOVERY and mRebootUpdate == True
+ // Condition: mReason == REBOOT_RECOVERY and mRebootUpdate == True
// (mRebootUpdate is set by checking if /cache/recovery/uncrypt_file exists.)
// UI: progress bar
//
// Path 2: Reboot to recovery for factory reset
- // Condition: mRebootReason == REBOOT_RECOVERY
+ // Condition: mReason == REBOOT_RECOVERY
// UI: spinning circle only (no progress bar)
//
// Path 3: Regular reboot / shutdown
// Condition: Otherwise
// UI: spinning circle only (no progress bar)
- if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
+ if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
if (mRebootUpdate) {
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
@@ -343,7 +345,7 @@
* the beginning of the SystemServer startup.
*/
{
- String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
+ String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
@@ -467,7 +469,7 @@
uncrypt();
}
- rebootOrShutdown(mContext, mReboot, mRebootReason);
+ rebootOrShutdown(mContext, mReboot, mReason);
}
private void setRebootProgress(final int progress, final CharSequence message) {
@@ -610,13 +612,14 @@
*
* @param context Context used to vibrate or null without vibration
* @param reboot true to reboot or false to shutdown
- * @param reason reason for reboot
+ * @param reason reason for reboot/shutdown
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
Log.e(TAG, "Reboot failed, will attempt shutdown instead");
+ reason = null;
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
// vibrate before shutting down
Vibrator vibrator = new SystemVibrator(context);
@@ -636,7 +639,7 @@
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
- PowerManagerService.lowLevelShutdown();
+ PowerManagerService.lowLevelShutdown(reason);
}
private void uncrypt() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 001a6f8..85b2a41 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5679,7 +5679,7 @@
// Called by window manager policy. Not exposed externally.
@Override
public void shutdown(boolean confirm) {
- ShutdownThread.shutdown(mContext, confirm);
+ ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}
// Called by window manager policy. Not exposed externally.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 39ebdfc..46aa117 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -86,7 +86,7 @@
}
@Override
- public void shutdown(boolean confirm, boolean wait) {
+ public void shutdown(boolean confirm, String reason, boolean wait) {
// pass for now.
}