您的位置:首页 > 移动开发 > Android开发

Android6.0关机流程源码分析一

2017-03-27 15:10 369 查看
_前段时间盆友问我怎么实现关机功能,于是我就开始捣鼓,第一个想法就是发送关机广播,然而遇到了些问题,一是获取不到关机权限,二是Intent.ACTION_REQUEST_SHUT_DOWN和Intent.SHUTDOWN这两个属性不对上层开放。一条路行不通就换条走吧,既然没对上层提供shutdown()函数,那就用反射的方法来取,结果还是因为没有关机权限而无法调用shutdown()函数。无奈只好决定来看下源码,分析关机流程。这里主要是分析正常的关机流程。画了个简单的调用流程图。



接下来一步步分析。我们正常关机一般就是长按关机键,然后系统弹出个关机对话框



选择Power Off则开启关机。

长按关机键(KEYCODE_POWER),PhoneWindowManager.java拦截该事件,做出处理

/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}

final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
switch(keycode){
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}

case KeyEvent.KEYCODE_SLEEP: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false;
if (!mPowerManager.isInteractive()) {
useHapticFeedback = false; // suppress feedback if already non-interactive
}
if (down) {
sleepPress(event.getEventTime());
} else {
sleepRelease(event.getEventTime());
}
break;
}

case KeyEvent.KEYCODE_WAKEUP: {

4000
result &= ~ACTION_PASS_TO_USER;
isWakeKey = true;
break;
}
}
}


down事件:

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
//如果电源键尚未处理,则检测是短按,长按,或多按操作中的哪一种,再决定做下一步处理。
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mScreenshotChordVolumeUpKeyTriggered;
if (!mPowerKeyHandled) {
//手机处于激活(亮屏)状态
if (interactive) {
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
//检查是否是长按操作
//hasLongPressOnPowerBehavior=getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING;
if (hasLongPressOnPowerBehavior()) {//true
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
//发送消息通知主线程处理长按操作
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
}
//手机待机状态
else {
//唤醒手机
wakeUpFromPowerKey(event.getDownTime());

if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();

if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
}


主线程接收到长按的消息并做出下一步处理

private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_POWER_LONG_PRESS:
//调用powerPress()函数
powerLongPress();
break;
}
}
}


那接着来看powerLongPress()函数是如何处理长按事件的

private void powerLongPress() {
final int behavior = getResolvedLongPressOnPowerBehavior();
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
performAuditoryFeedbackForAccessibilityIfNeed();
}
showGlobalActionsInternal();
break;
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
break;
}
}


这里根据长按的行为behavior来分情况处理的。

情况一:LONG_PRESS_POWER_NOTHING:不处理

情况二:LONG_PRESS_POWER_GLOBAL_ACTIONS:正常关机流程

void showGlobalActionsInternal() {
//请求ActivityManagerNative关闭系统所有窗口
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
if (mGlobalActions == null) {
//初始化GlobalActions
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
//显示关机对话框
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
if (keyguardShowing) {
// since it took two seconds of long press to bring this up,
// poke the wake lock so they have some time to see the dialog.
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
}


(1)sendCloseSystemWindows();//发送请求关闭系统的对话框

void sendCloseSystemWindows(String reason) {
PhoneWindow.sendCloseSystemWindows(mContext, reason);
}


调用的是PhoneWindow.java的方法,如下:

public static void sendCloseSystemWindows(Context context, String reason) {
if (ActivityManagerNative.isSystemReady()) {
try {
ActivityManagerNative.getDefault().closeSystemDialogs(reason);
} catch (RemoteException e) {
}
}
}


继续调用ActivityManagerNative.java的方法,如下:

public void closeSystemDialogs(String reason) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(reason);
mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}


mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0)

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case CLOSE_SYSTEM_DIALOGS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String reason = data.readString();
closeSystemDialogs(reason);
reply.writeNoException();
return true;
}
}
}


(2)mGlobalActions.showDialog();//显示关机对话框

/**
* Show the global actions dialog (creating if necessary)
* @param keyguardShowing True if keyguard is showing
*/
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
handleShow();
}
}


调用HandleShow()方法创建GlobalActionsDialog对话框

private void handleShow() {
awakenIfNecessary();
//创建关机对话框
mDialog = createDialog();
prepareDialog();

// 对话框视图只有一个item,当手单按时回调onPress()函数
if (mAdapter.getCount() == 1
&& mAdapter.getItem(0) instanceof SinglePressAction
&& !(mAdapter.getItem(0) instanceof LongPressAction)) {
((SinglePressAction) mAdapter.getItem(0)).onPress();
}
//否则显示关机对话框,设置对话框参数属性
else {
WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
attrs.setTitle("GlobalActions");
mDialog.getWindow().setAttributes(attrs);
mDialog.show();
mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
}
}

