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

Android关机流程源码分析

2016-12-31 18:23 561 查看
http://blog.csdn.net/yangwen123/article/details/11722105

上一篇文章Android
开关机动画显示源码分析详细介绍了开关机动画的显示过程,Android系统开机时,在启动SurfaceFlinger服务过程中通过Android属性系统方式来启动bootanim进程,实现开机动画显示过程;当系统关机时,又是如何启动关机动画的呢?Android系统的整个关机流程又是怎样的呢?本文就针对这两个问题透过源码来给出具体的分析。我们知道,当长按电源键,系统会弹出关机提示对话框



当点击选择关机时,系统就会完成整个关机流程。接下来就通过源码来介绍Android关机流程的完整实现过程。当长按电源键时,按键消息被分发到PhoneWindowManager的interceptKeyBeforeQueueing函数中处理:

[java] view
plaincopy

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {

...

switch (keyCode) {

...

case KeyEvent.KEYCODE_POWER: {

result &= ~ACTION_PASS_TO_USER;

if (down) {

if (isScreenOn && !mPowerKeyTriggered

&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {

mPowerKeyTriggered = true;

mPowerKeyTime = event.getDownTime();

interceptScreenshotChord();//抓屏

}

ITelephony telephonyService = getTelephonyService();

boolean hungUp = false;

if (telephonyService != null) {

try {

if (telephonyService.isRinging()) {

//当来电时按下电源键,启动静音

telephonyService.silenceRinger();

} else if ((mIncallPowerBehavior

& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0

&& telephonyService.isOffhook()) {

// Otherwise, if "Power button ends call" is enabled,

// the Power button will hang up any current active call.

hungUp = telephonyService.endCall();

}

} catch (RemoteException ex) {

Log.w(TAG, "ITelephony threw RemoteException", ex);

}

}

interceptPowerKeyDown(!isScreenOn || hungUp

|| mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);

} else {

...

}

break;

}

...

}

return result;

}

电源键和音量键的组合可以实现特定功能,比如按下电源键和音量向下键,可实现抓屏,interceptKeyBeforeQueueing函数首先根据条件处理电源键按下的特定任务,然后调用interceptPowerKeyDown做进一步处理

[java] view
plaincopy

private void interceptPowerKeyDown(boolean handled) {

mPowerKeyHandled = handled;

if (!handled) {

//隔500ms处理电源按键事件

mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());

}

}

这里的mHandler是在初始化PhoneWindowManager对象时创建的

[java] view
plaincopy

public void init(Context context, IWindowManager windowManager,WindowManagerFuncs windowManagerFuncs,

LocalPowerManager powerManager) {

...

mHandler = new PolicyHandler();

...

}

将一个Runnable对象mPowerLongPress发送到PolicyHandler中进行处理

[java] view
plaincopy

private final Runnable mPowerLongPress = new Runnable() {

public void run() {

// The context isn't read

if (mLongPressOnPowerBehavior < 0) {

mLongPressOnPowerBehavior = mContext.getResources().getInteger(

com.android.internal.R.integer.config_longPressOnPowerBehavior);

}

switch (mLongPressOnPowerBehavior) {

case LONG_PRESS_POWER_NOTHING:

break;

case LONG_PRESS_POWER_GLOBAL_ACTIONS:

mPowerKeyHandled = true;

performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);

sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);

showGlobalActionsDialog();

break;

case LONG_PRESS_POWER_SHUT_OFF:

mPowerKeyHandled = true;

performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);

sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);

mWindowManagerFuncs.shutdown();

break;

}

}

};

在处理电源长按事件时,根据mLongPressOnPowerBehavior完成不同的处理过程,mLongPressOnPowerBehavior的值是通过配置文件来设置的,在frameworks/base/core/res/values/config.xml中有以下一段配置:



通过读取配置文件取得config_longPressOnPowerBehavior配置的值为1,因此将显示关机对话框

[java] view
plaincopy

case LONG_PRESS_POWER_GLOBAL_ACTIONS:

mPowerKeyHandled = true;

performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);

//向ActivityManagerService请求关闭所有窗口

sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);

//显示关机对话框

showGlobalActionsDialog();

break;

关机对话框显示:

[java] view
plaincopy

void showGlobalActionsDialog() {

//创建GlobalActions对象

if (mGlobalActions == null) {

mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);

}

final boolean keyguardShowing = keyguardIsShowingTq();

//显示对话框

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.

mKeyguardMediator.pokeWakelock();

}

}

通过GlobalActions的showDialog函数来显示对话框

[java] view
plaincopy

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();//关机对话框显示

}

}

[java] view
plaincopy

private void handleShow() {

//创建对话框

mDialog = createDialog();

prepareDialog();//设置对话框属性

mDialog.show();//显示对话框

mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);

}

createDialog()函数用于创建一个即将显示的关机对话框,就是前面图片显示的对话框。

[java] view
plaincopy

private AlertDialog createDialog() {

//=========================创建对话框显示的列表项视图=====================================

//每一个列表项被被抽象为Action对象,

// 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);

}

//创建飞行模式切换ToggleAction对象

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);

