zoukankan      html  css  js  c++  java
  • Android 关机

    Android Framework层Power键关机流程(二,关机流程)

    Android 关机(reboot)流程 -- "sys.powerctl"

    一.framework

    一.framework
    1.1.按钮关机 mWindowManagerFuncs实现接口
    frameworksaseservicescorejavacomandroidserverpolicyGlobalActions.java

            @Override
            public void onPress() {
               boolean isBox = "box".equals(SystemProperties.get("ro.target.product"));
               boolean notUseLegeacyWakeupRestartPlatform = "rk3399".equals(SystemProperties.get("ro.board.platform"));
               if(isBox && !notUseLegeacyWakeupRestartPlatform){
                   wakeup_restart_set();
                   Log.d(TAG,"don't shutdown here,only go to sleep for box!");
                   mPowerManager.goToSleep(SystemClock.uptimeMillis());
               }else{
                // shutdown by making sure radio and power are handled accordingly.
                mWindowManagerFuncs.shutdown(false /* confirm */);
               }
            }
        }

    1.2.回调接口

    frameworksasecorejavaandroidviewWindowManagerPolicy.java  

        /**
         * Interface for calling back in to the window manager that is private
         * between it and the policy.
         */
        public interface WindowManagerFuncs {
    	
    		public void shutdown(boolean confirm);
    

    1.3.实现接口 shutdown方法
    frameworksaseservicescorejavacomandroidserverwmWindowManagerService.java

        // Called by window manager policy.  Not exposed externally.
        @Override
        public void shutdown(boolean confirm) {
            ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
        }
    

    1.4.关机流程

    frameworksaseservicescorejavacomandroidserverpowerShutdownThread.java  

        /**
        *请求清除关闭,等待子系统清除它们的
        *状态等。必须从其UI中的环形线程中调用
        *显示。
        * @param context用于显示关机进度对话框的上下文。
        * @param原因代码传递给android_reboot()(例如“userrequested”),或null。
        * @param confirm true如果在关闭之前需要用户确认。
        */
        public static void shutdown(final Context context, String reason, boolean confirm) {
            mReboot = false;
            mRebootSafeMode = false;
            mReason = reason;
            shutdownInner(context, confirm);
        }

    //shutdownInner 主要还是看 beginShutdownSequence这个方法

        static void shutdownInner(final Context context, boolean confirm) {
            // ensure that only one thread is trying to power down.
            // any additional calls are just returned
            synchronized (sIsStartedGuard) {
                if (sIsStarted) {
                    Log.d(TAG, "Request to shutdown already running, returning.");
                    return;
                }
            }
    
            final int longPressBehavior = context.getResources().getInteger(
                            com.android.internal.R.integer.config_longPressOnPowerBehavior);
            final int resourceId = mRebootSafeMode
                    ? com.android.internal.R.string.reboot_safemode_confirm
                    : (longPressBehavior == 2
                            ? com.android.internal.R.string.shutdown_confirm_question
                            : com.android.internal.R.string.shutdown_confirm);
    
            Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
    
            if (confirm) {
                final CloseDialogReceiver closer = new CloseDialogReceiver(context);
                if (sConfirmDialog != null) {
                    sConfirmDialog.dismiss();
                }
                sConfirmDialog = new AlertDialog.Builder(context)
                        .setTitle(mRebootSafeMode
                                ? com.android.internal.R.string.reboot_safemode_title
                                : com.android.internal.R.string.power_off)
                        .setMessage(resourceId)
                        .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                beginShutdownSequence(context);
                            }
                        })
                        .setNegativeButton(com.android.internal.R.string.no, null)
                        .create();
                closer.dialog = sConfirmDialog;
                sConfirmDialog.setOnDismissListener(closer);
                sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
                sConfirmDialog.show();
            } else {
                beginShutdownSequence(context);
            }
        }

    //beginShutdownSequence 对话框 关机动画

    	    // Used for shutdownanimation
        private static final String SYSTEM_SHUTDOWNANIMATION_FILE = "/system/media/shutdownanimation.zip";
    	
        private static void beginShutdownSequence(Context context) {
            synchronized (sIsStartedGuard) {
                if (sIsStarted) {
                    Log.d(TAG, "Shutdown sequence already running, returning.");
                    return;
                }
                sIsStarted = true;
            }
    
            // Throw up a system dialog to indicate the device is rebooting / shutting down.
            ProgressDialog pd = new ProgressDialog(context);
    
            // Path 1: Reboot to recovery for update
            //   Condition: mReason == REBOOT_RECOVERY_UPDATE
            //
            //  Path 1a: uncrypt needed
            //   Condition: if /cache/recovery/uncrypt_file exists but
            //              /cache/recovery/block.map doesn't.
            //   UI: determinate progress bar (mRebootHasProgressBar == True)
            //
            // * Path 1a is expected to be removed once the GmsCore shipped on
            //   device always calls uncrypt prior to reboot.
            //
            //  Path 1b: uncrypt already done
            //   UI: spinning circle only (no progress bar)
            //
            // Path 2: Reboot to recovery for factory reset
            //   Condition: mReason == REBOOT_RECOVERY
            //   UI: spinning circle only (no progress bar)
            //
            // Path 3: Regular reboot / shutdown
            //   Condition: Otherwise
            //   UI: spinning circle only (no progress bar)
            if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
                // We need the progress bar if uncrypt will be invoked during the
                // reboot, which might be time-consuming.
                mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
                        && !(RecoverySystem.BLOCK_MAP_FILE.exists());
                pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
                if (mRebootHasProgressBar) {
                    pd.setMax(100);
                    pd.setProgress(0);
                    pd.setIndeterminate(false);
                    pd.setProgressNumberFormat(null);
                    pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                    pd.setMessage(context.getText(
                                com.android.internal.R.string.reboot_to_update_prepare));
                } else {
                    pd.setIndeterminate(true);
                    pd.setMessage(context.getText(
                                com.android.internal.R.string.reboot_to_update_reboot));
                }
            } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
                // Factory reset path. Set the dialog message accordingly.
                pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
                pd.setMessage(context.getText(
                            com.android.internal.R.string.reboot_to_reset_message));
                pd.setIndeterminate(true);
            } else {
                pd.setTitle(context.getText(com.android.internal.R.string.power_off));
                pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
                pd.setIndeterminate(true);
            }
            pd.setCancelable(false);
            pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
    
            pd.show();
    
            sInstance.mProgressDialog = pd;
            sInstance.mContext = context;
            sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    
            // make sure we never fall asleep again
            sInstance.mCpuWakeLock = null;
            try {
                sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
                        PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
                sInstance.mCpuWakeLock.setReferenceCounted(false);
                sInstance.mCpuWakeLock.acquire();
            } catch (SecurityException e) {
                Log.w(TAG, "No permission to acquire wake lock", e);
                sInstance.mCpuWakeLock = null;
            }
    
            // also make sure the screen stays on for better user experience
            sInstance.mScreenWakeLock = null;
            if (sInstance.mPowerManager.isScreenOn()) {
                try {
                    sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
                            PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
                    sInstance.mScreenWakeLock.setReferenceCounted(false);
                    sInstance.mScreenWakeLock.acquire();
                } catch (SecurityException e) {
                    Log.w(TAG, "No permission to acquire wake lock", e);
                    sInstance.mScreenWakeLock = null;
                }
            }
    
            // start the thread that initiates shutdown
            sInstance.mHandler = new Handler() {
            };
            sInstance.start();
        }
    

    run

        public void run() {
    		//一大堆代码
            if (checkAnimationFileExist()) {//跑开机动画
                start_shutdownanim();
                thaw_orien_shutdownanim();
            }		
            rebootOrShutdown(mContext, mReboot, mReason);
        }
    
        public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
            if (reboot) {
                Log.i(TAG, "Rebooting, reason: " + reason);
                PowerManagerService.lowLevelReboot(reason);
                Log.e(TAG, "Reboot failed, will attempt shutdown instead");
                reason = null;
            } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
                // vibrate before shutting down
                Vibrator vibrator = new SystemVibrator(context);
                try {
                    vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
                } catch (Exception e) {
                    // Failure to vibrate shouldn't interrupt shutdown.  Just log it.
                    Log.w(TAG, "Failed to vibrate during shutdown.", e);
                }
    
                // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
                try {
                    Thread.sleep(SHUTDOWN_VIBRATE_MS);
                } catch (InterruptedException unused) {
                }
            }
    
            // Shutdown power
            Log.i(TAG, "Performing low-level shutdown...");
            PowerManagerService.lowLevelShutdown(reason);
        }

    1.5.PowerManagerService 设置关机属性
    frameworksaseservicescorejavacomandroidserverpowerPowerManagerService.java

        public static void lowLevelShutdown(String reason) {
            if (reason == null) {
                reason = "";
            }
            SystemProperties.set("sys.powerctl", "shutdown," + reason);
        }
    

     二.kernel

    2.1.system/core/rootdir/init.rc

    on property:sys.powerctl=*
       powerctl ${sys.powerctl}  

    2.2.systemcoreinituiltins.cpp 解析属性 showdown ANDROID_RB_POWEROFF

    static int do_powerctl(const std::vector<std::string>& args) {
        const char* command = args[1].c_str();
        int len = 0;
        unsigned int cmd = 0;
        const char *reboot_target = "";
        void (*callback_on_ro_remount)(const struct mntent*) = NULL;
    
        if (strncmp(command, "shutdown", 8) == 0) {
            cmd = ANDROID_RB_POWEROFF;
            len = 8;
        } else if (strncmp(command, "reboot", 6) == 0) {
            cmd = ANDROID_RB_RESTART2;
            len = 6;
        } else {
            ERROR("powerctl: unrecognized command '%s'
    ", command);
            return -EINVAL;
        }
    
        if (command[len] == ',') {
            if (cmd == ANDROID_RB_POWEROFF &&
                !strcmp(&command[len + 1], "userrequested")) {
                // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
                // Run fsck once the file system is remounted in read-only mode.
                callback_on_ro_remount = unmount_and_fsck;
            } else if (cmd == ANDROID_RB_RESTART2) {
                reboot_target = &command[len + 1];
            }
        } else if (command[len] != '') {
            ERROR("powerctl: unrecognized reboot target '%s'
    ", &command[len]);
            return -EINVAL;
        }
    
        std::string timeout = property_get("ro.build.shutdown_timeout");
        unsigned int delay = 0;
    
        if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) {
            Timer t;
            // Ask all services to terminate.
            ServiceManager::GetInstance().ForEachService(
                [] (Service* s) { s->Terminate(); });
    
            while (t.duration() < delay) {
                ServiceManager::GetInstance().ReapAnyOutstandingChildren();
    
                int service_count = 0;
                ServiceManager::GetInstance().ForEachService(
                    [&service_count] (Service* s) {
                        // Count the number of services running.
                        // Exclude the console as it will ignore the SIGTERM signal
                        // and not exit.
                        // Note: SVC_CONSOLE actually means "requires console" but
                        // it is only used by the shell.
                        if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
                            service_count++;
                        }
                    });
    
                if (service_count == 0) {
                    // All terminable services terminated. We can exit early.
                    break;
                }
    
                // Wait a bit before recounting the number or running services.
                usleep(kTerminateServiceDelayMicroSeconds);
            }
            NOTICE("Terminating running services took %.02f seconds", t.duration());
        }
    
        return android_reboot_with_callback(cmd, 0, reboot_target,
                                            callback_on_ro_remount);
    }

    2.3.看android_reboot_with_callback 这个回调

    int android_reboot_with_callback(
        int cmd, int flags __unused, const char *arg,
        void (*cb_on_remount)(const struct mntent*))
    {
        int ret;
        remount_ro(cb_on_remount);
        switch (cmd) {
            case ANDROID_RB_RESTART:
                ret = reboot(RB_AUTOBOOT);
                break;
    
            case ANDROID_RB_POWEROFF:
                ret = reboot(RB_POWER_OFF);
                break;
    
            case ANDROID_RB_RESTART2:
                ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                               LINUX_REBOOT_CMD_RESTART2, arg);
                break;
    
            default:
                ret = -1;
        }
    
        return ret;
    }
    
    int android_reboot(int cmd, int flags, const char *arg)
    {
        return android_reboot_with_callback(cmd, flags, arg, NULL);
    }
    

      

     

  • 相关阅读:
    读GNU官方的Make manual
    GNU LD之一LMA和VMA
    GNU LD之二LD script
    gcc 库的链接顺序问题
    GDB远程连接RX Probe在线debug程序
    mips gnu工具使用
    read PSE TPS2384 POE Firmware Guide
    adult道具项目开发
    2、与网络相关的命令 netstat , tcpdump 等。
    1、与 CPU、 内存、 磁盘相关的命令
  • 原文地址:https://www.cnblogs.com/crushgirl/p/15023295.html
Copyright © 2011-2022 走看看