(10)Android之路====一夫当关的POWER键

Power键使用的场景和使用的频率都很高,本次从浅层次了解它.首先看一下使用它的场景:

power键:
单击事件:
1,息屏休眠
2,亮屏唤醒

长按事件:
3,长按关机
4,长按开机

双击事件:
5,双击进相机

组合事件:
关机:
6,power + vol-进recovery
7,power + vol+进Factory test mode
开机:
8,power + vol-截屏

特殊事件:
9,通话挂断

上面是一个参考示例,不一定所有手机厂商都是这样做的,但都大同小异.1,2,3,5,8,9是在Android正常模式下作用的,4是SoC级作用的,6,7是在uboot下作用的.

篇幅有限,本次只研究前4种情况,其它情况不做详细介绍.其中第4中情况(长按开机)已经在第7篇开机流程中介绍过了.

首先是power的物理操作,会通过底层驱动一层层上传,到Framework时,经过InputManagerService处理按键事件后,最终将传递给PhoneWindowManager的dispatchUnhandledKey().

public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
    ...
    if (!interceptFallback(win, fallbackEvent, policyFlags)) {
        fallbackEvent.recycle();
        fallbackEvent = null;
    }
    ...
}

private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
    int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
    if ((actions & ACTION_PASS_TO_USER) != 0) {
        long delayMillis = interceptKeyBeforeDispatching(
                win, fallbackEvent, policyFlags);
        if (delayMillis == 0) {
            return true;
        }
    }
    return false;
}

其中interceptKeyBeforeQueueing()处理具体的业务逻辑:

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    ...
    switch (keyCode) {
        ...
        case KeyEvent.KEYCODE_POWER: {
            // Any activity on the power button stops the accessibility shortcut
            cancelPendingAccessibilityShortcutAction();
            result &= ~ACTION_PASS_TO_USER;
            isWakeKey = false; // wake-up will be handled separately
            if (down) {
                interceptPowerKeyDown(event, interactive);
            } else {
                interceptPowerKeyUp(event, interactive, canceled);
            }
            break;
        }
        ...
    }
    ...
    if (isWakeKey) {
        // 按power键时,isWakeKey置为false,于是不会调用wakeUp函数,即不会唤醒系统点亮屏幕
        wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
    }

    return result;
}

接下来我们分别看一下interceptPowerKeyDown()和interceptPowerKeyUp()处理流程.

1,息屏休眠

息屏休眠过程用到的是interceptPowerKeyUp,代码如下:

private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
    // 事件被取消,或者在按下Power键时,该事件已被消耗掉,那么就不用继续处理
    final boolean handled = canceled || mPowerKeyHandled;
    mScreenshotChordPowerKeyTriggered = false;
    // 退出截屏
    cancelPendingScreenshotChordAction();
    // 取消MSG_POWER_LONG_PRESS事件,即在一定事件内Power键弹起,则表示这一次不是长按Power键
    cancelPendingPowerKeyAction();

    if (!handled) {
        // Figure out how to handle the key now that it has been released.
        mPowerKeyPressCounter += 1;

        final int maxCount = getMaxMultiPressPowerCount();
        final long eventTime = event.getDownTime();
        if (mPowerKeyPressCounter < maxCount) {
            // This could be a multi-press.  Wait a little bit longer to confirm.
            // Continue holding the wake lock.
            // 处理Power键被多次按下场景对应,
            Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
                    interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
            msg.setAsynchronous(true);
            mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
            return;
        }

        // No other actions.  Handle it immediately.
        powerPress(eventTime, interactive, mPowerKeyPressCounter);
    }

    // Done.  Reset our state.
    finishPowerKeyPress();
}

其中powerPress处理具体时间,finishPowerKeyPress复位按键状态,这里,我们跟一下powerPress:

private void powerPress(long eventTime, boolean interactive, int count) {
    ...
    if (count == 2) {
        powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
    } else if (count == 3) {
        powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
    } else if (interactive && !mBeganFromNonInteractive) {
        switch (mShortPressOnPowerBehavior) {
            case SHORT_PRESS_POWER_NOTHING:
                break;
            case SHORT_PRESS_POWER_GO_TO_SLEEP:	// 最终执行这里,调用PMS的goToSleep
                goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
                break;
            ...
        }
    }
}

