长按电源键弹出关机按钮,长按关机按钮会弹出进入安全模式的设置,进入安全模式后将停止所有的第三方APP的加载,由于我们的系统只有自己定制的lunch,所以已经去掉系统的加载项LUNCHER2,进入安全模式后无法加载启动项而停在android界面,导致系统无法启动,为了避免系统进入安全模式,只有屏蔽长按关机按钮。
android\frameworks\base\policy\src\com\android\internal\policy\impl\GlobalActions.java
在private GlobalActionsDialog createDialog() 这个方法里定义关机界面和各种模式的选择等操作监听事件;
以下是长按关机按钮弹出安全模式选择的按钮监听:
dialog.getListView().setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { return mAdapter.getItem(position).onLongPress(); } });我们要做的就是把它改成
dialog.getListView().setOnItemLongClickListener(null);
即可停止监听长按关机按钮事件,也就表面上阻止了用户选择安全模式的可能;
下面分析一下android4.2的安全模式:
android\frameworks\base\core\java\android\os\SystemService.java
/** Request that the init daemon start a named service. */
public static void start(String name) { SystemProperties.set("ctl.start", name); }关于SystemProperties.set方法参见属性设置机制:
http://blog.csdn.net/ameyume/article/details/8056492
在android\frameworks\base\core\jni\AndroidRuntime.cpp中定义了
register_android_os_SystemProperties(JNIEnv *env);
这个方法在android\frameworks\base\core\jni\android_os_SystemProperties.cpp中定义,实际上是返回了此文件中的jni方法集合:
static JNINativeMethod method_table[] = {
{ "native_get", "(Ljava/lang/String;)Ljava/lang/String;", (void*) SystemProperties_getS }, { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", (void*) SystemProperties_getSS }, { "native_get_int", "(Ljava/lang/String;I)I", (void*) SystemProperties_get_int }, { "native_get_long", "(Ljava/lang/String;J)J", (void*) SystemProperties_get_long }, { "native_get_boolean", "(Ljava/lang/String;Z)Z", (void*) SystemProperties_get_boolean }, { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) SystemProperties_set }, { "native_add_change_callback", "()V", (void*) SystemProperties_add_change_callback },};这些方法是android\frameworks\base\core\java\android\os\SystemProperties.java中方法的本地实现(jni实现);
启动WindowManagerService,会调用
android\frameworks\base\services\java\com\android\server\wm\WindowManagerService.java中detectSafeMode()方法,代码如下:
public boolean detectSafeMode() {
if (!mInputMonitor.waitForInputDevicesReady( INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) { Slog.w(TAG, "Devices still not ready after waiting " + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS + " milliseconds before attempting to detect safe mode."); } int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_MENU); int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S); int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, KeyEvent.KEYCODE_DPAD_CENTER); int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL, InputManagerService.BTN_MOUSE); int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_VOLUME_DOWN); mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0 || volumeDownState > 0; try { if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) { mSafeMode = true; SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, ""); } } catch (IllegalArgumentException e) { } if (mSafeMode) { Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState + " dpad=" + dpadState + " trackball=" + trackballState + ")"); } else { Log.i(TAG, "SAFE MODE not enabled"); } mPolicy.setSafeMode(mSafeMode); return mSafeMode; }如果监测到是安全模式将进入到安全模式;
在android\frameworks\base\services\java\com\android\server\am\ActivityManagerService.java中
public final void enterSafeMode() {
synchronized(this) { // It only makes sense to do this before the system is ready // and started launching other packages. if (!mSystemReady) { try { AppGlobals.getPackageManager().enterSafeMode(); } catch (RemoteException e) { } } } }在\android\frameworks\base\services\java\com\android\server\pm\PackageManagerService.java中public void enterSafeMode() {
enforceSystemOrRoot("Only the system can request entering safe mode"); if (!mSystemReady) { mSafeMode = true; } }android\frameworks\base\services\java\com\android\server\wm\WindowManagerService.javapublic void systemReady() {
mPolicy.systemReady(); }最后会调用到android\frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java
/** {@inheritDoc} */
public void systemReady() { if (mKeyguardMediator != null) { // tell the keyguard mKeyguardMediator.onSystemReady(); } synchronized (mLock) { updateOrientationListenerLp(); mSystemReady = true; mHandler.post(new Runnable() { public void run() { updateSettings(); } }); } }android\frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
public final void showSafeModeOverlay() {
View v = LayoutInflater.from(mContext).inflate( com.android.internal.R.layout.safe_mode, null); WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; lp.width = WindowManager.LayoutParams.WRAP_CONTENT; lp.height = WindowManager.LayoutParams.WRAP_CONTENT; lp.gravity = Gravity.BOTTOM | Gravity.START; lp.format = v.getBackground().getOpacity(); lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; ((WindowManager)mContext.getSystemService( Context.WINDOW_SERVICE)).addView(v, lp); }android\frameworks\base\services\java\com\android\server\AppWidgetService.java
public void systemReady(boolean safeMode) {
mSafeMode = safeMode; mAppWidgetServices.get(0).systemReady(safeMode); // Register for the boot completed broadcast, so we can send the // ENABLE broacasts. If we try to send them now, they time out, // because the system isn't ready to handle them yet. mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); // Register for configuration changes so we can update the names // of the widgets when the locale changes. mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null); // Register for broadcasts about package install, etc., so we can // update the provider list. IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, sdFilter, null, null); IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_REMOVED); userFilter.addAction(Intent.ACTION_USER_STOPPING); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) { onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); } } }, userFilter); }