mHandler.removeMessages(EVENT_SERVICE_CHANGE_WAIT_TIMEOUT);

mHandler.sendEmptyMessageDelayed(EVENT_SERVICE_CHANGE_WAIT_TIMEOUT,DELAY_AIRPLANE_SET_TIME);

}

}

@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;

}

};

//更新当前飞行模式状态

onAirplaneModeChanged();

onRadioBusyStateChanged();

mItems = new ArrayList<Action>();

//向mItems列表中依次添加关机选择,飞行模式切换,静音模式选择

// first: power off

mItems.add(

//创建关机SinglePressAction

new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off,

R.string.global_action_power_off) {

public void onPress() {

// shutdown by making sure radio and power are handled accordingly.

mWindowManagerFuncs.shutdown();

}

public boolean onLongPress() {

mWindowManagerFuncs.rebootSafeMode();

return true;

}

public boolean showDuringKeyguard() {

return true;

}

public boolean showBeforeProvisioning() {

return true;

}

});

// next: airplane mode

mItems.add(mAirplaneModeOn);

// last: silent mode

if (SHOW_SILENT_TOGGLE) {

mItems.add(mSilentModeAction);

}

//获取系统中所有用户信息

List<UserInfo> users = mContext.getPackageManager().getUsers();

if (users.size() > 1) {//对于多用户Android系统,在显示的对话框下面添加用户切换选项

UserInfo currentUser;

try {

currentUser = ActivityManagerNative.getDefault().getCurrentUser();

} catch (RemoteException re) {

currentUser = null;

}

for (final UserInfo user : users) {

boolean isCurrentUser = currentUser == null

? user.id == 0 : (currentUser.id == user.id);

SinglePressAction switchToUser = new SinglePressAction(

com.android.internal.R.drawable.ic_menu_cc,

(user.name != null ? user.name : "Primary")

+ (isCurrentUser ? " \u2714" : "")) {

public void onPress() {

try {

ActivityManagerNative.getDefault().switchUser(user.id);

getWindowManager().lockNow();

} catch (RemoteException re) {

Log.e(TAG, "Couldn't switch user " + re);

}

}

public boolean showDuringKeyguard() {

return true;

}

public boolean showBeforeProvisioning() {

return false;

}

};

mItems.add(switchToUser);

}

}

mAdapter = new MyAdapter();//创建适配器,保存了所有数据,这里用MyAdapter保存列表项视图

//=========================创建对话框=========================================

final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);

ab.setAdapter(mAdapter, this).setInverseBackgroundForced(true);

final AlertDialog dialog = ab.create();

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) {

return mAdapter.getItem(position).onLongPress();//视图和数据相关联

}

});

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);

dialog.setOnDismissListener(this);

return dialog;

}

这里需要介绍对话框列表创建的方法,代码实现比较灵魂,值得学习。首先将显示对话框列表中的每一项用应该Action来描述,Action是一个接口,定义了每一个列表项的动作方法



各个列表项定义不同类型的Action,比如关机选项使用SinglePressAction来描述,目前Android系统定义了几种类型的Action,对应关机对话框中的不同选项。



将创建的列表选项添加到动态数组mItems中,并且为该对话框定义一个适配器MyAdapter,在单击对话框列表项时,调用适配器中对应的项来响应单击事件。Android适配器的使用实现了MVC编程模式,将数据和视图分开。通常我们将数据保存在一个数组中,通过适配器和视图控件关联显示,只不过这里的数据比较特殊,它是用来描述列表项显示的内容。

[java] view
plaincopy

public boolean onItemLongClick(AdapterView<?> parent, View view, int position,long id) {

return mAdapter.getItem(position).onLongPress();

}

public void onClick(DialogInterface dialog, int which) {

if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {

dialog.dismiss();

}

mAdapter.getItem(which).onPress();

}

对于关机选项,其单击和长按事件处理过程如下:

[java] view
plaincopy

public void onPress() {

// shutdown by making sure radio and power are handled accordingly.

mWindowManagerFuncs.shutdown();

}

public boolean onLongPress() {

mWindowManagerFuncs.rebootSafeMode();

return true;

}

对关机的处理都是调用mWindowManagerFuncs来完成的,mWindowManagerFuncs的类型为WindowManagerFuncs,在调用PhoneWindowManager的init函数时通过参数传进来。mWindowManagerFuncs对象在那里构造呢?WindowManagerService定义了一个WindowManagerPolicy类型变量:

[java] view
plaincopy

final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();

通过策略管理类PolicyManager对象的makeNewWindowManager函数创建一个窗口策略管理对象

[java] view
plaincopy

public static WindowManagerPolicy makeNewWindowManager() {

return sPolicy.makeNewWindowManager();

}

该函数通过Binder通信方式请求服务端Policy来完成对象的创建过程

Policy.Java

[java] view
plaincopy

public WindowManagerPolicy makeNewWindowManager() {

return new PhoneWindowManager();

}

在WindowManagerService的构造过程中,会创建一个PolicyThread类来初始化窗口管理策略WindowManagerPolicy

[java] view
plaincopy