PowerManagerService.java

private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
    synchronized (mLock) {
        if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
            updatePowerStateLocked();
        }
    }
}

public void goToSleep(long eventTime, int reason, int flags) {
    ...
    try {
        goToSleepInternal(eventTime, reason, flags, uid);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

会执行goToSleepNoUpdateLocked:

@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
    ...
    try {
        ...
        // 标记最后一次灭屏时间
        mLastSleepTime = eventTime;
        // 是否进入屏保
        mSandmanSummoned = true;
        // 设置wakefulness值为WAKEFULNESS_DOZING,因此先进Doze状态
        setWakefulnessLocked(WAKEFULNESS_DOZING, reason);

        // Report the number of wake locks that will be cleared by going to sleep.
        // 灭屏时,将清除以下三种使得屏幕保持亮屏的wakelock锁
        int numWakeLocksCleared = 0;
        final int numWakeLocks = mWakeLocks.size();
        for (int i = 0; i < numWakeLocks; i++) {
            final WakeLock wakeLock = mWakeLocks.get(i);
            switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                case PowerManager.FULL_WAKE_LOCK:
                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                case PowerManager.SCREEN_DIM_WAKE_LOCK:
                    numWakeLocksCleared += 1;
                    break;
            }
        }
        EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);

        // Skip dozing if requested.
        // 如果带有PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE的flag,则直接进入Sleep状态,不再进入Doze状态
        if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
            // 真正进入休眠的方法
            reallyGoToSleepNoUpdateLocked(eventTime, uid);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}

根据逻辑,可以看出,屏幕除非指定flag为GO_TO_SLEEP_FLAG_NO_DOZE时,会直接进入sleep,否则会先进入Doze状态,之后,再进入sleep状态.这里的息屏流程会先通过setWakefulnessLocked进Doze状态.(PMS定义了4种屏幕状态: Awake唤醒, Dream屏保, Doze打盹, Asleep休眠),然后通过flags判断是否调用reallyGoToSleepNoUpdateLocked进入休眠状态.我们先来分析setWakefulnessLocked,代码如下:

void setWakefulnessLocked(int wakefulness, int reason) {
    if (mWakefulness != wakefulness) {
        mWakefulness = wakefulness;
        mWakefulnessChanging = true;
        mDirty |= DIRTY_WAKEFULNESS;
        if (mNotifier != null) {
            mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
        }
    }
}

这里调用了Notifier的onWakefulnessChangeStarted方法,Notifier是PMS中用于"通知"的组件类:

public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
    final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
    ...
    // Handle any early interactive state changes.
    // Finish pending incomplete ones from a previous cycle.
    if (mInteractive != interactive) {
        // Finish up late behaviors if needed.
        if (mInteractiveChanging) {
            handleLateInteractiveChange();
        }
        ...
        // 处理早期工作
        handleEarlyInteractiveChange();
    }
}

wakefulness在前面设置为Doze,所以是不可交互状态,会执行handleEarlyInteractiveChange()方法:

private void handleEarlyInteractiveChange() {
    synchronized (mLock) {
        if (mInteractive) {
            // Waking up...
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    // Note a SCREEN tron event is logged in PowerManagerService.
                    mPolicy.startedWakingUp();
                }
            });

            // Send interactive broadcast.
            mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
            mPendingWakeUpBroadcast = true;
            updatePendingBroadcastLocked();
        } else {
            // Going to sleep...
            // Tell the policy that we started going to sleep.
            final int why = translateOffReason(mInteractiveChangeReason);
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    // 通过PhoneWindowManager设置锁屏
                    mPolicy.startedGoingToSleep(why);
                }
            });
        }
    }
}

