Loading core/java/android/hardware/display/DisplayManagerInternal.java +5 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,11 @@ public abstract class DisplayManagerInternal { * */ public abstract boolean isUidPresentOnDisplay(int uid, int displayId); /** * Persist brightness slider events. */ public abstract void persistBrightnessSliderEvents(); /** * Describes the requested power state of the display. * Loading core/res/AndroidManifest.xml +5 −1 Original line number Diff line number Diff line Loading @@ -3958,6 +3958,10 @@ <service android:name="com.android.server.net.watchlist.ReportWatchlistJobService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.display.BrightnessIdleJob" android:permission="android.permission.BIND_JOB_SERVICE" > </service> </application> </manifest> services/core/java/com/android/server/display/BrightnessIdleJob.java 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.hardware.display.DisplayManagerInternal; import android.util.Slog; import com.android.server.LocalServices; import java.util.concurrent.TimeUnit; /** * JobService used to persists brightness slider events when the device * is idle and charging. */ public class BrightnessIdleJob extends JobService { // Must be unique within the system server uid. private static final int JOB_ID = 3923512; public static void scheduleJob(Context context) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); JobInfo pending = jobScheduler.getPendingJob(JOB_ID); JobInfo jobInfo = new JobInfo.Builder(JOB_ID, new ComponentName(context, BrightnessIdleJob.class)) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .setPeriodic(TimeUnit.HOURS.toMillis(24)).build(); if (pending != null && !pending.equals(jobInfo)) { jobScheduler.cancel(JOB_ID); pending = null; } if (pending == null) { jobScheduler.schedule(jobInfo); } } public static void cancelJob(Context context) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); jobScheduler.cancel(JOB_ID); } @Override public boolean onStartJob(JobParameters params) { if (BrightnessTracker.DEBUG) { Slog.d(BrightnessTracker.TAG, "Scheduled write of brightness events"); } DisplayManagerInternal dmi = LocalServices.getService(DisplayManagerInternal.class); dmi.persistBrightnessSliderEvents(); return false; } @Override public boolean onStopJob(JobParameters params) { return false; } } No newline at end of file services/core/java/com/android/server/display/BrightnessTracker.java +45 −5 Original line number Diff line number Diff line Loading @@ -61,12 +61,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.concurrent.TimeUnit; /** Loading @@ -75,8 +75,8 @@ import java.util.concurrent.TimeUnit; */ public class BrightnessTracker { private static final String TAG = "BrightnessTracker"; private static final boolean DEBUG = false; static final String TAG = "BrightnessTracker"; static final boolean DEBUG = false; private static final String EVENTS_FILE = "brightness_events.xml"; private static final int MAX_EVENTS = 100; Loading @@ -103,6 +103,8 @@ public class BrightnessTracker { @GuardedBy("mEventsLock") private RingBuffer<BrightnessChangeEvent> mEvents = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS); @GuardedBy("mEventsLock") private boolean mEventsDirty; private final Runnable mEventsWriter = () -> writeEvents(); private volatile boolean mWriteEventsScheduled; Loading Loading @@ -170,6 +172,8 @@ public class BrightnessTracker { intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); mBroadcastReceiver = new Receiver(); mInjector.registerReceiver(mContext, mBroadcastReceiver, intentFilter); mInjector.scheduleIdleJob(mContext); } /** Stop listening for events */ Loading @@ -181,6 +185,7 @@ public class BrightnessTracker { mInjector.unregisterSensorListener(mContext, mSensorListener); mInjector.unregisterReceiver(mContext, mBroadcastReceiver); mInjector.unregisterBrightnessObserver(mContext, mSettingsObserver); mInjector.cancelIdleJob(mContext); } /** Loading Loading @@ -211,6 +216,10 @@ public class BrightnessTracker { brightness, userId); } public void persistEvents() { scheduleWriteEvents(); } private void handleBrightnessChanged() { if (DEBUG) { Slog.d(TAG, "Brightness change"); Loading Loading @@ -278,6 +287,7 @@ public class BrightnessTracker { Slog.d(TAG, "Event " + event.brightness + " " + event.packageName); } synchronized (mEventsLock) { mEventsDirty = true; mEvents.append(event); } } Loading @@ -291,8 +301,12 @@ public class BrightnessTracker { private void writeEvents() { mWriteEventsScheduled = false; // TODO kick off write on handler thread e.g. every 24 hours. synchronized (mEventsLock) { if (!mEventsDirty) { // Nothing to write return; } final AtomicFile writeTo = mInjector.getFile(); if (writeTo == null) { return; Loading @@ -301,12 +315,14 @@ public class BrightnessTracker { if (writeTo.exists()) { writeTo.delete(); } mEventsDirty = false; } else { FileOutputStream output = null; try { output = writeTo.startWrite(); writeEventsLocked(output); writeTo.finishWrite(output); mEventsDirty = false; } catch (IOException e) { writeTo.failWrite(output); Slog.e(TAG, "Failed to write change mEvents.", e); Loading @@ -317,6 +333,8 @@ public class BrightnessTracker { private void readEvents() { synchronized (mEventsLock) { // Read might prune events so mark as dirty. mEventsDirty = true; mEvents.clear(); final AtomicFile readFrom = mInjector.getFile(); if (readFrom != null && readFrom.exists()) { Loading Loading @@ -344,13 +362,16 @@ public class BrightnessTracker { out.startTag(null, TAG_EVENTS); BrightnessChangeEvent[] toWrite = mEvents.toArray(); // Clear events, code below will add back the ones that are still within the time window. mEvents.clear(); if (DEBUG) { Slog.d(TAG, "Writing events " + toWrite.length); } final long timeCutOff = System.currentTimeMillis() - MAX_EVENT_AGE; final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE; for (int i = 0; i < toWrite.length; ++i) { int userSerialNo = mInjector.getUserSerialNumber(mUserManager, toWrite[i].userId); if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) { mEvents.append(toWrite[i]); out.startTag(null, TAG_EVENT); out.attribute(null, ATTR_BRIGHTNESS, Integer.toString(toWrite[i].brightness)); out.attribute(null, ATTR_TIMESTAMP, Long.toString(toWrite[i].timeStamp)); Loading Loading @@ -465,6 +486,17 @@ public class BrightnessTracker { } } public void dump(PrintWriter pw) { synchronized (mEventsLock) { pw.println("BrightnessTracker state:"); pw.println(" mEvents.size=" + mEvents.size()); pw.println(" mEventsDirty=" + mEventsDirty); } synchronized (mDataCollectionLock) { pw.println(" mLastSensorReadings.size=" + mLastSensorReadings.size()); } } // Not allowed to keep the SensorEvent so used to copy the data we care about. private static class LightData { public float lux; Loading Loading @@ -635,5 +667,13 @@ public class BrightnessTracker { public ActivityManager.StackInfo getFocusedStack() throws RemoteException { return ActivityManager.getService().getFocusedStackInfo(); } public void scheduleIdleJob(Context context) { BrightnessIdleJob.scheduleJob(context); } public void cancelIdleJob(Context context) { BrightnessIdleJob.cancelJob(context); } } } services/core/java/com/android/server/display/DisplayManagerService.java +8 −0 Original line number Diff line number Diff line Loading @@ -1285,6 +1285,9 @@ public final class DisplayManagerService extends SystemService { pw.println(); mPersistentDataStore.dump(pw); pw.println(); mBrightnessTracker.dump(pw); } } Loading Loading @@ -1921,5 +1924,10 @@ public final class DisplayManagerService extends SystemService { public boolean isUidPresentOnDisplay(int uid, int displayId) { return isUidPresentOnDisplayInternal(uid, displayId); } @Override public void persistBrightnessSliderEvents() { mBrightnessTracker.persistEvents(); } } } Loading
core/java/android/hardware/display/DisplayManagerInternal.java +5 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,11 @@ public abstract class DisplayManagerInternal { * */ public abstract boolean isUidPresentOnDisplay(int uid, int displayId); /** * Persist brightness slider events. */ public abstract void persistBrightnessSliderEvents(); /** * Describes the requested power state of the display. * Loading
core/res/AndroidManifest.xml +5 −1 Original line number Diff line number Diff line Loading @@ -3958,6 +3958,10 @@ <service android:name="com.android.server.net.watchlist.ReportWatchlistJobService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.display.BrightnessIdleJob" android:permission="android.permission.BIND_JOB_SERVICE" > </service> </application> </manifest>
services/core/java/com/android/server/display/BrightnessIdleJob.java 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.hardware.display.DisplayManagerInternal; import android.util.Slog; import com.android.server.LocalServices; import java.util.concurrent.TimeUnit; /** * JobService used to persists brightness slider events when the device * is idle and charging. */ public class BrightnessIdleJob extends JobService { // Must be unique within the system server uid. private static final int JOB_ID = 3923512; public static void scheduleJob(Context context) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); JobInfo pending = jobScheduler.getPendingJob(JOB_ID); JobInfo jobInfo = new JobInfo.Builder(JOB_ID, new ComponentName(context, BrightnessIdleJob.class)) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .setPeriodic(TimeUnit.HOURS.toMillis(24)).build(); if (pending != null && !pending.equals(jobInfo)) { jobScheduler.cancel(JOB_ID); pending = null; } if (pending == null) { jobScheduler.schedule(jobInfo); } } public static void cancelJob(Context context) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); jobScheduler.cancel(JOB_ID); } @Override public boolean onStartJob(JobParameters params) { if (BrightnessTracker.DEBUG) { Slog.d(BrightnessTracker.TAG, "Scheduled write of brightness events"); } DisplayManagerInternal dmi = LocalServices.getService(DisplayManagerInternal.class); dmi.persistBrightnessSliderEvents(); return false; } @Override public boolean onStopJob(JobParameters params) { return false; } } No newline at end of file
services/core/java/com/android/server/display/BrightnessTracker.java +45 −5 Original line number Diff line number Diff line Loading @@ -61,12 +61,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.concurrent.TimeUnit; /** Loading @@ -75,8 +75,8 @@ import java.util.concurrent.TimeUnit; */ public class BrightnessTracker { private static final String TAG = "BrightnessTracker"; private static final boolean DEBUG = false; static final String TAG = "BrightnessTracker"; static final boolean DEBUG = false; private static final String EVENTS_FILE = "brightness_events.xml"; private static final int MAX_EVENTS = 100; Loading @@ -103,6 +103,8 @@ public class BrightnessTracker { @GuardedBy("mEventsLock") private RingBuffer<BrightnessChangeEvent> mEvents = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS); @GuardedBy("mEventsLock") private boolean mEventsDirty; private final Runnable mEventsWriter = () -> writeEvents(); private volatile boolean mWriteEventsScheduled; Loading Loading @@ -170,6 +172,8 @@ public class BrightnessTracker { intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); mBroadcastReceiver = new Receiver(); mInjector.registerReceiver(mContext, mBroadcastReceiver, intentFilter); mInjector.scheduleIdleJob(mContext); } /** Stop listening for events */ Loading @@ -181,6 +185,7 @@ public class BrightnessTracker { mInjector.unregisterSensorListener(mContext, mSensorListener); mInjector.unregisterReceiver(mContext, mBroadcastReceiver); mInjector.unregisterBrightnessObserver(mContext, mSettingsObserver); mInjector.cancelIdleJob(mContext); } /** Loading Loading @@ -211,6 +216,10 @@ public class BrightnessTracker { brightness, userId); } public void persistEvents() { scheduleWriteEvents(); } private void handleBrightnessChanged() { if (DEBUG) { Slog.d(TAG, "Brightness change"); Loading Loading @@ -278,6 +287,7 @@ public class BrightnessTracker { Slog.d(TAG, "Event " + event.brightness + " " + event.packageName); } synchronized (mEventsLock) { mEventsDirty = true; mEvents.append(event); } } Loading @@ -291,8 +301,12 @@ public class BrightnessTracker { private void writeEvents() { mWriteEventsScheduled = false; // TODO kick off write on handler thread e.g. every 24 hours. synchronized (mEventsLock) { if (!mEventsDirty) { // Nothing to write return; } final AtomicFile writeTo = mInjector.getFile(); if (writeTo == null) { return; Loading @@ -301,12 +315,14 @@ public class BrightnessTracker { if (writeTo.exists()) { writeTo.delete(); } mEventsDirty = false; } else { FileOutputStream output = null; try { output = writeTo.startWrite(); writeEventsLocked(output); writeTo.finishWrite(output); mEventsDirty = false; } catch (IOException e) { writeTo.failWrite(output); Slog.e(TAG, "Failed to write change mEvents.", e); Loading @@ -317,6 +333,8 @@ public class BrightnessTracker { private void readEvents() { synchronized (mEventsLock) { // Read might prune events so mark as dirty. mEventsDirty = true; mEvents.clear(); final AtomicFile readFrom = mInjector.getFile(); if (readFrom != null && readFrom.exists()) { Loading Loading @@ -344,13 +362,16 @@ public class BrightnessTracker { out.startTag(null, TAG_EVENTS); BrightnessChangeEvent[] toWrite = mEvents.toArray(); // Clear events, code below will add back the ones that are still within the time window. mEvents.clear(); if (DEBUG) { Slog.d(TAG, "Writing events " + toWrite.length); } final long timeCutOff = System.currentTimeMillis() - MAX_EVENT_AGE; final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE; for (int i = 0; i < toWrite.length; ++i) { int userSerialNo = mInjector.getUserSerialNumber(mUserManager, toWrite[i].userId); if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) { mEvents.append(toWrite[i]); out.startTag(null, TAG_EVENT); out.attribute(null, ATTR_BRIGHTNESS, Integer.toString(toWrite[i].brightness)); out.attribute(null, ATTR_TIMESTAMP, Long.toString(toWrite[i].timeStamp)); Loading Loading @@ -465,6 +486,17 @@ public class BrightnessTracker { } } public void dump(PrintWriter pw) { synchronized (mEventsLock) { pw.println("BrightnessTracker state:"); pw.println(" mEvents.size=" + mEvents.size()); pw.println(" mEventsDirty=" + mEventsDirty); } synchronized (mDataCollectionLock) { pw.println(" mLastSensorReadings.size=" + mLastSensorReadings.size()); } } // Not allowed to keep the SensorEvent so used to copy the data we care about. private static class LightData { public float lux; Loading Loading @@ -635,5 +667,13 @@ public class BrightnessTracker { public ActivityManager.StackInfo getFocusedStack() throws RemoteException { return ActivityManager.getService().getFocusedStackInfo(); } public void scheduleIdleJob(Context context) { BrightnessIdleJob.scheduleJob(context); } public void cancelIdleJob(Context context) { BrightnessIdleJob.cancelJob(context); } } }
services/core/java/com/android/server/display/DisplayManagerService.java +8 −0 Original line number Diff line number Diff line Loading @@ -1285,6 +1285,9 @@ public final class DisplayManagerService extends SystemService { pw.println(); mPersistentDataStore.dump(pw); pw.println(); mBrightnessTracker.dump(pw); } } Loading Loading @@ -1921,5 +1924,10 @@ public final class DisplayManagerService extends SystemService { public boolean isUidPresentOnDisplay(int uid, int displayId) { return isUidPresentOnDisplayInternal(uid, displayId); } @Override public void persistBrightnessSliderEvents() { mBrightnessTracker.persistEvents(); } } }