/**
* Create the global actions dialog.
* @return A new dialog.
*/
private GlobalActionsDialog createDialog() {
// Simple toggle style if there's no vibrator, otherwise use a tri-state
if (!mHasVibrator) {
mSilentModeAction = new SilentModeToggleAction();
} else {
mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
}
//飞行模式
mAirplaneModeOn = new ToggleAction(
R.drawable.ic_lock_airplane_mode,
R.drawable.ic_lock_airplane_mode_off,
R.string.global_actions_toggle_airplane_mode,
R.string.global_actions_airplane_mode_on_status,
R.string.global_actions_airplane_mode_off_status) {

void onToggle(boolean on) {
if (mHasTelephony && Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
mIsWaitingForEcmExit = true;
// Launch ECM exit dialog
Intent ecmDialogIntent =
new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(ecmDialogIntent);
} else {
changeAirplaneModeSystemSetting(on);
}
}

@Override
protected void changeStateFromPress(boolean buttonOn) {
if (!mHasTelephony) return;

// In ECM mode airplane state cannot be changed
if (!(Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
mState = buttonOn ? State.TurningOn : State.TurningOff;
mAirplaneState = mState;
}
}

public boolean showDuringKeyguard() {
return true;
}

public boolean showBeforeProvisioning() {
return false;
}
13e26
};
//飞行模式改变
onAirplaneModeChanged();

mItems = new ArrayList<Action>();
//framework/base/core/res/res/values/config.xml(Global Actions:power、bugreport、users、reboot、airplane)
String[] defaultActions = mContext.getResources().getStringArray(
com.android.internal.R.array.config_globalActionsList);

ArraySet<String> addedKeys = new ArraySet<String>();
//循环给对话框的的列表添加item
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
// If we already have added this, don't add it again.
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
//关机
mItems.add(new PowerAction());
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
//飞行模式
mItems.add(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
mItems.add(getBugReportAction());
}
} else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
//静音
if (mShowSilentToggle) {
mItems.add(mSilentModeAction);
}
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
// Add here so we don't add more than one.
addedKeys.add(actionKey);
}

//创建适配器
mAdapter = new MyAdapter();

AlertParams params = new AlertParams(mContext);
params.mAdapter = mAdapter;
params.mOnClickListener = this;
params.mForceInverseBackground = true;

//创建GlobalActionsDialog对象
GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
//触摸对话框外部,对话框消失
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.

//给对话框列表注册监听事件
dialog.getListView().setItemsCanFocus(true);
dialog.getListView().setLongClickable(true);
dialog.getListView().setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
long id) {
final Action action = mAdapter.getItem(position);
if (action instanceof LongPressAction) {
return ((LongPressAction) action).onLongPress();
}
return false;
}
});
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

dialog.setOnDismissListener(this);

return dialog;
}


关机Action:PowerAction

private final class PowerAction extends SinglePressAction implements LongPressAction {
private PowerAction() {
super(com.android.internal.R.drawable.ic_lock_power_off,
R.string.global_action_power_off);
}

@Override
public boolean onLongPress() {
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
mWindowManagerFuncs.rebootSafeMode(true);
return true;
}
return false;
}

@Override
public boolean showDuringKeyguard() {
return true;
}

@Override
public boolean showBeforeProvisioning() {
return true;
}

@Override
public void onPress() {
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown(false /* confirm */);
}
}


onPress()和onLongpress()是分别处理单击和长按的方法,那么WindownManagerService.java实现了WindowManagerPolicy.WindowManagerFuncs接口,所以实际上调用的是WindownManagerService.java类的shutdown()、rebootSafeMode()方法。

路径:framework/base/services/core/java/com/android/server/wm/WindowManagerService.java

最终都是调用ShutdownThread.java的方法。

该类路径:framework/base/services/core/java/com/android/server/power/ShutdownThread.java