在这个方法中,将调用mPolicy.startedGoingToSleep(why)进行锁屏流程,回到PMS中,在处理完setWakefulnessLocked()方法后,由于没有PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE,所以不会立即执行reallyGoToSleepNoUpdateLocked()方法,此时goToSleepNoUpdateLocked()方法完毕并返回true。之后开始执行updatePowerStateLocked()方法,此方法分为6个阶段:
阶段0: 更新基础信息,电池, 屏幕唤醒标示, 亮度;
阶段1: 更新wakefulness;
阶段2: 更新display状态;
阶段3: 更新屏保;
阶段4: 如果wakefulness改变,做最后的收尾工作;
阶段5: 更新suspend锁;

这里不详细深入此函数,有机会后面如果介绍PMS,应该会涉及到此函数,代码如下:

private void updatePowerStateLocked() {
    ...

    try {
        // Phase 0: Basic state updates.
        updateIsPoweredLocked(mDirty);
        updateStayOnLocked(mDirty);
        updateScreenBrightnessBoostLocked(mDirty);

        // Phase 1: Update wakefulness.
        // Loop because the wake lock and user activity computations are influenced
        // by changes in wakefulness.
        final long now = SystemClock.uptimeMillis();
        int dirtyPhase2 = 0;
        for (;;) {
            int dirtyPhase1 = mDirty;
            dirtyPhase2 |= dirtyPhase1;
            mDirty = 0;

            updateWakeLockSummaryLocked(dirtyPhase1);
            updateUserActivitySummaryLocked(now, dirtyPhase1);
            if (!updateWakefulnessLocked(dirtyPhase1)) {
                break;
            }
        }

        // Phase 2: Update display power state.
        boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);

        // Phase 3: Update dream state (depends on display ready signal).
        updateDreamLocked(dirtyPhase2, displayBecameReady);

        // Phase 4: Send notifications, if needed.
        finishWakefulnessChangeIfNeededLocked();

        // Phase 5: Update suspend blocker.
        // Because we might release the last suspend blocker here, we need to make sure
        // we finished everything else first!
        updateSuspendBlockerLocked();
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
}

在updateDreamLocked()中更新屏保状态时,如果此时处于Doze状态且没有进行屏保,则将调用reallyGoToSleepNoUpdateLocked()方法,将wakefulness值设置为了Sleep,代码如下:

private void updateDreamLocked(int dirty, boolean displayBecameReady) {
    ...
    scheduleSandmanLocked();
    ...
}

private void scheduleSandmanLocked() {
    if (!mSandmanScheduled) {
        mSandmanScheduled = true;
        Message msg = mHandler.obtainMessage(MSG_SANDMAN);
        msg.setAsynchronous(true);
        mHandler.sendMessage(msg);
    }
}

private final class PowerManagerHandler extends Handler {
    ...

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            ...
            case MSG_SANDMAN:
                handleSandman();
                break;
            ...
        }
    }
}

private void handleSandman() { // runs on handler thread
    ...
    // Doze has ended or will be stopped.  Update the power state.
    reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
    updatePowerStateLocked();
    ...
}

reallyGoToSleepNoUpdateLocked代码如下:

private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
    ...
    try {
        Slog.i(TAG, "Sleeping (uid " + uid +")...");
        // 设置为sleep状态
        setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}

除了power键息屏之外,还有超时息屏和Sensor息屏,这里不进行讨论.可以参考这篇博客.

2,亮屏唤醒

亮屏唤醒过程用到的是interceptPowerKeyDown,代码如下:

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
    ...
    // Latch power key state to detect screenshot chord.
    // 截屏功能
    if (interactive && !mScreenshotChordPowerKeyTriggered
            && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
        mScreenshotChordPowerKeyTriggered = true;
        mScreenshotChordPowerKeyTime = event.getDownTime();
        interceptScreenshotChord();
    }

    // Stop ringing or end call if configured to do so when power is pressed.
    TelecomManager telecomManager = getTelecommService();
    boolean hungUp = false;
    if (telecomManager != null) {
        if (telecomManager.isRinging()) {
            // Pressing Power while there's a ringing incoming
            // call should silence the ringer.
            // 来电话时,按下power键会使手机静音
            telecomManager.silenceRinger();
        } else if ((mIncallPowerBehavior
                & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
                && telecomManager.isInCall() && interactive) {
            // Otherwise, if "Power button ends call" is enabled,
            // the Power button will hang up any current active call.
            // 如果设置了power键挂机,在通话时,按下会挂断电话
            hungUp = telecomManager.endCall();
        }
    }
    ...

    // If the power key has still not yet been handled, then detect short
    // press, long press, or multi press and decide what to do.
    mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
            || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
    if (!mPowerKeyHandled) {
        if (interactive) {
            // 亮屏状态,主要是测量长按事件
            ...
        } else {
            // 息屏,用PMS的wakeup,唤醒系统
            wakeUpFromPowerKey(event.getDownTime());
            ...
        }
    }
}

