reinicio silencioso de Android REINICIAR QUIESCENT

antecedentes

La animación de arranque nativa de Android debe procesarse en el proyecto y, bajo ciertas condiciones, se requiere un reinicio silencioso (antes de que el sistema Android comience a ingresar al escritorio, la pantalla permanece completamente en un estado sin brillo). Debido a que la ROM utilizada en el proyecto es apoyado por la plataforma MTK, no sabía el modo QUIESCENT_REBOOT de Android al principio, así que encontré una manera de lograr esta función Para más detalles, ver el blog:. Animación de arranque basado en Android-Q . Debido a que el Linux posterior permitió a SELinux mejorar las restricciones de permisos, la solución original requirió cambios relativamente grandes porque los permisos restringían la ejecución, lectura y escritura de archivos. Más tarde, aprendí el modo QUIESCENT_REBOOT de Android y lo usé en el proyecto para resolver el problema. Este es el principio del modo QUIESCENT_REBOOT.

Principio y proceso de Android Quiescent

1. PowerManager.reboot (PowerManager.REBOOT_QUIESCENT) para reiniciar silenciosamente (la prueba local puede activar el reinicio de energía de svc inactivo a través de la línea de comando)

1 、 代码 : frameworks / base / core / java / android / os / PowerManager.java

public void reboot(String reason) {
    
    
    try {
    
    
        // mService是PowerManagerService
        mService.reboot(false, reason, true);
    } catch (RemoteException e) {
    
    
        throw e.rethrowFromSystemServer();
    }
}

2 、 代码 frameworks / base / services / core / java / com / android / server / power / PowerManagerService.java

// True if the lights should stay off until an explicit user action.
// 这个标记记录是否静默重启
private static boolean sQuiescent;

@Override // Binder call
public void reboot(boolean confirm, String reason, boolean wait) {
    
    
    mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
    ......
    final long ident = Binder.clearCallingIdentity();
    try {
    
    
        shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
    } finally {
    
    
        Binder.restoreCallingIdentity(ident);
    }
}

private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
            final String reason, boolean wait) {
    
    
    // lowLevelReboot会去解析reason并存储到SystemProperties
    if (mHandler == null || !mSystemReady) {
    
    
        if (RescueParty.isAttemptingFactoryReset()) {
    
    
            // If we're stuck in a really low-level reboot loop, and a
            // rescue party is trying to prompt the user for a factory data
            // reset, we must GET TO DA CHOPPA!
            PowerManagerService.lowLevelReboot(reason);
        } else {
    
    
            throw new IllegalStateException("Too early to call shutdown() or reboot()");
        }
    }

    // 调用ShutdownThread重启
    Runnable runnable = new Runnable() {
    
    
        @Override
        public void run() {
    
    
            synchronized (this) {
    
    
                if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
    
    
                    ShutdownThread.rebootSafeMode(getUiContext(), confirm);
                } else if (haltMode == HALT_MODE_REBOOT) {
    
    
                    ShutdownThread.reboot(getUiContext(), reason, confirm);
                } else {
    
    
                    ShutdownThread.shutdown(getUiContext(), reason, confirm);
                }
            }
        }
    };
    ......
}

public static void lowLevelReboot(String reason) {
    
    
    if (reason == null) {
    
    
        reason = "";
    }
    
    // If the reason is "quiescent", it means that the boot process should proceed
    // without turning on the screen/lights.
    // The "quiescent" property is sticky, meaning that any number
    // of subsequent reboots should honor the property until it is reset.
    if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
    
    
        sQuiescent = true;
        reason = "";
    } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
    
    
        sQuiescent = true;
        reason = reason.substring(0,
              reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
    }
    
    if (sQuiescent) {
    
    
        // Pass the optional "quiescent" argument to the bootloader to let it know
        // that it should not turn the screen/lights on.
        reason = reason + ",quiescent";
    }

    // 这里会存储到系统参数
    SystemProperties.set("sys.powerctl", "reboot," + reason);
    try {
    
    
        Thread.sleep(20 * 1000L);
    } catch (InterruptedException e) {
    
    
        Thread.currentThread().interrupt();
    }
    Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}

