長按電源鍵彈出關機按鈕,長按關機按鈕會彈出進入安全模式的設置,進入安全模式後將中止全部的第三方APP的加載,因爲咱們的系統只有本身定製的lunch,因此已經去掉系統的加載項LUNCHER2,進入安全模式後沒法加載啓動項而停在android界面,致使系統沒法啓動,爲了不繫統進入安全模式,只有屏蔽長按關機按鈕。java
android\frameworks\base\policy\src\com\android\internal\policy\impl\GlobalActions.javaandroid
在private GlobalActionsDialog createDialog() 這個方法裏定義關機界面和各類模式的選擇等操做監聽事件;安全
如下是長按關機按鈕彈出安全模式選擇的按鈕監聽:
ide
dialog.getListView().setOnItemLongClickListener(
new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
long id) {
return mAdapter.getItem(position).onLongPress();
}
});post
咱們要作的就是把它改爲this
dialog.getListView().setOnItemLongClickListener(null);.net
便可中止監聽長按關機按鈕事件,也就表面上阻止了用戶選擇安全模式的可能;orm
下面分析一下android4.2的安全模式:server
android\frameworks\base\core\java\android\os\SystemService.javablog
/** 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.java
public 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); }