android6.0 PowerManagerService dream分析

上一篇博客分析了PowerManagerService的各种状态,最后分析到dream相关,讲的不详细。这里我们再分析下。


一、Dream关闭

首先我们结合打印的log,看看handleSandman函数,log直接加在下面的函数中。当然我们现在说的情况是mWakefulness是dozing状态。

    private void handleSandman() { // runs on handler thread
        // Handle preconditions.
        final boolean startDreaming;
        final int wakefulness;
        synchronized (mLock) {
            mSandmanScheduled = false;
            wakefulness = mWakefulness;
            if (mSandmanSummoned && mDisplayReady) {
                startDreaming = canDreamLocked() || canDozeLocked();
                Slog.d(TAG, "handleSandman startDreaming:" + startDreaming);//这个变量log打印为true
                mSandmanSummoned = false;
            } else {
                startDreaming = false;
            }
        }

        // Start dreaming if needed.
        // We only control the dream on the handler thread, so we don't need to worry about
        // concurrent attempts to start or stop the dream.
        final boolean isDreaming;
        if (mDreamManager != null) {
            // Restart the dream whenever the sandman is summoned.
            if (startDreaming) {
                mDreamManager.stopDream(false /*immediate*/);
                mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);//调用startStream
            }
            
            isDreaming = mDreamManager.isDreaming();
            Slog.d(TAG, "handleSandman isDreaming:" + isDreaming);//返回false
        } else {
        Slog.d(TAG, "handleSandman mDreamManager null");
            isDreaming = false;
        }

        // Update dream state.
        synchronized (mLock) {
            // Remember the initial battery level when the dream started.
            if (startDreaming && isDreaming) {
                mBatteryLevelWhenDreamStarted = mBatteryLevel;
                if (wakefulness == WAKEFULNESS_DOZING) {
                    Slog.i(TAG, "Dozing...");
                } else {
                    Slog.i(TAG, "Dreaming...");
                }
            }

            // If preconditions changed, wait for the next iteration to determine
            // whether the dream should continue (or be restarted).
            if (mSandmanSummoned || mWakefulness != wakefulness) {
                return; // wait for next cycle
            }

            // Determine whether the dream should continue.
            if (wakefulness == WAKEFULNESS_DREAMING) {
                Slog.d(TAG, "handleSandman WAKEFULNESS_DREAMING");
                if (isDreaming && canDreamLocked()) {
                    if (mDreamsBatteryLevelDrainCutoffConfig >= 0
                            && mBatteryLevel < mBatteryLevelWhenDreamStarted
                                    - mDreamsBatteryLevelDrainCutoffConfig
                            && !isBeingKeptAwakeLocked()) {
                        // If the user activity timeout expired and the battery appears
                        // to be draining faster than it is charging then stop dreaming
                        // and go to sleep.
                        Slog.i(TAG, "Stopping dream because the battery appears to "
                                + "be draining faster than it is charging.  "
                                + "Battery level when dream started: "
                                + mBatteryLevelWhenDreamStarted + "%.  "
                                + "Battery level now: " + mBatteryLevel + "%.");
                    } else {
                        return; // continue dreaming
                    }
                }

                // Dream has ended or will be stopped.  Update the power state.
                if (isItBedTimeYetLocked()) {
                    goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
                            PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
                    updatePowerStateLocked();
                } else {
                    wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM",
                            Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID);
                    updatePowerStateLocked();
                }
            } else if (wakefulness == WAKEFULNESS_DOZING) {
                if (isDreaming) {//为false
                    Slog.d(TAG, "handleSandman isDreaming = true");
                    return; // continue dozing
                }

                // Doze has ended or will be stopped.  Update the power state.
                Slog.d(TAG, "handleSandman mwakefulness:" + mWakefulness);//dozing状态
                reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
                Slog.d(TAG, "handleSandman mwakefulness:" + mWakefulness);//sleep状态了
                updatePowerStateLocked();
            }
        }

        Slog.d(TAG, "handleSandman wakefulness:" + mWakefulness);

        // Stop dream.
        if (isDreaming) {
            mDreamManager.stopDream(false /*immediate*/);
        }
    }

看了上面的注释很明显,我们是调用了startdream,但是isDreaming返回是false。明显是没有支持dream。因此power也就直接进入的sleep状态。


那我们再来看看这个dream,下面是DreamManagerService的LocalService

    private final class LocalService extends DreamManagerInternal {
        @Override
        public void startDream(boolean doze) {
            startDreamInternal(doze);
        }

        @Override
        public void stopDream(boolean immediate) {
            stopDreamInternal(immediate);
        }

        @Override
        public boolean isDreaming() {
            return isDreamingInternal();
        }
    }
我们来看startDreamInternal函数

    private void startDreamInternal(boolean doze) {
        Slog.d(TAG, "startDreamInternal");
        final int userId = ActivityManager.getCurrentUser();
        final ComponentName dream = chooseDreamForUser(doze, userId);
        
        if (dream != null) {
            synchronized (mLock) {
                startDreamLocked(dream, false /*isTest*/, doze, userId);
            }
        } else {
            Slog.d(TAG, "dream is null");// 加的打印log
        }
    }