sQuiescent registra si se debe reiniciar en silencio, lowLevelReboot analizará el motivo y establecerá sQuiescent en verdadero, al mismo tiempo almacenará el motivo en SystemProperties y, finalmente, llamará a ShutdownThread para pasar el parámetro con el motivo.

3. Code frameworks / base / services / core / java / com / android / server / power / ShutdownThread.java
Esta clase se procesa principalmente por separado de acuerdo con algunas condiciones, como recuperación, etc. también pueden mostrar ventanas emergentes, aquí están Aquellos que estén interesados ​​pueden verlo por sí mismos según la ruta del código. No se usa en esta clase de reinicio silencioso.

4. Mencioné SystemProperties.set ("sys.powerctl", "reiniciar", + motivo), que es muy importante aquí. El reinicio silencioso almacenará este valor en el parámetro de inicio específico del kernel, que será recuperado por el sistema la próxima vez que se reinicie. El principio y el código fuente de SystemProperties están involucrados aquí, no lo analizo específicamente, sé para qué se usa.

5. Al mismo tiempo, el kernel también analizará el motivo y almacenará otras SystemProperties; el proceso aproximado es que si se lee el indicador Quiescent de rtc en lk, no se muestra el logotipo de inicio y se agrega androidboot.quiescent = 1 a cmdline; lk -> kernel -> init, init analizará la cmdline y analizará androidboot.quiescent = 1, y lo establecerá en ro.boot.quiescent = 1, de modo que todos los lugares en el siguiente Android sabrán que se trata de un arranque inactivo.

6. En bootanimation (frameworks / base / cmds / bootanimation), si se lee ro.boot.quiescent = 1, el
código de animación de arranque no se muestra : frameworks / base / cmds / bootanimation / BootAnimationUtil.cpp

    bool bootAnimationDisabled() {
    
    
45    char value[PROPERTY_VALUE_MAX];
46    property_get("debug.sf.nobootanimation", value, "0");
47    if (atoi(value) > 0) {
    
    
48        return true;
49    }
50
51    property_get("ro.boot.quiescent", value, "0");
52    return atoi(value) > 0;
53}

Código: frameworks / base / cmds / bootanimation / bootanimation_main.cpp

36int main()
37{
    
    
38    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
39    
      // 如果noBootAnimation,不展示开机动画
40    bool noBootAnimation = bootAnimationDisabled();
41    ALOGI_IF(noBootAnimation,  "boot animation disabled");
42    if (!noBootAnimation) {
    
    
43
44        sp<ProcessState> proc(ProcessState::self());
45        ProcessState::self()->startThreadPool();
46
47        // create the boot animation object (may take up to 200ms for 2MB zip)
48        sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
49
50        waitForSurfaceFlinger();
51
52        boot->run("BootAnimation", PRIORITY_DISPLAY);
53
54        ALOGV("Boot animation set up. Joining pool.");
55
56        IPCThreadState::self()->joinThreadPool();
57    }
58    return 0;
59}

7. Aquí también implica la ocultación del registro de arranque En la capa del núcleo, el logotipo o el brillo se oculta según los parámetros de arranque almacenados en el núcleo. Probablemente sea una conjetura, si está interesado, puede estudiarlo usted mismo.

Resolver problemas en el proyecto

Además de ocultar la animación de arranque en el proyecto, también debe ajustar el brillo al mínimo.
1. Es necesario bloquear el código para la configuración predeterminada de la programación de encendido. Código
: frameworks / base / services / core / java / com / android / server / display / DisplayManagerService.java

    @VisibleForTesting
    DisplayManagerService(Context context, Injector injector) {
    
    
        super(context);
        ......
        PowerManager pm = mContext.getSystemService(PowerManager.class);

        // 注释掉的为源代码,这里会取一个默认160的亮度并设置
        //mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
           
        // 这里根据静默的参数,增加判断
        if (SystemProperties.getInt("ro.boot.quiescent", 0) == 0) {
    
    
            mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
        }
        ......
    }

2. Porque además de este lugar, se establecerá el brillo predeterminado y la capa de Android restablecerá el brillo después de que el sistema esté activo, y volverá al brillo normal.

Supongo que te gusta

Origin blog.csdn.net/archie_7/article/details/109285017
Recomendado
Clasificación