private WindowManagerService(Context context, PowerManagerService pm,

boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {

...

PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);

thr.start();

synchronized (thr) {

while (!thr.mRunning) {

try {

thr.wait();

} catch (InterruptedException e) {

}

}

}

...

}

在PolicyThread线程中执行初始化函数

[java] view
plaincopy

static class PolicyThread extends Thread {

@Override

public void run() {

Looper.prepare();

...

mPolicy.init(mContext, mService, mService, mPM);

synchronized (this) {

mRunning = true;

notifyAll();

}

...

Looper.loop();

}

}

mPolicy的类型定义为WindowManagerPolicy类型,而WindowManagerPolicy是一个接口类型,PhoneWindowManager实现了该接口,为mPolicy创建的真正对象是PhoneWindowManager对象,因此PolicyThread线程将调用PhoneWindowManager的init函数

[java] view
plaincopy

public void init(Context context, IWindowManager windowManager,

WindowManagerFuncs windowManagerFuncs,LocalPowerManager powerManager) {

...

mWindowManagerFuncs = windowManagerFuncs;

...

}

传进来的参数windowManager和windowManagerFuncs都是WindowManagerService对象,因为WindowManagerService继承于IWindowManager.Stub类同时实现了WindowManagerPolicy.WindowManagerFuncs接口,这下就很清晰地知道GlobalActions类中的mWindowManagerFuncs变量其实是WindowManagerService对象,因此关机的单击及长按事件由WindowManagerService实现:

[java] view
plaincopy

public void shutdown() {

ShutdownThread.shutdown(mContext, true);

}

public void rebootSafeMode() {

ShutdownThread.rebootSafeMode(mContext, true);

}

WindowManagerService也不真正实现关机操作,而是转交个ShutdownThread来完成。对于关机处理过程:

[java] view
plaincopy

public static void shutdown(final Context context, boolean confirm) {

mReboot = false;

mRebootSafeMode = false;

shutdownInner(context, confirm);

}

该函数实现非常简单,只是设置一些标志位,然后将关机任务又转交给shutdownInner来处理,这里的参数confirm用于标识是否需要弹出关机确认对话框。



[java] view
plaincopy

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().getI
31f39
nteger(

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);

}

}

调用beginShutdownSequence函数进入关机流程。

[java] view
plaincopy

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();

shutdownTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_TIME;

//执行关机动画

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!");

}

//初始化关机线程ShutdownThread

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() {

};

//启动关机线程ShutdownThread

sInstance.start();

}

这个函数执行两个任务,1)通过虚拟机Runtime启动关机动画进程bootanimation,用于显示关机动画,开关机动画在Android
开关机动画显示源码分析进行了详细的分析介绍。2)启动关机线程ShutdownThread来完成关机操作

[java] view
plaincopy

public void run() {

BroadcastReceiver br = new BroadcastReceiver() {

@Override public void onReceive(Context context, Intent intent) {

// 用于接收关机广播

actionDone();

}

};

//写属性"sys.shutdown.requested"保存关机原因

{

String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");

SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);

}

//如果是安全模式关机,写属性"persist.sys.safemode"

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);

//等待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;

}

try {

mActionDoneSync.wait(delay);

} catch (InterruptedException e) {

}

}

}

//10S时间内关闭ActivityManager服务

final IActivityManager am =ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));

if (am != null) {

try {

am.shutdown(MAX_BROADCAST_TIME);

} catch (RemoteException e) {

}

}

//12s内关闭radios.

shutdownRadios(MAX_RADIO_WAIT_TIME);

//10s内关闭ICCS

shutdownIccs(MAX_ICC_WAIT_TIME);

// 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");

//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;

}

try {

mActionDoneSync.wait(delay);

} catch (InterruptedException e) {

}

}

}

//关机时间定义为5s,这里计算关机超过的时间

long shutdownDelay = shutdownTime - SystemClock.elapsedRealtime();

if (shutdownDelay > 0) {

Log.i(TAG, "Shutdown delay:"+shutdownDelay);

SystemClock.sleep(shutdownDelay);

}

//继续关机

rebootOrShutdown(mReboot, mRebootReason);

}

该函数内主要完成以下一些工作:

(1)发送关机广播ACTION_SHUTDOWN

(2)关闭ActivityManager 服务

(3)关闭无线相关的服务

(4)关闭Iccs

(5)关闭MountService服务

[java] view
plaincopy

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) {//震动时间为500ms

// vibrate before shutting down

Vibrator vibrator = new SystemVibrator();

try {

//关机震动500ms

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) {

}

}

//关闭电源

Log.i(TAG, "Performing low-level shutdown...");

PowerManagerService.lowLevelShutdown();

}

这里是启动关机震动并关闭电源

[java] view
plaincopy

public static void lowLevelShutdown() {

nativeShutdown();

}

这里通过JNI调用C++的关机函数

[java] view
plaincopy

static void nativeShutdown(JNIEnv *env, jobject clazz) {

delFlag();

android_reboot(ANDROID_RB_POWEROFF, 0, 0);

}

android_reboot函数最终通过Linux系统调用关闭系统。到此关机操作就基本完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  流程