我们在这个函数中加了log,发现dream为null,所以压根美欧调用startDreamLocked函数。

    private ComponentName chooseDreamForUser(boolean doze, int userId) {
        if (doze) {
            ComponentName dozeComponent = getDozeComponent(userId);
            return validateDream(dozeComponent) ? dozeComponent : null;
        }
        ComponentName[] dreams = getDreamComponentsForUser(userId);
        return dreams != null && dreams.length != 0 ? dreams[0] : null;
    }

chooseDreamForUser返回为null,是因为getDozeComponent返回为null。

我们再看getDozeComponent函数:

    private ComponentName getDozeComponent(int userId) {
        String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
        if (TextUtils.isEmpty(name)) {
            name = mContext.getResources().getString(
                    com.android.internal.R.string.config_dozeComponent);
        }
        boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                Settings.Secure.DOZE_ENABLED, 1, userId) != 0;
        return TextUtils.isEmpty(name) || !enabled ? null : ComponentName.unflattenFromString(name);
    }

上面这个变量name是null,导致返回null。还是系统没有支持dream的原因。


二、DreamService

虽然我们系统不支持,我们也看下代码,先看下startDreamLocked函数

    private void startDreamLocked(final ComponentName name,
            final boolean isTest, final boolean canDoze, final int userId) {
        if (Objects.equal(mCurrentDreamName, name)
                && mCurrentDreamIsTest == isTest
                && mCurrentDreamCanDoze == canDoze
                && mCurrentDreamUserId == userId) {
            return;
        }

        stopDreamLocked(true /*immediate*/);

        Slog.i(TAG, "Entering dreamland.");

        final Binder newToken = new Binder();
        mCurrentDreamToken = newToken;
        mCurrentDreamName = name;
        mCurrentDreamIsTest = isTest;
        mCurrentDreamCanDoze = canDoze;
        mCurrentDreamUserId = userId;

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mController.startDream(newToken, name, isTest, canDoze, userId);
            }
        });
    }

最终是调用了mController.startDream函数,再来看DreamController类的startDream函数

    public void startDream(Binder token, ComponentName name,
            boolean isTest, boolean canDoze, int userId) {
        stopDream(true /*immediate*/);

        Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
        try {
            // Close the notification shade. Don't need to send to all, but better to be explicit.
            mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);

            mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);

            mDreamStartTime = SystemClock.elapsedRealtime();
            MetricsLogger.visible(mContext,
                    mCurrentDream.mCanDoze ? MetricsLogger.DOZING : MetricsLogger.DREAMING);

            try {
                mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
            } catch (RemoteException ex) {
                Slog.e(TAG, "Unable to add window token for dream.", ex);
                stopDream(true /*immediate*/);
                return;
            }

            Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
            intent.setComponent(name);
            intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            try {
                if (!mContext.bindServiceAsUser(intent, mCurrentDream,//开启Service
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                        new UserHandle(userId))) {
                    Slog.e(TAG, "Unable to bind dream service: " + intent);
                    stopDream(true /*immediate*/);
                    return;
                }
            } catch (SecurityException ex) {
                Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
                stopDream(true /*immediate*/);
                return;
            }

            mCurrentDream.mBound = true;
            mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);//出错处理
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        }
    }

然后bindService了DreamService,我们来看这个Service的onBind接口。

    public final IBinder onBind(Intent intent) {
        if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
        return new DreamServiceWrapper();
    }

DreamServiceWrapper 如下,就是binder接口。用来binder通信

    private final class DreamServiceWrapper extends IDreamService.Stub {
        @Override
        public void attach(final IBinder windowToken, final boolean canDoze) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    DreamService.this.attach(windowToken, canDoze);
                }
            });
        }

        @Override
        public void detach() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    DreamService.this.detach();
                }
            });
        }

        @Override
        public void wakeUp() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    DreamService.this.wakeUp(true /*fromSystem*/);
                }
            });
        }
    }

我们再来看DreamRecord ,就是在DreamController调用bindService时候作为ServiceConnection

    private final class DreamRecord implements DeathRecipient, ServiceConnection {
        ......
        // May be called on any thread.
        @Override
        public void onServiceConnected(ComponentName name, final IBinder service) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mConnected = true;
                    if (mCurrentDream == DreamRecord.this && mService == null) {
                        attach(IDreamService.Stub.asInterface(service));
                    }
                }
            });
        }

我们再来看attach这个函数,远程调用了Service的attach函数,把Service的binder保存在了mCurrentDream的mService中,这样就能和DreamService通信了

    private void attach(IDreamService service) {
        try {
            service.asBinder().linkToDeath(mCurrentDream, 0);
            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
        } catch (RemoteException ex) {
            Slog.e(TAG, "The dream service died unexpectedly.", ex);
            stopDream(true /*immediate*/);
            return;
        }

        mCurrentDream.mService = service;

        if (!mCurrentDream.mIsTest) {
            mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL);
            mCurrentDream.mSentStartBroadcast = true;
        }
    }


三、总结

这篇博客主要讲了PowerManagerService中没有支持dream,但是我们也简单介绍了DreamService的源码。




你可能感兴趣的:(android6.0 PowerManagerService dream分析)