/**
* 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);
}
/**
* 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) {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
return;
}

mReboot = true;
mRebootSafeMode = true;
mRebootUpdate = false;
mRebootReason = null;

shutdownInner(context, confirm);
}


最后调用shutdownInner()

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);
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
//创建关机确认对话框
sConfirmDialog = 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 = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
sConfirmDialog.show();
} else {
//不需要关机确认对话框,直接进入关机流程
beginShutdownSequence(context);
}
}


开始进入关机流程

private static void beginShutdownSequence(Context context) {
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, "Shutdown sequence already running, returning.");
return;
}
sIsStarted = true;
}

// Throw up a system dialog to indicate the device is rebooting / shutting down.
ProgressDialog pd = null;

// Path 1: Reboot to recovery and install the update
//   Condition: mRebootReason == 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
//   UI: spinning circle only (no progress bar)
//
// Path 3: Regular reboot / shutdown
//   Condition: Otherwise
//   UI: spinning circle only (no progress bar)
//检查是否是定时关机
if(!sIsPowerOffAlarm){
//非定时关机
pd = new ProgressDialog(context);
if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
if (mRebootUpdate) {
//Reboot to Recovery Progress Dialog. This is shown before it reboots to recovery
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_update_prepare));
pd.setMax(100);
pd.setProgressNumberFormat(null);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setProgress(0);
pd.setIndeterminate(false);
} else {
// Factory reset path. Set the dialog message accordingly.
//恢复出厂设置对话框属性设置Reboot to Recovery for factory reset
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_reset_message));
pd.setIndeterminate(true);
}
} else {
//关机Shutdown Progress Dialog. This is shown if the user chooses to power off the phone
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);
}
String[] bootcmd = {"bootanimation",
"shutdown"} ;
try {
////执行关机动画
Log.i(TAG, "exec the bootanimation ");
SystemProperties.set("service.bootanim.exit", "0");
Runtime.getRuntime().exec(bootcmd);
} catch (Exception e){
Log.e(TAG,"bootanimation command exe err!");
}
}

//初始化关机线程
sInstance.mProgressDialog = pd;
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
//启动关机线程
if(sIsPowerOffAlarm){
Looper.prepare();
sInstance.mHandler = new Handler();
Log.d(TAG,">>> before start <<<");
sInstance.start();
Looper.loop();
}else{
sInstance.mHandler = new Handler() {
};

sInstance.start();
}
}


run()

/**
* 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() {
BroadcastReceiver br = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// We don't allow apps to cancel this, so ignore the result.
//用于接收关机广播,bu,不允许appcancel this,忽略
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;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
//等待10s,前面定义的广播接收器收到关机广播时mActionDone设置为true,同时取消等待
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;
} else if (mRebootUpdate) {
int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
sInstance.setRebootProgress(status, null);
}
try {
mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
} catch (InterruptedException e) {
}
}
}
if (mRebootUpdate) {
sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
}

Log.i(TAG, "Shutting down activity manager...");

//10s内关闭ActivityManager服务
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
if (mRebootUpdate) {
sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
}

Log.i(TAG, "Shutting down package manager...");

//关掉PackageManager服务
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
if (pm != null) {
pm.shutdown();
}
if (mRebootUpdate) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}

// Shutdown radios.12秒内关闭收音机
shutdownRadios(MAX_RADIO_WAIT_TIME);
if (mRebootUpdate) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}

// 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.
//20s内关闭MountService服务
mActionDone = false;
final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
synchronized (mActionDoneSync) {
try {
final IMountService mount = IMountService.Stub.asInterface(
ServiceManager.checkService("mount"));
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;
} else if (mRebootUpdate) {
int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
(MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
MAX_SHUTDOWN_WAIT_TIME);
status += RADIO_STOP_PERCENT;
sInstance.setRebootProgress(status, null);
}
try {
mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
} catch (InterruptedException e) {
}
}
}
if (mRebootUpdate) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);

// If it's to reboot to install update, invoke uncrypt via init service.
uncrypt();
}
//重启或关机
rebootOrShutdown(mContext, mReboot, mRebootReason);
}


重启或关机

/**
* Do not call this directly. Use {@link #reboot(Context, String, boolean)}
* or {@link #shutdown(Context, boolean)} instead.
*
* @param context Context used to vibrate or null without vibration
* @param reboot true to reboot or false to shutdown
* @param reason reason for reboot
*/
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");
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
// vibrate before shutting down
//关机前震动
Vibrator vibrator = new SystemVibrator(context);
try {
//震动时间、属性设置
vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
} 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的方法关闭电源。
PowerManagerService.lowLevelShutdown();
}


run()方法主要完成以下一些工作:

(1)发送关机广播ACTION_SHUTDOWN;

(2)关闭服务;

(3)关闭Radio

(4)设置关机震动

(5)调用PowerManagerService的方法关闭电源。

路径:/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

/**
* Low-level function turn the device off immediately, without trying
* to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.
*/
public static void lowLevelShutdown() {
SystemProperties.set("sys.powerctl", "shutdown");
}


开始进入到jni层,暂时不深入分析。

情况三、四:LONG_PRESS_POWER_SHUT_OFF:

直接调用mWindowManagerFuncs.shutdown()进行关机。

把关机源码粗略的分析一遍,大概了解了关机的流程。对于篇头说的两个Intent的属性是定义在Intent.java

public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";

public static final String
ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";


把自己写的apk放在源码里编译,调用关机的函数shutdown()就可以实现关机功能了,当然也可以参考源码中的定时关机功能通过启动ShutdownActivity关机。

Intent sdIntent = new Intent(android.intent.action.ACTION_REQUEST_SHUTDOWN);
/*是否显示关机确认对话框 */      sdIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
sdIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
启动ShutdownActivity
this.startActivity(shutdown);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: