diff options
Diffstat (limited to 'services/java')
5 files changed, 560 insertions, 36 deletions
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 289ab2a..2cc2704 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -17,8 +17,8 @@ package com.android.server; import com.android.internal.app.IBatteryStats; -import com.android.internal.app.ShutdownThread; import com.android.server.am.BatteryStatsService; +import com.android.server.pm.ShutdownThread; import android.app.ActivityManagerNative; import android.app.IActivityManager; @@ -47,7 +47,6 @@ import android.os.IBinder; import android.os.IPowerManager; import android.os.LocalPowerManager; import android.os.Message; -import android.os.Power; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -71,6 +70,7 @@ import static android.provider.Settings.System.WINDOW_ANIMATION_SCALE; import static android.provider.Settings.System.TRANSITION_ANIMATION_SCALE; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; @@ -84,6 +84,12 @@ public class PowerManagerService extends IPowerManager.Stub private static final String TAG = "PowerManagerService"; static final String PARTIAL_NAME = "PowerManagerService"; + // Wake lock that ensures that the CPU is running. The screen might not be on. + private static final int PARTIAL_WAKE_LOCK_ID = 1; + + // Wake lock that ensures that the screen is on. + private static final int FULL_WAKE_LOCK_ID = 2; + static final boolean DEBUG_SCREEN_ON = false; private static final boolean LOG_PARTIAL_WL = false; @@ -134,6 +140,10 @@ public class PowerManagerService extends IPowerManager.Stub // Screen brightness should always have a value, but just in case... private static final int DEFAULT_SCREEN_BRIGHTNESS = 192; + // Threshold for BRIGHTNESS_LOW_BATTERY (percentage) + // Screen will stay dim if battery level is <= LOW_BATTERY_THRESHOLD + private static final int LOW_BATTERY_THRESHOLD = 10; + // flags for setPowerState private static final int ALL_LIGHTS_OFF = 0x00000000; private static final int SCREEN_ON_BIT = 0x00000001; @@ -175,8 +185,8 @@ public class PowerManagerService extends IPowerManager.Stub // we should read them from the driver, but our current hardware returns 0 // for the initial value. Oops! static final int INITIAL_SCREEN_BRIGHTNESS = 255; - static final int INITIAL_BUTTON_BRIGHTNESS = Power.BRIGHTNESS_OFF; - static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF; + static final int INITIAL_BUTTON_BRIGHTNESS = PowerManager.BRIGHTNESS_OFF; + static final int INITIAL_KEYBOARD_BRIGHTNESS = PowerManager.BRIGHTNESS_OFF; private final int MY_UID; private final int MY_PID; @@ -296,6 +306,11 @@ public class PowerManagerService extends IPowerManager.Stub private native void nativeInit(); private native void nativeSetPowerState(boolean screenOn, boolean screenBright); private native void nativeStartSurfaceFlingerAnimation(int mode); + private static native void nativeAcquireWakeLock(int lock, String id); + private static native void nativeReleaseWakeLock(String id); + private static native int nativeSetScreenState(boolean on); + private static native void nativeShutdown(); + private static native void nativeReboot(String reason) throws IOException; /* static PrintStream mLog; @@ -515,14 +530,13 @@ public class PowerManagerService extends IPowerManager.Stub MY_PID = Process.myPid(); Binder.restoreCallingIdentity(token); - // XXX remove this when the kernel doesn't timeout wake locks - Power.setLastUserActivityTimeout(7*24*3600*1000); // one week - // assume nothing is on yet mUserState = mPowerState = 0; // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); + + nativeInit(); } private ContentQueryMap mSettings; @@ -541,11 +555,6 @@ public class PowerManagerService extends IPowerManager.Stub mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION); mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); - nativeInit(); - synchronized (mLocks) { - updateNativePowerStateLocked(); - } - mInitComplete = false; mScreenBrightnessAnimator = new ScreenBrightnessAnimator("mScreenBrightnessUpdaterThread", Process.THREAD_PRIORITY_DISPLAY); @@ -581,8 +590,6 @@ public class PowerManagerService extends IPowerManager.Stub } } - nativeInit(); - Power.powerInitNative(); synchronized (mLocks) { updateNativePowerStateLocked(); // We make sure to start out with the screen on due to user activity. @@ -686,6 +693,26 @@ public class PowerManagerService extends IPowerManager.Stub } } + /** + * Low-level function turn the device off immediately, without trying + * to be clean. Most people should use + * {@link com.android.server.pm.internal.app.ShutdownThread} for a clean shutdown. + */ + public static void lowLevelShutdown() { + nativeShutdown(); + } + + /** + * Low-level function to reboot the device. + * + * @param reason code to pass to the kernel (e.g. "recovery"), or null. + * @throws IOException if reboot fails for some reason (eg, lack of + * permission) + */ + public static void lowLevelReboot(String reason) throws IOException { + nativeReboot(reason); + } + private class WakeLock implements IBinder.DeathRecipient { WakeLock(int f, IBinder b, String t, int u, int p) { @@ -926,7 +953,7 @@ public class PowerManagerService extends IPowerManager.Stub if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 1, tag); } } - Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME); + nativeAcquireWakeLock(PARTIAL_WAKE_LOCK_ID, PARTIAL_NAME); } if (diffsource) { @@ -1010,7 +1037,7 @@ public class PowerManagerService extends IPowerManager.Stub mPartialCount--; if (mPartialCount == 0) { if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 0, wl.tag); - Power.releaseWakeLock(PARTIAL_NAME); + nativeReleaseWakeLock(PARTIAL_NAME); } } // Unlink the lock from the binder. @@ -1719,10 +1746,10 @@ public class PowerManagerService extends IPowerManager.Stub + " mSkippedScreenOn=" + mSkippedScreenOn); } mScreenBrightnessHandler.removeMessages(ScreenBrightnessAnimator.ANIMATE_LIGHTS); - mScreenBrightnessAnimator.animateTo(Power.BRIGHTNESS_OFF, SCREEN_BRIGHT_BIT, 0); + mScreenBrightnessAnimator.animateTo(PowerManager.BRIGHTNESS_OFF, SCREEN_BRIGHT_BIT, 0); } } - int err = Power.setScreenState(on); + int err = nativeSetScreenState(on); if (err == 0) { mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0); if (mUseSoftwareAutoBrightness) { @@ -1934,7 +1961,7 @@ public class PowerManagerService extends IPowerManager.Stub private boolean batteryIsLow() { return (!mIsPowered && - mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD); + mBatteryService.getBatteryLevel() <= LOW_BATTERY_THRESHOLD); } private boolean shouldDeferScreenOnLocked() { @@ -2024,7 +2051,7 @@ public class PowerManagerService extends IPowerManager.Stub nominalCurrentValue = mScreenBrightnessDim; break; case 0: - nominalCurrentValue = Power.BRIGHTNESS_OFF; + nominalCurrentValue = PowerManager.BRIGHTNESS_OFF; break; case SCREEN_BRIGHT_BIT: default: @@ -2050,7 +2077,7 @@ public class PowerManagerService extends IPowerManager.Stub // was dim steps = (int)(ANIM_STEPS*ratio*scale); } - brightness = Power.BRIGHTNESS_OFF; + brightness = PowerManager.BRIGHTNESS_OFF; } else { if ((oldState & SCREEN_ON_BIT) != 0) { // was bright @@ -2101,13 +2128,13 @@ public class PowerManagerService extends IPowerManager.Stub if (offMask != 0) { if (mSpew) Slog.i(TAG, "Setting brightess off: " + offMask); - setLightBrightness(offMask, Power.BRIGHTNESS_OFF); + setLightBrightness(offMask, PowerManager.BRIGHTNESS_OFF); } if (dimMask != 0) { int brightness = mScreenBrightnessDim; if ((newState & BATTERY_LOW_BIT) != 0 && - brightness > Power.BRIGHTNESS_LOW_BATTERY) { - brightness = Power.BRIGHTNESS_LOW_BATTERY; + brightness > PowerManager.BRIGHTNESS_LOW_BATTERY) { + brightness = PowerManager.BRIGHTNESS_LOW_BATTERY; } if (mSpew) Slog.i(TAG, "Setting brightess dim " + brightness + ": " + dimMask); setLightBrightness(dimMask, brightness); @@ -2115,8 +2142,8 @@ public class PowerManagerService extends IPowerManager.Stub if (onMask != 0) { int brightness = getPreferredBrightness(); if ((newState & BATTERY_LOW_BIT) != 0 && - brightness > Power.BRIGHTNESS_LOW_BATTERY) { - brightness = Power.BRIGHTNESS_LOW_BATTERY; + brightness > PowerManager.BRIGHTNESS_LOW_BATTERY) { + brightness = PowerManager.BRIGHTNESS_LOW_BATTERY; } if (mSpew) Slog.i(TAG, "Setting brightess on " + brightness + ": " + onMask); setLightBrightness(onMask, brightness); @@ -2198,8 +2225,8 @@ public class PowerManagerService extends IPowerManager.Stub if (elapsed < duration) { int delta = endValue - startValue; newValue = startValue + delta * elapsed / duration; - newValue = Math.max(Power.BRIGHTNESS_OFF, newValue); - newValue = Math.min(Power.BRIGHTNESS_ON, newValue); + newValue = Math.max(PowerManager.BRIGHTNESS_OFF, newValue); + newValue = Math.min(PowerManager.BRIGHTNESS_ON, newValue); } else { newValue = endValue; mInitialAnimation = false; @@ -2249,7 +2276,7 @@ public class PowerManagerService extends IPowerManager.Stub if (target != currentValue) { final boolean doScreenAnim = (mask & (SCREEN_BRIGHT_BIT | SCREEN_ON_BIT)) != 0; - final boolean turningOff = endValue == Power.BRIGHTNESS_OFF; + final boolean turningOff = endValue == PowerManager.BRIGHTNESS_OFF; if (turningOff && doScreenAnim) { // Cancel all pending animations since we're turning off mScreenBrightnessHandler.removeCallbacksAndMessages(null); @@ -2353,7 +2380,7 @@ public class PowerManagerService extends IPowerManager.Stub private boolean isScreenTurningOffLocked() { return (mScreenBrightnessAnimator.isAnimating() - && mScreenBrightnessAnimator.endValue == Power.BRIGHTNESS_OFF); + && mScreenBrightnessAnimator.endValue == PowerManager.BRIGHTNESS_OFF); } private boolean shouldLog(long time) { diff --git a/services/java/com/android/server/ShutdownActivity.java b/services/java/com/android/server/ShutdownActivity.java index c9d4d01..d85abe6 100644 --- a/services/java/com/android/server/ShutdownActivity.java +++ b/services/java/com/android/server/ShutdownActivity.java @@ -22,7 +22,8 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Slog; -import com.android.internal.app.ShutdownThread; + +import com.android.server.pm.ShutdownThread; public class ShutdownActivity extends Activity { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 849281d..d9833ab 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -46,7 +46,6 @@ import android.util.Log; import android.util.Slog; import android.view.WindowManager; -import com.android.internal.app.ShutdownThread; import com.android.internal.os.BinderInternal; import com.android.internal.os.SamplingProfilerIntegration; import com.android.internal.widget.LockSettingsService; @@ -56,6 +55,7 @@ import com.android.server.input.InputManagerService; import com.android.server.net.NetworkPolicyManagerService; import com.android.server.net.NetworkStatsService; import com.android.server.pm.PackageManagerService; +import com.android.server.pm.ShutdownThread; import com.android.server.usb.UsbService; import com.android.server.wm.WindowManagerService; diff --git a/services/java/com/android/server/pm/ShutdownThread.java b/services/java/com/android/server/pm/ShutdownThread.java new file mode 100644 index 0000000..1d6e068 --- /dev/null +++ b/services/java/com/android/server/pm/ShutdownThread.java @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.server.pm; + +import android.app.ActivityManagerNative; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.IActivityManager; +import android.app.ProgressDialog; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.IBluetooth; +import android.nfc.NfcAdapter; +import android.nfc.INfcAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.Vibrator; +import android.os.SystemVibrator; +import android.os.storage.IMountService; +import android.os.storage.IMountShutdownObserver; + +import com.android.internal.telephony.ITelephony; +import com.android.server.PowerManagerService; + +import android.util.Log; +import android.view.WindowManager; + +public final class ShutdownThread extends Thread { + // constants + private static final String TAG = "ShutdownThread"; + private static final int MAX_NUM_PHONE_STATE_READS = 24; + private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500; + // maximum time we wait for the shutdown broadcast before going on. + private static final int MAX_BROADCAST_TIME = 10*1000; + private static final int MAX_SHUTDOWN_WAIT_TIME = 20*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; + + private static boolean mReboot; + private static boolean mRebootSafeMode; + private static String mRebootReason; + + // Provides shutdown assurance in case the system_server is killed + public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested"; + + // Indicates whether we are rebooting into safe mode + public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode"; + + // static instance of this thread + private static final ShutdownThread sInstance = new ShutdownThread(); + + private final Object mActionDoneSync = new Object(); + private boolean mActionDone; + private Context mContext; + private PowerManager mPowerManager; + private PowerManager.WakeLock mCpuWakeLock; + private PowerManager.WakeLock mScreenWakeLock; + private Handler mHandler; + + 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 + * is shown. + * + * @param context Context used to display the shutdown progress dialog. + * @param confirm true if user confirmation is needed before shutting down. + */ + public static void shutdown(final Context context, boolean confirm) { + mReboot = false; + mRebootSafeMode = false; + shutdownInner(context, confirm); + } + + static void shutdownInner(final Context context, boolean confirm) { + // ensure that only one thread is trying to power down. + // any additional calls are just returned + synchronized (sIsStartedGuard) { + if (sIsStarted) { + Log.d(TAG, "Request to shutdown already running, returning."); + return; + } + } + + final int longPressBehavior = context.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerBehavior); + final int resourceId = mRebootSafeMode + ? com.android.internal.R.string.reboot_safemode_confirm + : (longPressBehavior == 2 + ? com.android.internal.R.string.shutdown_confirm_question + : com.android.internal.R.string.shutdown_confirm); + + Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior); + + if (confirm) { + final CloseDialogReceiver closer = new CloseDialogReceiver(context); + final AlertDialog dialog = new AlertDialog.Builder(context) + .setTitle(mRebootSafeMode + ? com.android.internal.R.string.reboot_safemode_title + : com.android.internal.R.string.power_off) + .setMessage(resourceId) + .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + beginShutdownSequence(context); + } + }) + .setNegativeButton(com.android.internal.R.string.no, null) + .create(); + closer.dialog = dialog; + dialog.setOnDismissListener(closer); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + dialog.show(); + } else { + beginShutdownSequence(context); + } + } + + private static class CloseDialogReceiver extends BroadcastReceiver + implements DialogInterface.OnDismissListener { + private Context mContext; + public Dialog dialog; + + CloseDialogReceiver(Context context) { + mContext = context; + IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + context.registerReceiver(this, filter); + } + + @Override + public void onReceive(Context context, Intent intent) { + dialog.cancel(); + } + + public void onDismiss(DialogInterface unused) { + mContext.unregisterReceiver(this); + } + } + + /** + * Request a clean shutdown, waiting for subsystems to clean up their + * state etc. Must be called from a Looper thread in which its UI + * is shown. + * + * @param context Context used to display the shutdown progress dialog. + * @param reason code to pass to the kernel (e.g. "recovery"), or null. + * @param confirm true if user confirmation is needed before shutting down. + */ + public static void reboot(final Context context, String reason, boolean confirm) { + mReboot = true; + mRebootSafeMode = false; + mRebootReason = reason; + shutdownInner(context, confirm); + } + + /** + * Request a reboot into safe mode. Must be called from a Looper thread in which its UI + * is shown. + * + * @param context Context used to display the shutdown progress dialog. + * @param confirm true if user confirmation is needed before shutting down. + */ + public static void rebootSafeMode(final Context context, boolean confirm) { + mReboot = true; + mRebootSafeMode = true; + mRebootReason = null; + shutdownInner(context, confirm); + } + + private static void beginShutdownSequence(Context context) { + synchronized (sIsStartedGuard) { + if (sIsStarted) { + Log.d(TAG, "Shutdown sequence already running, returning."); + return; + } + sIsStarted = true; + } + + // 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)); + pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); + pd.setIndeterminate(true); + pd.setCancelable(false); + pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + + pd.show(); + + sInstance.mContext = context; + sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + + // make sure we never fall asleep again + sInstance.mCpuWakeLock = null; + try { + sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu"); + sInstance.mCpuWakeLock.setReferenceCounted(false); + sInstance.mCpuWakeLock.acquire(); + } catch (SecurityException e) { + Log.w(TAG, "No permission to acquire wake lock", e); + sInstance.mCpuWakeLock = null; + } + + // also make sure the screen stays on for better user experience + sInstance.mScreenWakeLock = null; + if (sInstance.mPowerManager.isScreenOn()) { + try { + sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock( + PowerManager.FULL_WAKE_LOCK, TAG + "-screen"); + sInstance.mScreenWakeLock.setReferenceCounted(false); + sInstance.mScreenWakeLock.acquire(); + } catch (SecurityException e) { + Log.w(TAG, "No permission to acquire wake lock", e); + sInstance.mScreenWakeLock = null; + } + } + + // start the thread that initiates shutdown + sInstance.mHandler = new Handler() { + }; + sInstance.start(); + } + + void actionDone() { + synchronized (mActionDoneSync) { + mActionDone = true; + mActionDoneSync.notifyAll(); + } + } + + /** + * Makes sure we handle the shutdown gracefully. + * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. + */ + public void run() { + boolean nfcOff; + boolean bluetoothOff; + boolean radioOff; + + BroadcastReceiver br = new BroadcastReceiver() { + @Override public void onReceive(Context context, Intent intent) { + // We don't allow apps to cancel this, so ignore the result. + actionDone(); + } + }; + + /* + * Write a system property in case the system_server reboots before we + * get to the actual hardware restart. If that happens, we'll retry at + * the beginning of the SystemServer startup. + */ + { + String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : ""); + SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason); + } + + /* + * If we are rebooting into safe mode, write a system property + * indicating so. + */ + if (mRebootSafeMode) { + SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1"); + } + + Log.i(TAG, "Sending shutdown broadcast..."); + + // First send the high-level shut down broadcast. + mActionDone = false; + mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null, + br, mHandler, 0, null, null); + + final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME; + synchronized (mActionDoneSync) { + while (!mActionDone) { + long delay = endTime - SystemClock.elapsedRealtime(); + if (delay <= 0) { + Log.w(TAG, "Shutdown broadcast timed out"); + break; + } + try { + mActionDoneSync.wait(delay); + } catch (InterruptedException e) { + } + } + } + + Log.i(TAG, "Shutting down activity manager..."); + + final IActivityManager am = + ActivityManagerNative.asInterface(ServiceManager.checkService("activity")); + if (am != null) { + try { + am.shutdown(MAX_BROADCAST_TIME); + } catch (RemoteException e) { + } + } + + final INfcAdapter nfc = + INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc")); + final ITelephony phone = + ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); + final IBluetooth bluetooth = + IBluetooth.Stub.asInterface(ServiceManager.checkService( + BluetoothAdapter.BLUETOOTH_SERVICE)); + final IMountService mount = + IMountService.Stub.asInterface( + ServiceManager.checkService("mount")); + + try { + nfcOff = nfc == null || + nfc.getState() == NfcAdapter.STATE_OFF; + if (!nfcOff) { + Log.w(TAG, "Turning off NFC..."); + nfc.disable(false); // Don't persist new state + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during NFC shutdown", ex); + nfcOff = true; + } + + try { + bluetoothOff = bluetooth == null || + bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF; + if (!bluetoothOff) { + Log.w(TAG, "Disabling Bluetooth..."); + bluetooth.disable(false); // disable but don't persist new state + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during bluetooth shutdown", ex); + bluetoothOff = true; + } + + try { + radioOff = phone == null || !phone.isRadioOn(); + if (!radioOff) { + Log.w(TAG, "Turning off radio..."); + phone.setRadio(false); + } + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during radio shutdown", ex); + radioOff = true; + } + + Log.i(TAG, "Waiting for NFC, Bluetooth and Radio..."); + + // Wait a max of 32 seconds for clean shutdown + for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) { + if (!bluetoothOff) { + try { + bluetoothOff = + bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF; + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during bluetooth shutdown", ex); + bluetoothOff = true; + } + } + if (!radioOff) { + try { + radioOff = !phone.isRadioOn(); + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during radio shutdown", ex); + radioOff = true; + } + } + if (!nfcOff) { + try { + nfcOff = nfc.getState() == NfcAdapter.STATE_OFF; + } catch (RemoteException ex) { + Log.e(TAG, "RemoteException during NFC shutdown", ex); + nfcOff = true; + } + } + + if (radioOff && bluetoothOff && nfcOff) { + Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete."); + break; + } + SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); + } + + // Shutdown MountService to ensure media is in a safe state + IMountShutdownObserver observer = new IMountShutdownObserver.Stub() { + public void onShutDownComplete(int statusCode) throws RemoteException { + Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown"); + actionDone(); + } + }; + + Log.i(TAG, "Shutting down MountService"); + // Set initial variables and time out time. + mActionDone = false; + final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME; + synchronized (mActionDoneSync) { + try { + if (mount != null) { + mount.shutdown(observer); + } else { + Log.w(TAG, "MountService unavailable for shutdown"); + } + } catch (Exception e) { + Log.e(TAG, "Exception during MountService shutdown", e); + } + while (!mActionDone) { + long delay = endShutTime - SystemClock.elapsedRealtime(); + if (delay <= 0) { + Log.w(TAG, "Shutdown wait timed out"); + break; + } + try { + mActionDoneSync.wait(delay); + } catch (InterruptedException e) { + } + } + } + + rebootOrShutdown(mReboot, mRebootReason); + } + + /** + * Do not call this directly. Use {@link #reboot(Context, String, boolean)} + * or {@link #shutdown(Context, boolean)} instead. + * + * @param reboot true to reboot or false to shutdown + * @param reason reason for reboot + */ + public static void rebootOrShutdown(boolean reboot, String reason) { + if (reboot) { + Log.i(TAG, "Rebooting, reason: " + reason); + try { + PowerManagerService.lowLevelReboot(reason); + } catch (Exception e) { + Log.e(TAG, "Reboot failed, will attempt shutdown instead", e); + } + } else if (SHUTDOWN_VIBRATE_MS > 0) { + // vibrate before shutting down + Vibrator vibrator = new SystemVibrator(); + try { + vibrator.vibrate(SHUTDOWN_VIBRATE_MS); + } catch (Exception e) { + // Failure to vibrate shouldn't interrupt shutdown. Just log it. + Log.w(TAG, "Failed to vibrate during shutdown.", e); + } + + // vibrator is asynchronous so we need to wait to avoid shutting down too soon. + try { + Thread.sleep(SHUTDOWN_VIBRATE_MS); + } catch (InterruptedException unused) { + } + } + + // Shutdown power + Log.i(TAG, "Performing low-level shutdown..."); + PowerManagerService.lowLevelShutdown(); + } +} diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 2efcb8e..c90c0c7 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -34,7 +34,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import com.android.internal.app.IBatteryStats; -import com.android.internal.app.ShutdownThread; import com.android.internal.policy.PolicyManager; import com.android.internal.policy.impl.PhoneWindowManager; import com.android.internal.view.IInputContext; @@ -48,6 +47,7 @@ import com.android.server.Watchdog; import com.android.server.am.BatteryStatsService; import com.android.server.input.InputFilter; import com.android.server.input.InputManagerService; +import com.android.server.pm.ShutdownThread; import android.Manifest; import android.app.ActivityManagerNative; @@ -82,7 +82,6 @@ import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; -import android.os.Power; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -5025,6 +5024,18 @@ public class WindowManagerService extends IWindowManager.Stub return mInputManager.monitorInput(inputChannelName); } + // Called by window manager policy. Not exposed externally. + @Override + public void shutdown() { + ShutdownThread.shutdown(mContext, true); + } + + // Called by window manager policy. Not exposed externally. + @Override + public void rebootSafeMode() { + ShutdownThread.rebootSafeMode(mContext, true); + } + public void setInputFilter(InputFilter filter) { mInputManager.setInputFilter(filter); } @@ -8700,13 +8711,13 @@ public class WindowManagerService extends IWindowManager.Stub mPowerManager.setScreenBrightnessOverride(-1); } else { mPowerManager.setScreenBrightnessOverride((int) - (mInnerFields.mScreenBrightness * Power.BRIGHTNESS_ON)); + (mInnerFields.mScreenBrightness * PowerManager.BRIGHTNESS_ON)); } if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) { mPowerManager.setButtonBrightnessOverride(-1); } else { mPowerManager.setButtonBrightnessOverride((int) - (mInnerFields.mButtonBrightness * Power.BRIGHTNESS_ON)); + (mInnerFields.mButtonBrightness * PowerManager.BRIGHTNESS_ON)); } } if (mInnerFields.mHoldScreen != mHoldingScreenOn) { |