zoukankan      html  css  js  c++  java
  • Android关机流程源码分析

    上一篇文章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()) {
    							// 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做进一步处理

    private void interceptPowerKeyDown(boolean handled) {
    	mPowerKeyHandled = handled;
    	if (!handled) {
    		//隔500ms处理电源按键事件
    		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() {
    		// 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,因此将显示关机对话框

    case LONG_PRESS_POWER_GLOBAL_ACTIONS:
    	mPowerKeyHandled = true;
    	performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
    	//向ActivityManagerService请求关闭所有窗口
    	sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
    	//显示关机对话框
    	showGlobalActionsDialog();
    	break;

    关机对话框显示:

    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函数来显示对话框

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


    private void handleShow() {
    	//创建对话框
    	mDialog = createDialog();
    	prepareDialog();//设置对话框属性
    	mDialog.show();//显示对话框
    	mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
    }

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

    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编程模式,将数据和视图分开。通常我们将数据保存在一个数组中,通过适配器和视图控件关联显示,只不过这里的数据比较特殊,它是用来描述列表项显示的内容。

    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() {
    	// 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类型变量:

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

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

    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来完成关机操作

    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服务

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

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

    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系统调用关闭系统。到此关机操作就基本完成了。

  • 相关阅读:
    最全的项目
    最全的liunx系统修改root用户密码
    最全docker安装步骤
    最全的ideal 常 用 的 快 捷
    最全的ideal 常用的快捷
    ftp路径
    站点路径
    sublime text3 切换中文方法
    UI设计: PS 快捷键 Ctrl+Shift+alt+T,旋转复制
    SQL中表与表的简单关系
  • 原文地址:https://www.cnblogs.com/james1207/p/3324816.html
Copyright © 2011-2022 走看看