最近遇到fastboot关机电流偏高的问题,虽然最后确认是硬件的问题,但还是顺便分析了一下android开关机的流程。总结一下,加深印象,也方便日后查阅。

Android智能手机和平板一般都有Power key,长按Power key弹出关机对话框,选择power off就会让系统关闭。关机动作从按键触发中断,linux kernel层给android framework层返回按键事件进入framework层,再从framework层到kernel层执行关机任务。本文分析过程将分成两篇,(1)Framework层 (2)JNI和Kernel层,代码基于自己的android4.3源码。

一. 长按power key对应的handler代码:

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

    private final Runnable mPowerLongPress = new Runnable() {        @Override        public void run() {            // The context isn't read            if (mLongPressOnPowerBehavior < 0) {                mLongPressOnPowerBehavior = mContext.getResources().getInteger(                        com.android.internal.R.integer.config_longPressOnPowerBehavior);            }            int resolvedBehavior = mLongPressOnPowerBehavior;            if (FactoryTest.isLongPressOnPowerOffEnabled()) {                resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;            }            switch (resolvedBehavior) {            case LONG_PRESS_POWER_NOTHING:                break;            case LONG_PRESS_POWER_GLOBAL_ACTIONS:                mPowerKeyHandled = true;                if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {                    performAuditoryFeedbackForAccessibilityIfNeed();                }                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);                showGlobalActionsDialog();                break;            case LONG_PRESS_POWER_SHUT_OFF:            case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:                mPowerKeyHandled = true;                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);                mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);                break;            }        }    };

run()函数中通过从mLongPressOnPowerBehavior向resolvedBehavior传入值,从而基于resolvedBehavior决定关机动作。下面是对代码的分析:

1. mLongPressOnPowerBehavior初始值为-1,所以会通过getInteger()从config_longPressOnPowerBehavior配置选项中得到mLongPressOnPowerBehavior。

    int mLongPressOnPowerBehavior = -1;

2. 检查是否是FactoryTest模式enable了长按powerkey进行关机的选项,是则LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM。

3. switch(resolvedBehavior)来决定关机动作:

  • LONG_PRESS_POWER_NOTHING = 0,Do nothing;
  • LONG_PRESS_POWER_GLOBAL_ACTIONS = 1,这是正常关机所走的流程。首先mPowerKeyHandled = ture,然后sendCloseSystemWindows()发送显示关闭系统的对话框的请求,reason是SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS,
        void sendCloseSystemWindows(String reason) {        sendCloseSystemWindows(mContext, reason);    }    static void sendCloseSystemWindows(Context context, String reason) {        if (ActivityManagerNative.isSystemReady()) {            try {                ActivityManagerNative.getDefault().closeSystemDialogs(reason);            } catch (RemoteException e) {            }        }    }
    最后,showGlobalActionsDialog()会显示请求的对话框;
  • LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3,直接调用mWindowManagerFuncs.shutdown()进行关机,shutdown()原型:
            public void shutdown(boolean confirm);

二、显示power off对话框:showGlobalActionsDialog()

showGlobalActionsDialog()的定义:

    void showGlobalActionsDialog() {        if (mGlobalActions == null) {            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);        }        final boolean keyguardShowing = keyguardIsShowingTq();        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());        if (keyguardShowing) {            // since it took two seconds of long press to bring this up,            // poke the wake lock so they have some time to see the dialog.            mKeyguardMediator.userActivity();        }    }

下面是对代码的分析:

1. 这里首先new GlobalActions,注意一下GlobalActions()的后一个参数是mWindowManagerFuncs;

2. 然后会调用mGlobalActions.showDialog()来显示对话框;

Android 关机流程分析-----(1)Framework层_第1张图片

3. 最后根据keyguardShowing的值,也就是是否在锁屏状态,决定是否需要userActivity。一般不会有这种情况。

显示对话框的具体调用是mGlobalActions.showDialog(),它在frameworks/base/policy/src/com/android/internal/policy/impl/GlobalActions.java中。

    /**     * Show the global actions dialog (creating if necessary)     * @param keyguardShowing True if keyguard is showing     */    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {        mKeyguardShowing = keyguardShowing;        mDeviceProvisioned = isDeviceProvisioned;        if (mDialog != null) {            mDialog.dismiss();            mDialog = null;            // Show delayed, so that the dismiss of the previous dialog completes            mHandler.sendEmptyMessage(MESSAGE_SHOW);        } else {            handleShow();        }    }
再进入mGlobalActions.handleShow()中,handleShow()中调用了createDialog(),showDialog()、handleShow()和createDialog()都是GlobalActions类的私有函数。
    private void handleShow() {        awakenIfNecessary();        mDialog = createDialog();        prepareDialog();        WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();        attrs.setTitle("GlobalActions");        mDialog.getWindow().setAttributes(attrs);        mDialog.show();        mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);    }
createDialog()是最后要显示的对话框的内容,这个函数虽然很长,但是耐心分析很快就能知道它都做了什么。
    /**     * Create the global actions dialog.     * @return A new dialog.     */    private GlobalActionsDialog createDialog() {        // Simple toggle style if there's no vibrator, otherwise use a tri-state        if (!mHasVibrator) {            mSilentModeAction = new SilentModeToggleAction();        } else {            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);        }        mAirplaneModeOn = new ToggleAction(                R.drawable.ic_lock_airplane_mode,                R.drawable.ic_lock_airplane_mode_off,                R.string.global_actions_toggle_airplane_mode,                R.string.global_actions_airplane_mode_on_status,                R.string.global_actions_airplane_mode_off_status) {            void onToggle(boolean on) {                if (mHasTelephony && Boolean.parseBoolean(                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {                    mIsWaitingForEcmExit = true;                    // Launch ECM exit dialog                    Intent ecmDialogIntent =                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                    mContext.startActivity(ecmDialogIntent);                } else {                    changeAirplaneModeSystemSetting(on);                }            }            @Override            protected void changeStateFromPress(boolean buttonOn) {                if (!mHasTelephony) return;                // In ECM mode airplane state cannot be changed                if (!(Boolean.parseBoolean(                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {                    mState = buttonOn ? State.TurningOn : State.TurningOff;                    mAirplaneState = mState;                }            }            public boolean showDuringKeyguard() {                return true;            }            public boolean showBeforeProvisioning() {                return false;            }        };        onAirplaneModeChanged();        mItems = new ArrayList<Action>();        // first: power off        mItems.add(            new SinglePressAction(                    com.android.internal.R.drawable.ic_lock_power_off,                    R.string.global_action_power_off) {                public void onPress() {                    // shutdown by making sure radio and power are handled accordingly.                    mWindowManagerFuncs.shutdown(true);                }                public boolean onLongPress() {                    mWindowManagerFuncs.rebootSafeMode(true);                    return true;                }                public boolean showDuringKeyguard() {                    return true;                }                public boolean showBeforeProvisioning() {                    return true;                }            });        // next: airplane mode        mItems.add(mAirplaneModeOn);        // next: bug report, if enabled        if (Settings.Global.getInt(mContext.getContentResolver(),                Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0) {            mItems.add(                new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,                        R.string.global_action_bug_report) {                    public void onPress() {                        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);                        builder.setTitle(com.android.internal.R.string.bugreport_title);                        builder.setMessage(com.android.internal.R.string.bugreport_message);                        builder.setNegativeButton(com.android.internal.R.string.cancel, null);                        builder.setPositiveButton(com.android.internal.R.string.report,                                new DialogInterface.OnClickListener() {                                    @Override                                    public void onClick(DialogInterface dialog, int which) {                                        // Add a little delay before executing, to give the                                        // dialog a chance to go away before it takes a                                        // screenshot.                                        mHandler.postDelayed(new Runnable() {                                            @Override public void run() {                                                try {                                                    ActivityManagerNative.getDefault()                                                            .requestBugReport();                                                } catch (RemoteException e) {                                                }                                            }                                        }, 500);                                    }                                });                        AlertDialog dialog = builder.create();                        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);                        dialog.show();                    }                    public boolean onLongPress() {                        return false;                    }                    public boolean showDuringKeyguard() {                        return true;                    }                    public boolean showBeforeProvisioning() {                        return false;                    }                });        }        // last: silent mode        if (mShowSilentToggle) {            mItems.add(mSilentModeAction);        }        // one more thing: optionally add a list of users to switch to        if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {            addUsersToMenu(mItems);        }        mAdapter = new MyAdapter();        AlertParams params = new AlertParams(mContext);        params.mAdapter = mAdapter;        params.mOnClickListener = this;        params.mForceInverseBackground = true;        GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.        dialog.getListView().setItemsCanFocus(true);        dialog.getListView().setLongClickable(true);        dialog.getListView().setOnItemLongClickListener(                new AdapterView.OnItemLongClickListener() {                    @Override                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,                            long id) {                        return mAdapter.getItem(position).onLongPress();                    }        });        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);        dialog.setOnDismissListener(this);        return dialog;    }

Android 关机流程分析-----(1)Framework层_第2张图片
  • 前面函数中为稍后的各类选项做了准备工作;
  • first: power off,这里主要定义了两种动作,短按(onPress)和长按(onLongPress),对应的两种结果就是shutdown()和rebootSafeMode(); Android 关机流程分析-----(1)Framework层_第3张图片 Android 关机流程分析-----(1)Framework层_第4张图片
  • next: airplane mode
  • next: bug report, if enabled
  • last: silent mode

因为本文主要分析关机流程,所以对后面几个选项就不分析了。回到handleShow()中,然后调用mDialog类中的函数做显示窗口的动作。

三、执行ShutdownThread.shutdown(),启动关机线程执行关机动作。

前面在GlobalActions.createDialog()中,当进入power off,然后onPress()的时候,mWindowManagerFuncs.shutdown(ture)将被调用。

                public void onPress() {                    // shutdown by making sure radio and power are handled accordingly.                    mWindowManagerFuncs.shutdown(true);                }
看一下mWindowManagerFuncs的定义,可以看到它是一个WindowManagerFuncs接口类。

    private final WindowManagerFuncs mWindowManagerFuncs;
WindowManagerFuncs类是在/frameworks/base/core/java/android/view/WindowManagerPolicy.java中定义,它被包含在WindowManagerPolicy接口类中。

在WindowManagerFuncs类中,shutdown(boolean confirm)只给出了原型,并没有具体实现。搜索一下很容易发现真正被调用执行的是在/frameworks/base/services/java/com/android/server/wm/WindowManagerService.java中定义的shutdown(),即WindowManagerService.shutdown()。

    // Called by window manager policy.  Not exposed externally.    @Override    public void shutdown(boolean confirm) {        ShutdownThread.shutdown(mContext, confirm);    }    // Called by window manager policy.  Not exposed externally.    @Override    public void rebootSafeMode(boolean confirm) {        ShutdownThread.rebootSafeMode(mContext, confirm);    }
shutdown()和rebootSafeMode()都在这里定义并会被window manager policy调用。这里已经指明真正执行关机线程的是ShutdownThread.shutdown(mContext, confirm)。

下面来看一下具体的关机流程:

ShutdownThread类在frameworks/base/services/java/com/android/server/power/ShutdownThread.java中定义,下面是shutdown()的代码。

    /**     * Request a clean shutdown, waiting for subsystems to clean up their     * state etc.  Must be called from a Looper thread in which its UI     * is shown.     *     * @param context Context used to display the shutdown progress dialog.     * @param confirm true if user confirmation is needed before shutting down.     */    public static void shutdown(final Context context, boolean confirm) {        mReboot = false;        mRebootSafeMode = false;        shutdownInner(context, confirm);    }    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);        }    }
1. 注意两个参数:context 和 confirm,context用来用来显示关机进程的对话,confirm确保是true如果关机之前需要确认。这一点很容易理解。

Android 关机流程分析-----(1)Framework层_第5张图片 2. 在shutdown()将会调用shutdownInner(),longPressBehavior和resourceId是用来记录一些标志。

一般情况下confirm为true,即表示确认shutdown,然后系统会显示确认shutdown的对话框,同时执行beginShutdownSequence(),启动shutdown线程。如果不需要confirm就可以shutdown,则直接执行beginShutdownSequence(),启动shutdown线程。

3. 下面看一下beginShutdownSequence()的具体流程。

    private static void beginShutdownSequence(Context context) {        synchronized (sIsStartedGuard) {            if (sIsStarted) {                Log.d(TAG, "Shutdown sequence already running, returning.");                return;            }            sIsStarted = true;        }        // throw up an indeterminate system dialog to indicate radio is        // shutting down.        ProgressDialog pd = new ProgressDialog(context);        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.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();    }

  • 参数context非常重要,它继续用来显示关机进程的对话框;还要注意一点,sInstance是ShutdownThread静态类实例,也是this thread的实例,接下来还会用到很多它的函数。
        // static instance of this thread    private static final ShutdownThread sInstance = new ShutdownThread();

  • ProgressDialog pd用来启动一个不明确的系统对话框来表明radio正在关闭,在Google原生系统中可以看到这样的对话框。pd的成员函数setTitle()、setMessage()、setIndeterminate()、setCancelable()会根据context内容对对话框属性进行设置,show()会显示对话框。
  • 确保系统不会再进入睡眠。通过sInstance.mCpuWakeLock来获得wakelock,使系统不会睡眠。
  • 保证screen不会马上黑下去,这样可以保证更好的用户体验。通过sInstance.mScreenWakeLock获得screen wakelock使屏幕长亮。
  • 最后启动shutdown线程sInstance.start()。

四、framework层最后的一步:ShutdownThread.run()

当进程执行到sInstance.start()后,就进入了framework层最后的一步:ShutdownThread.run()。

    /**     * Makes sure we handle the shutdown gracefully.     * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.     */    public void run() {        BroadcastReceiver br = new BroadcastReceiver() {            @Override public void onReceive(Context context, Intent intent) {                // We don't allow apps to cancel this, so ignore the result.                actionDone();            }        };        /*         * Write a system property in case the system_server reboots before we         * get to the actual hardware restart. If that happens, we'll retry at         * the beginning of the SystemServer startup.         */        {            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);        }        /*         * If we are rebooting into safe mode, write a system property         * indicating so.         */        if (mRebootSafeMode) {            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");        }        Log.i(TAG, "Sending shutdown broadcast...");                // First send the high-level shut down broadcast.        mActionDone = false;        mContext.sendOrderedBroadcastAsUser(new Intent(Intent.ACTION_SHUTDOWN),                UserHandle.ALL, null, br, mHandler, 0, null, null);                final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;        synchronized (mActionDoneSync) {            while (!mActionDone) {                long delay = endTime - SystemClock.elapsedRealtime();                if (delay <= 0) {                    Log.w(TAG, "Shutdown broadcast timed out");                    break;                }                try {                    mActionDoneSync.wait(delay);                } catch (InterruptedException e) {                }            }        }                Log.i(TAG, "Shutting down activity manager...");                final IActivityManager am =            ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));        if (am != null) {            try {                am.shutdown(MAX_BROADCAST_TIME);            } catch (RemoteException e) {            }        }        // Shutdown radios.        shutdownRadios(MAX_RADIO_WAIT_TIME);        // Shutdown MountService to ensure media is in a safe state        IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {            public void onShutDownComplete(int statusCode) throws RemoteException {                Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");                actionDone();            }        };        Log.i(TAG, "Shutting down MountService");        // Set initial variables and time out time.        mActionDone = false;        final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;        synchronized (mActionDoneSync) {            try {                final IMountService mount = IMountService.Stub.asInterface(                        ServiceManager.checkService("mount"));                if (mount != null) {                    mount.shutdown(observer);                } else {                    Log.w(TAG, "MountService unavailable for shutdown");                }            } catch (Exception e) {                Log.e(TAG, "Exception during MountService shutdown", e);            }            while (!mActionDone) {                long delay = endShutTime - SystemClock.elapsedRealtime();                if (delay <= 0) {                    Log.w(TAG, "Shutdown wait timed out");                    break;                }                try {                    mActionDoneSync.wait(delay);                } catch (InterruptedException e) {                }            }        }        rebootOrShutdown(mReboot, mRebootReason);    }
run()函数虽然长,但是还是比较好理解的。

1. 如果分配的时间已经过去,不管radio和bluetooth状态如何都关闭。

2. 如果是rebootSafeMode,会设置一些系统属性。

3. 接下来是shutdown的流程,首先向APP层发送shutdown的广播。注意synchronized。

4. shutdown radios,调用shutdownRadios(),它也是ShutdownThread的成员函数。

5. shutdown mountservice,这样可以保证media的安全。

6. 设置初始化参数和时间。

7. rebootOrShutdown(),最后执行的shutdown流程的函数。

    /**     * Do not call this directly. Use {@link #reboot(Context, String, boolean)}     * or {@link #shutdown(Context, boolean)} instead.     *     * @param reboot true to reboot or false to shutdown     * @param reason reason for reboot     */    public static void rebootOrShutdown(boolean reboot, String reason) {        if (reboot) {            Log.i(TAG, "Rebooting, reason: " + reason);            try {                PowerManagerService.lowLevelReboot(reason);            } catch (Exception e) {                Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);            }        } else if (SHUTDOWN_VIBRATE_MS > 0) {            // vibrate before shutting down            Vibrator vibrator = new SystemVibrator();            try {                vibrator.vibrate(SHUTDOWN_VIBRATE_MS);            } 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();    }}
1. 注释表明:这是由shutdown(final Context context, boolean confirm)调用的。参数reboot如果是true,则reboot,false则shutdown;参数reason就是reboot reason。

2. 如果reboot是true,则会执行PowerManagerService.lowLevelReboot(reason)的过程;否则继续shutdown的过程。文章中分析shutdown的流程,所以reboot暂时不看。

3. 接下来系统会确保shutdown之前的机器震动,从注释很容易看明白。

4. Shutdown power开始进入底层的shutdown,即进入JNI层和kernel层。

PowerManagerService.lowLevelShutdown()是在frameworks/base/services/java/com/android/server/power/PowerManagerService.java中定义的。它是一个通往下层JNI的函数。

    /**     * Low-level function turn the device off immediately, without trying     * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.     */    public static void lowLevelShutdown() {        nativeShutdown();    }
nativeShutdown()就是通往下层的接口了。

上层framework层的分析就到此为止了,后续的文章将继续分析JNI层以及kernel的关机流程。





更多相关文章

  1. Android系统(245)---SystemServer进程的创建流程
  2. [置顶] Android 实现对话框圆角功能
  3. (连载)Android 8.0 : 系统启动流程之Linux内核
  4. Android,对话框定时自动关闭的实现
  5. android上层应用apk到G-sensor driver的大致流程
  6. 技术转载:Android对话框大合集

随机推荐

  1. 将count(*)值写入另一个表中的方法
  2. sql中varchar和nvarchar的区别与使用方法
  3. 解决SQL Server虚拟内存不足情况
  4. sql server不存在 sql server拒绝访问第1
  5. SQL Server口令 sql server安全性第1/2页
  6. 用SQL语句实现随机查询数据并不显示错误
  7. SQL命令大全-中英文对照第1/3页
  8. 解决MSSQL2005远程连接sql2000非默认端口
  9. MSSQL差异备份取系统权限的相关软件下载
  10. SQL Server 不删除信息重新恢复自动编号