这里wakeUpFromPowerKey调用了PMS的wakeUp:

private void wakeUpFromPowerKey(long eventTime) {
    akeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");
}

private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {
    ...
    mPowerManager.wakeUp(wakeTime, reason);
    return true;
}

PowerManagerService.java

private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName, int opUid) {
    synchronized (mLock) {
        if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
            updatePowerStateLocked();
        }
    }
}

public void wakeUp(long eventTime, String reason, String opPackageName) {
    ...
    try {
        wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

会执行wakeUpNoUpdateLocked,如下:

private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
        String opPackageName, int opUid) {
    ...
    try {
        ...
        // 设置wakefulness为WAKEFULNESS_AWAKE
        setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
        // 通知BatteryStatsService统计亮屏
        mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
        // 更新用户活动时间
        userActivityNoUpdateLocked(
                eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}

setWakefulnessLocked会调用mNotifier.onWakefulnessChangeStarted(wakefulness, reason);这个在息屏哪里已经分析过了,这里简单重复一下:

private void handleEarlyInteractiveChange() {
    synchronized (mLock) {
        if (mInteractive) {
            // Waking up...
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    // 回调PhoneWindowManager
                    mPolicy.startedWakingUp();
                }
            });
            ...
            // 发送广播
            updatePendingBroadcastLocked();
        } else {
            // Going to sleep...
        }
    }
}

public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
    ...
    if (mInteractive != interactive) {
        // Finish up late behaviors if needed.
        if (mInteractiveChanging) {
            handleLateInteractiveChange();
        }
        ...
        handleEarlyInteractiveChange();
    }
}

PhoneWindowManager.java

public void startedWakingUp() {
    ...    
    synchronized (mLock) {
        mAwake = true;

        updateWakeGestureListenerLp();
        updateOrientationListenerLp();
        updateLockScreenTimeout();
    }

    if (mKeyguardDelegate != null) {
        mKeyguardDelegate.onStartedWakingUp();
    }
}

接下来再看userActivityNoUpdateLocked,这个方法负责更新系统和用户最后交互时间,计算的时间在updateUserActivitySummary()方法中会用于判断何时灭屏,执行完后,我们回到wakeUpInternal()方法,接着会执行updatePowerStateLocked(),这个在息屏关机小节说过了,执行完那6个阶段后,就可以亮屏唤醒了.

除此之外,还有来电亮屏, USB插拔亮屏等情况,这里不做讨论,可以参考博客.

3,长按关机

关机流程再原生里边上层作用主要是在ShutdownThread.java,在SoC厂不仅是卖集成CPU的SoC,而是卖套片,套片包括:集成CPU的SoC, 射频基带和PMIC,(也有把基带集成到SoC中的,成本会高一些),所以,各SoC厂商都会根据自己的硬件会进行一定程度的修改.比如展锐,在ShutdownThread.java那级目录有增加为自己的硬件适配的代码:sprdpower.这里我们不讨论原厂适配后的机制,仅分析原生机制,下面,我们从ShutdownThread.java切入研究一下关机流程.

从PhoneWindowManager.java的interceptKeyBeforeQueueing-->interceptPowerKeyDown-->PolicyHandler-->powerLongPress-->showGlobalActionsInternal-->mGlobalActions.showDialog-->执行到GlobalActions.java的showDialog-->层层递进-->执行到WindowManagerService.java的shutdown-->执行到ShutdownThread.java的shutdown.

关机在Android上面是利用重启机制,我们可以通过adb shell执行reboot -p的方式关机,在ShutdownThread.java中有3种不同的重启机制,如下:

// 关机
public static void shutdown(final Context context, String reason, boolean confirm) {
    mReboot = false;
    mRebootSafeMode = false;
    mReason = reason;
    shutdownInner(context, confirm);
}

// 重启
public static void reboot(final Context context, String reason, boolean confirm) {
    mReboot = true;
    mRebootSafeMode = false;
    mRebootHasProgressBar = false;
    mReason = reason;
    shutdownInner(context, confirm);
}

// 重启到安全模式
public static void rebootSafeMode(final Context context, boolean confirm) {
    ...
    mReboot = true;
    mRebootSafeMode = true;
    mRebootHasProgressBar = false;
    mReason = null;
    shutdownInner(context, confirm);
}

从上面代码可以看出,几种不同形式的重启,内部都是通过shutdownInner()方法实现的,区别就是参数设置不同.

private static void shutdownInner(final Context context, boolean confirm) {
    ...
    if (confirm) {  // 确认,长按power键,界面显示确认按钮
        ...     // UI部分省略,dialog
        beginShutdownSequence(context);
        ...
    } else {        // 无需确认
        beginShutdownSequence(context);
    }
}

beginShutdownSequence()中执行以下流程:

private static void beginShutdownSequence(Context context) {
    ...
    // make sure we never fall asleep again
    // 获取CPU锁,防止休眠
    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
    // 启动并执行关机线程run方法
    sInstance.mHandler = new Handler() {
    };
    sInstance.start();
}

相关run方法如下:

public void run() {
    ...
    // 发送关机广播,有些应用要获取这个信息
    metricStarted(METRIC_SEND_BROADCAST);
    shutdownTimingLog.traceBegin("SendShutdownBroadcast");
    Log.i(TAG, "Sending shutdown broadcast...");

    ...
    // 关闭ActivityManager
    final IActivityManager am =
            IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
    if (am != null) {
        try {
            am.shutdown(MAX_BROADCAST_TIME);
        } catch (RemoteException e) {
        }
    }
    ...
    // 关闭PackageManagerService
    final PackageManagerService pm = (PackageManagerService)
        ServiceManager.getService("package");
    if (pm != null) {
        pm.shutdown();
    }
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
    }
    ...

    // Shutdown radios,包括Phone(modem), NFC, Bluetooth等
    shutdownTimingLog.traceBegin("ShutdownRadios");
    metricStarted(METRIC_RADIOS);
    shutdownRadios(MAX_RADIO_WAIT_TIME);
    ...

    // Shutdown StorageManagerService to ensure media is in a safe state
    IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
        public void onShutDownComplete(int statusCode) throws RemoteException {
            Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
            actionDone();
        }
    };
    ...
    storageManager.shutdown(observer);  // 关闭的同时,会测量其关闭耗时
    ...

    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);

        // If it's to reboot to install an update and uncrypt hasn't been
        // done yet, trigger it now.
        uncrypt();
    }

    ...
    // 执行重启或关机方法
    rebootOrShutdown(mContext, mReboot, mReason);
}

最后通过rebootOrShutdown()方法执行,其代码如下:

public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
    if (reboot) {
        ...
        PowerManagerService.lowLevelReboot(reason);
        ...
    } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
        // 延时振动,省略
    }

    // Shutdown power
    PowerManagerService.lowLevelShutdown(reason);
}

下边是PowerManagerService.java的lowLevelShutdown()方法:

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

其调用了SystemProperties.java的set方法:

public static void set(String key, String val) {
    if (val != null && val.length() > PROP_VALUE_MAX) {
        throw newValueTooLargeException(key, val);
    }
    if (TRACK_KEY_ACCESS) onKeyAccess(key);
    native_set(key, val);
}

可以看到其调用了Native层的函数,另外,这里普及一下这些层次的关系:

java层--->jni通信-->native层-->HAL层-->用户空间层-->kernel层-->驱动层-->硬件层.

接着往下看,根据映射关系,其调用了android_os_SystemProperties.cpp的SystemProperties_set()函数,如下:

static void SystemProperties_set(JNIEnv *env, jobject clazz,
                                      jstring keyJ, jstring valJ)
{
    ...
    err = property_set(key, val);
    ...
}

static const JNINativeMethod method_table[] = {
    ...
    { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) SystemProperties_set },
    ...
};

其调用了properties.cpp

int property_set(const char *key, const char *value) {
    return __system_property_set(key, value);
}

bionic/libc/bionic/system_properties.cpp

int __system_property_set(const char* key, const char* value) {
    ...
    if (g_propservice_protocol_version == kProtocolVersion1) {
        // 将关机属性的name,value,size 放入到msg中
        prop_msg msg;
        memset(&msg, 0, sizeof msg);
        msg.cmd = PROP_MSG_SETPROP;
        strlcpy(msg.name, key, sizeof msg.name);
        strlcpy(msg.value, value, sizeof msg.value);

        // 将msg发送到服务端,property的服务进程在init.rc中运行,触发关机属性值的设定调用dopwrctrl
        return send_prop_msg(&msg);
    } else {
        // Use proper protocol
        ...
        return 0;
    }
}

init.rc

# sys.powerctl被设置为任意值都会触发下面的动作
on property:sys.powerctl=*
   powerctl ${sys.powerctl}

system/core/init/reboot.cpp

bool HandlePowerctlMessage(const std::string& command) {
    ...
    if (cmd_params.size() > 3) {
        command_invalid = true;
    } else if (cmd_params[0] == "shutdown") {
        cmd = ANDROID_RB_POWEROFF;
        ...
    } else if (cmd_params[0] == "reboot") {
        cmd = ANDROID_RB_RESTART2;
        ...
    } else if (command == "thermal-shutdown") {  // no additional parameter allowed
        // run_fsck is false to avoid delay
        cmd = ANDROID_RB_THERMOFF;
    } else {
        command_invalid = true;
    }
	...

    // Queue built-in shutdown_done
    auto shutdown_handler = [cmd, command, reboot_target,
                             run_fsck](const std::vector&) {
        DoReboot(cmd, command, reboot_target, run_fsck);
        return 0;
    };
    ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
	...

    return true;
}

调用到了DoReboot(),

static void __attribute__((noreturn))
RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
    ...
    switch (cmd) {
        case ANDROID_RB_POWEROFF:  // 关机
            reboot(RB_POWER_OFF);
            break;

        case ANDROID_RB_RESTART2:
            syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                    LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
            break;

        case ANDROID_RB_THERMOFF:
            reboot(RB_POWER_OFF);
            break;
    }
    ...
}

void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget, bool runFsck) {
    ...
    RebootSystem(cmd, rebootTarget);
    ...
}

bionic/libc/bionic/reboot.cpp

int reboot(int mode) {
    return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);
}

bionic/libc/arch-arm64/syscalls/__reboot.S

ENTRY(__reboot)
    mov     x8, __NR_reboot
    svc     #0
    cmn     x0, #(MAX_ERRNO + 1)
    cneg    x0, x0, hi
    b.hi    __set_errno_internal

    ret
END(__reboot)
.hidden __reboot

从汇编看是执行__NR_reboot,定位这个入口比较复杂,可以参考:http://doc.okbase.net/jinlu7611/archive/226918.html

在Android 8.1定位到:kernel/kernel/reboot.c

void kernel_power_off(void)
{
    kernel_shutdown_prepare(SYSTEM_POWER_OFF);
    if (pm_power_off_prepare)
        pm_power_off_prepare();
    migrate_to_reboot_cpu();
    syscore_shutdown();
    pr_emerg("Power down\n");
    kmsg_dump(KMSG_DUMP_POWEROFF);
    machine_power_off();
}

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
		void __user *, arg)
{
    ...

    mutex_lock(&reboot_mutex);
    switch (cmd) {
        ...
    case LINUX_REBOOT_CMD_POWER_OFF:
        kernel_power_off();
        do_exit(0);
        break;
        ...
    }
    mutex_unlock(&reboot_mutex);
    return ret;
}

关机的后续流程,请自行网上找一下kernel关机流程作为参考.

你可能感兴趣的:(Android)