• Android 中的 安全模式(safe mode)


    前言

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

    代码说明

    涉及的Frameworks 的几个类

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

    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);
              }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    在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;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

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

  • 相关阅读:
    手写Demo体验volatile可见性的作用
    Hadoop完全分布式搭建
    unity中实现场景跳转
    maven
    巨噬细胞膜包裹PLGA纳米粒HCPT-MCNP/MCF-7细胞膜包覆PLGA纳米球共载姜黄素和二氢卟吩e6的研究
    【精华】拒绝国外IP海外IP访问的几种方法
    Linux之线程互斥
    【线性表】—不带头单向非循环链表的增删查改
    ElasticSearch6.8.4&kibana6.8.4 安装教程
    Linux: network: tcp_rmem/rmem_default
  • 原文地址:https://blog.csdn.net/houxian1103/article/details/128033863