前言

安全模式是安卓系统的一种特殊模式,和WINDOWS的安全模式相似,在安全模式下用户可以轻松地修复手机系统的一些错误,方便快捷。由于第三方应用程序,可能会存在一定的兼容性问题,所以在安装软件后会出现系统文件报错、手机无法正常开机或者开机后系统程序不停报错的现象。遇到这种情况,若进行恢复出厂设置,手机中的资料是无法进行备份的,但是Android系统中添加了“安全模式”

代码说明

涉及的Frameworks 的几个类

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
frameworks/base/services/java/com/android/server/SystemServer.java

SystemServer.java 中是启动安全模式的代码

   private void startOtherServices() {
          final Context context = mSystemContext;
          VibratorService vibrator = null;
          DynamicSystemService dynamicSystem = null;
          IStorageManager storageManager = null;
          NetworkManagementService networkManagement = null;  
 IpSecService ipSecService = null;
          NetworkStatsService networkStats = null;
          NetworkPolicyManagerService networkPolicy = null;
          ConnectivityService connectivity = null;
          NsdService serviceDiscovery = null;
          WindowManagerService wm = null;
          SerialService serial = null;
          NetworkTimeUpdateService networkTimeUpdater = null;
          InputManagerService inputManager = null;
          TelephonyRegistry telephonyRegistry = null;
          ConsumerIrService consumerIr = null;
          MmsServiceBroker mmsService = null;
          HardwarePropertiesManagerService hardwarePropertiesService = null;
  
          boolean disableSystemTextClassifier = SystemProperties.getBoolean(
                  "config.disable_systemtextclassifier", false);
  
          boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime",
                  false);
          boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
                  false);
          boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false);
          boolean enableLeftyService = SystemProperties.getBoolean("config.enable_lefty", false);
  
          boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
  
          boolean isWatch = context.getPackageManager().hasSystemFeature(
                  PackageManager.FEATURE_WATCH);
  
          boolean isArc = context.getPackageManager().hasSystemFeature(
                  "org.chromium.arc");
  
          boolean enableVrService = context.getPackageManager().hasSystemFeature(
                  PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
  
          // For debugging RescueParty
          if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
              throw new RuntimeException();
          }
  
          try {
              final String SECONDARY_ZYGOTE_PRELOAD = "SecondaryZygotePreload";
              // We start the preload ~1s before the webview factory preparation, to
              // ensure that it completes before the 32 bit relro process is forked
              // from the zygote. In the event that it takes too long, the webview
              // RELRO process will block, but it will do so without holding any locks.
              mZygotePreload = SystemServerInitThreadPool.get().submit(() -> {
                  try {
                      Slog.i(TAG, SECONDARY_ZYGOTE_PRELOAD);
                      TimingsTraceLog traceLog = new TimingsTraceLog(
                              SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
                      traceLog.traceBegin(SECONDARY_ZYGOTE_PRELOAD);
                      if (!Process.ZYGOTE_PROCESS.preloadDefault(Build.SUPPORTED_32_BIT_ABIS[0])) {
                          Slog.e(TAG, "Unable to preload default resources");
                      }
                      traceLog.traceEnd();
                  } catch (Exception ex) {
                      Slog.e(TAG, "Exception preloading default resources", ex);
                  }
              }, SECONDARY_ZYGOTE_PRELOAD);
  
              traceBeginAndSlog("StartKeyAttestationApplicationIdProviderService");
              ServiceManager.addService("sec_key_att_app_id_provider",
                      new KeyAttestationApplicationIdProviderService(context));
              traceEnd();
  
              traceBeginAndSlog("StartKeyChainSystemService");
              mSystemServiceManager.startService(KeyChainSystemService.class);
              traceEnd();
  
              traceBeginAndSlog("StartSchedulingPolicyService");
              ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
              traceEnd();
  		  
		final boolean safeMode = wm.detectSafeMode();
          if (safeMode) {
              // If yes, immediately turn on the global setting for airplane mode.
              // Note that this does not send broadcasts at this stage because
              // subsystems are not yet up. We will send broadcasts later to ensure
              // all listeners have the chance to react with special handling.
              Settings.Global.putInt(context.getContentResolver(),
                      Settings.Global.AIRPLANE_MODE_ON, 1);
          }

在SystemServer中的startOtherServices()中通过调用wm.detectSafeMode()判断是否进入安全模式, 接下来看下WMS源码看是怎么判断是否进入安全模式的,然后从这里屏蔽掉进入安全模式的入口就可以了。

WindowManagerService.java 中是否进入安全模式代码如下:

 

public boolean detectSafeMode() {
        if (!mInputManagerCallback.waitForInputDevicesReady(
                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
            Slog.w(TAG_WM, "Devices still not ready after waiting "
                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
                   + " milliseconds before attempting to detect safe mode.");
        }
 
        if (Settings.Global.getInt(
                mContext.getContentResolver(), Settings.Global.SAFE_BOOT_DISALLOWED, 0) != 0) {
            return false;
        }
 
        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
                    || SystemProperties.getInt(ShutdownThread.RO_SAFEMODE_PROPERTY, 0) != 0) {
                mSafeMode = true;
                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
            }
        } catch (IllegalArgumentException e) {
        }
        if (mSafeMode) {
            Log.i(TAG_WM, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
            // May already be set if (for instance) this process has crashed
            if (SystemProperties.getInt(ShutdownThread.RO_SAFEMODE_PROPERTY, 0) == 0) {
                SystemProperties.set(ShutdownThread.RO_SAFEMODE_PROPERTY, "1");
            }
        } else {
            Log.i(TAG_WM, "SAFE MODE not enabled");
        }
        mPolicy.setSafeMode(mSafeMode);
        return mSafeMode;
    }

从上面的函数可以看出是否进入安全模式的的判断,通过分析上述代码可知,系统在这里对5个键值进行了扫描:菜单键menuState、s键sState、dpad中间键dpadState、轨迹球trackballState以及音量减键volumeDownState。其中有一个被检测到,则会将安全模式唯一的全局变量标识SafeMode设为true相关操作,当然你也可以屏蔽掉安全模式,但是我们在这里是不推荐这样做的。

Logo

智屏生态联盟致力于大屏生态发展,利用大屏快应用技术降低开发者开发、发布大屏应用门槛

更多推荐