http://blog.csdn.net/yangwen123/article/details/11722105
上一篇文章Android 开关机动画显示源码分析详细介绍了开关机动画的显示过程,Android系统开机时,在启动SurfaceFlinger服务过程中通过Android属性系统方式来启动bootanim进程,实现开机动画显示过程;当系统关机时,又是如何启动关机动画的呢?Android系统的整个关机流程又是怎样的呢?本文就针对这两个问题透过源码来给出具体的分析。我们知道,当长按电源键,系统会弹出关机提示对话框
当点击选择关机时,系统就会完成整个关机流程。接下来就通过源码来介绍Android关机流程的完整实现过程。当长按电源键时,按键消息被分发到PhoneWindowManager的interceptKeyBeforeQueueing函数中处理:
-
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()) {
-
-
-
hungUp = telephonyService.endCall();
-
}
-
} catch (RemoteException ex) {
-
Log.w(TAG, "ITelephony threw RemoteException", ex);
-
}
-
}
-
interceptPowerKeyDown(!isScreenOn || hungUp
-
|| mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
-
} else {
-
...
-
}
-
break;
-
}
-
...
-
}
-
return result;
-
}
电源键和音量键的组合可以实现特定功能,比如按下电源键和音量向下键,可实现抓屏,interceptKeyBeforeQueueing函数首先根据条件处理电源键按下的特定任务,然后调用interceptPowerKeyDown做进一步处理
-
private void interceptPowerKeyDown(boolean handled) {
-
mPowerKeyHandled = handled;
-
if (!handled) {
-
-
mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
-
}
-
}
这里的mHandler是在初始化PhoneWindowManager对象时创建的
-
public void init(Context context, IWindowManager windowManager,WindowManagerFuncs windowManagerFuncs,
-
LocalPowerManager powerManager) {
-
...
-
mHandler = new PolicyHandler();
-
...
-
}
将一个Runnable对象mPowerLongPress发送到PolicyHandler中进行处理
-
private final Runnable mPowerLongPress = new Runnable() {
-
public void run() {
-
-
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,因此将显示关机对话框
-
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
-
mPowerKeyHandled = true;
-
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-
-
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-
-
showGlobalActionsDialog();
-
break;
关机对话框显示:
-
void showGlobalActionsDialog() {
-
-
if (mGlobalActions == null) {
-
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
-
}
-
final boolean keyguardShowing = keyguardIsShowingTq();
-
-
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
-
if (keyguardShowing) {
-
-
-
mKeyguardMediator.pokeWakelock();
-
}
-
}
通过GlobalActions的showDialog函数来显示对话框
-
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
-
mKeyguardShowing = keyguardShowing;
-
mDeviceProvisioned = isDeviceProvisioned;
-
if (mDialog != null) {
-
mDialog.dismiss();
-
mDialog = null;
-
-
mHandler.sendEmptyMessage(MESSAGE_SHOW);
-
} else {
-
handleShow();
-
}
-
}
-
private void handleShow() {
-
-
mDialog = createDialog();
-
prepareDialog();
-
mDialog.show();
-
mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
-
}
createDialog()函数用于创建一个即将显示的关机对话框,就是前面图片显示的对话框。
-
private AlertDialog createDialog() {
-
-
-
-
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;
-
-
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;
-
-
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();
-
-
-
mItems.add(
-
-
new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off,
-
R.string.global_action_power_off) {
-
public void onPress() {
-
-
mWindowManagerFuncs.shutdown();
-
}
-
public boolean onLongPress() {
-
mWindowManagerFuncs.rebootSafeMode();
-
return true;
-
}
-
public boolean showDuringKeyguard() {
-
return true;
-
}
-
public boolean showBeforeProvisioning() {
-
return true;
-
}
-
});
-
-
mItems.add(mAirplaneModeOn);
-
-
if (SHOW_SILENT_TOGGLE) {
-
mItems.add(mSilentModeAction);
-
}
-
-
List users = mContext.getPackageManager().getUsers();
-
if (users.size() > 1) {
-
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();
-
-
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编程模式,将数据和视图分开。通常我们将数据保存在一个数组中,通过适配器和视图控件关联显示,只不过这里的数据比较特殊,它是用来描述列表项显示的内容。
-
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();
-
}
对于关机选项,其单击和长按事件处理过程如下:
-
public void onPress() {
-
-
mWindowManagerFuncs.shutdown();
-
}
-
-
public boolean onLongPress() {
-
mWindowManagerFuncs.rebootSafeMode();
-
return true;
-
}
对关机的处理都是调用mWindowManagerFuncs来完成的,mWindowManagerFuncs的类型为WindowManagerFuncs,在调用PhoneWindowManager的init函数时通过参数传进来。mWindowManagerFuncs对象在那里构造呢?WindowManagerService定义了一个WindowManagerPolicy类型变量:
-
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
通过策略管理类PolicyManager对象的makeNewWindowManager函数创建一个窗口策略管理对象
-
public static WindowManagerPolicy makeNewWindowManager() {
-
return sPolicy.makeNewWindowManager();
-
}
该函数通过Binder通信方式请求服务端Policy来完成对象的创建过程
Policy.java
-
public WindowManagerPolicy makeNewWindowManager() {
-
return new PhoneWindowManager();
-
}
在WindowManagerService的构造过程中,会创建一个PolicyThread类来初始化窗口管理策略WindowManagerPolicy
-
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线程中执行初始化函数
-
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函数
-
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实现:
-
public void shutdown() {
-
ShutdownThread.shutdown(mContext, true);
-
}
-
-
public void rebootSafeMode() {
-
ShutdownThread.rebootSafeMode(mContext, true);
-
}
WindowManagerService也不真正实现关机操作,而是转交个ShutdownThread来完成。对于关机处理过程:
-
public static void shutdown(final Context context, boolean confirm) {
-
mReboot = false;
-
mRebootSafeMode = false;
-
shutdownInner(context, confirm);
-
}
该函数实现非常简单,只是设置一些标志位,然后将关机任务又转交给shutdownInner来处理,这里的参数confirm用于标识是否需要弹出关机确认对话框。
-
static void shutdownInner(final Context context, boolean confirm) {
-
-
-
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);
-
}
-
}
调用beginShutdownSequence函数进入关机流程。
-
private static void beginShutdownSequence(Context context) {
-
synchronized (sIsStartedGuard) {
-
if (sIsStarted) {
-
Log.d(TAG, "Shutdown sequence already running, returning.");
-
return;
-
}
-
sIsStarted = true;
-
}
-
-
-
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);
-
-
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!");
-
}
-
-
sInstance.mContext = context;
-
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-
-
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;
-
}
-
-
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;
-
}
-
}
-
-
sInstance.mHandler = new Handler() {
-
};
-
-
sInstance.start();
-
}
这个函数执行两个任务,1)通过虚拟机Runtime启动关机动画进程bootanimation,用于显示关机动画,开关机动画在
Android 开关机动画显示源码分析进行了详细的分析介绍。2)启动关机线程ShutdownThread来完成关机操作
-
public void run() {
-
BroadcastReceiver br = new BroadcastReceiver() {
-
@Override public void onReceive(Context context, Intent intent) {
-
-
actionDone();
-
}
-
};
-
-
{
-
String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
-
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
-
}
-
-
if (mRebootSafeMode) {
-
SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
-
}
-
Log.i(TAG, "Sending shutdown 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) {
-
}
-
}
-
}
-
-
final IActivityManager am =ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
-
if (am != null) {
-
try {
-
am.shutdown(MAX_BROADCAST_TIME);
-
} catch (RemoteException e) {
-
}
-
}
-
-
shutdownRadios(MAX_RADIO_WAIT_TIME);
-
-
shutdownIccs(MAX_ICC_WAIT_TIME);
-
-
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");
-
-
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) {
-
}
-
}
-
}
-
-
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服务
-
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) {
-
-
Vibrator vibrator = new SystemVibrator();
-
try {
-
-
vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
-
} catch (Exception e) {
-
-
Log.w(TAG, "Failed to vibrate during shutdown.", e);
-
}
-
-
try {
-
Thread.sleep(SHUTDOWN_VIBRATE_MS);
-
} catch (InterruptedException unused) {
-
}
-
}
-
-
Log.i(TAG, "Performing low-level shutdown...");
-
PowerManagerService.lowLevelShutdown();
-
}
这里是启动关机震动并关闭电源
-
public static void lowLevelShutdown() {
-
nativeShutdown();
-
}
这里通过JNI调用C++的关机函数
-
static void nativeShutdown(JNIEnv *env, jobject clazz) {
-
delFlag();
-
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
-
}
android_reboot函数最终通过Linux系统调用关闭系统。到此关机操作就基本完成了。