Loading core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -10479,6 +10479,7 @@ public final class Settings { * track_cpu_times_by_proc_state (boolean) * track_cpu_active_cluster_time (boolean) * read_binary_cpu_time (boolean) * proc_state_cpu_times_read_delay_ms (long) * </pre> * * <p> Loading core/java/com/android/internal/os/BatteryStatsImpl.java +42 −3 Original line number Diff line number Diff line Loading @@ -230,6 +230,13 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting protected final SparseIntArray mPendingUids = new SparseIntArray(); @GuardedBy("this") private long mNumCpuTimeReads; @GuardedBy("this") private long mNumBatchedCpuTimeReads; @GuardedBy("this") private long mCpuTimeReadsTrackingStartTime = SystemClock.uptimeMillis(); /** Container for Resource Power Manager stats. Updated by updateRpmStatsLocked. */ private final RpmStats mTmpRpmStats = new RpmStats(); /** The soonest the RPM stats can be updated after it was last updated. */ Loading Loading @@ -485,7 +492,8 @@ public class BatteryStatsImpl extends BatteryStats { Future<?> scheduleSync(String reason, int flags); Future<?> scheduleCpuSyncDueToRemovedUid(int uid); Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff); Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff, long delayMillis); Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff); Future<?> scheduleCpuSyncDueToSettingChange(); Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery, Loading Loading @@ -9694,7 +9702,11 @@ public class BatteryStatsImpl extends BatteryStats { if (mBsi.mPendingUids.size() == 0) { mBsi.mExternalSync.scheduleReadProcStateCpuTimes( mBsi.mOnBatteryTimeBase.isRunning(), mBsi.mOnBatteryScreenOffTimeBase.isRunning()); mBsi.mOnBatteryScreenOffTimeBase.isRunning(), mBsi.mConstants.PROC_STATE_CPU_TIMES_READ_DELAY_MS); mBsi.mNumCpuTimeReads++; } else { mBsi.mNumBatchedCpuTimeReads++; } if (mBsi.mPendingUids.indexOfKey(mUid) < 0 || ArrayUtils.contains(CRITICAL_PROC_STATES, mProcessState)) { Loading Loading @@ -13167,15 +13179,19 @@ public class BatteryStatsImpl extends BatteryStats { = "track_cpu_active_cluster_time"; public static final String KEY_READ_BINARY_CPU_TIME = "read_binary_cpu_time"; public static final String KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS = "proc_state_cpu_times_read_delay_ms"; private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false; private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000; public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; // Not used right now. public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME; public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); Loading Loading @@ -13215,7 +13231,9 @@ public class BatteryStatsImpl extends BatteryStats { KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME); READ_BINARY_CPU_TIME = mParser.getBoolean( KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME); updateProcStateCpuTimesReadDelayMs(PROC_STATE_CPU_TIMES_READ_DELAY_MS, mParser.getLong(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS, DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS)); } } Loading @@ -13224,6 +13242,19 @@ public class BatteryStatsImpl extends BatteryStats { if (isEnabled && !wasEnabled) { mKernelSingleUidTimeReader.markDataAsStale(true); mExternalSync.scheduleCpuSyncDueToSettingChange(); mNumCpuTimeReads = 0; mNumBatchedCpuTimeReads = 0; mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); } } private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) { PROC_STATE_CPU_TIMES_READ_DELAY_MS = newDelayMillis; if (oldDelayMillis != newDelayMillis) { mNumCpuTimeReads = 0; mNumBatchedCpuTimeReads = 0; mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); } } Loading @@ -13234,6 +13265,8 @@ public class BatteryStatsImpl extends BatteryStats { pw.println(TRACK_CPU_ACTIVE_CLUSTER_TIME); pw.print(KEY_READ_BINARY_CPU_TIME); pw.print("="); pw.println(READ_BINARY_CPU_TIME); pw.print(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print("="); pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS); } } Loading Loading @@ -14943,5 +14976,11 @@ public class BatteryStatsImpl extends BatteryStats { mCameraOnTimer.logState(pr, " "); } super.dumpLocked(context, pw, flags, reqUid, histStart); pw.print("Total cpu time reads: "); pw.println(mNumCpuTimeReads); pw.print("Batched cpu time reads: "); pw.println(mNumBatchedCpuTimeReads); pw.print("Batching Duration (min): "); pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTime) / (60 * 1000)); } } core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +38 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING; import static android.os.BatteryStats.Uid.UID_PROCESS_TYPES; import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS; import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_TRACK_CPU_TIMES_BY_PROC_STATE; import static junit.framework.Assert.assertNotNull; Loading Loading @@ -101,6 +102,11 @@ public class BstatsCpuTimesValidationTest { private static final int WORK_DURATION_MS = 2000; private static final String DESIRED_PROC_STATE_CPU_TIMES_DELAY = "0"; private static boolean sBatteryStatsConstsUpdated; private static String sOriginalBatteryStatsConsts; private static Context sContext; private static UiDevice sUiDevice; private static int sTestPkgUid; Loading @@ -117,13 +123,43 @@ public class BstatsCpuTimesValidationTest { PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0); checkCpuTimesAvailability(); if (sPerProcStateTimesAvailable && sCpuFreqTimesAvailable) { setDesiredReadyDelay(); } } @AfterClass public static void tearDownOnce() throws Exception { if (sBatteryStatsConstsUpdated) { Settings.Global.putString(sContext.getContentResolver(), Settings.Global.BATTERY_STATS_CONSTANTS, sOriginalBatteryStatsConsts); } batteryReset(); } private static void setDesiredReadyDelay() { sOriginalBatteryStatsConsts = Settings.Global.getString(sContext.getContentResolver(), Settings.Global.BATTERY_STATS_CONSTANTS); String newBatteryStatsConstants; final String newConstant = KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + "=" + DESIRED_PROC_STATE_CPU_TIMES_DELAY; if (sOriginalBatteryStatsConsts == null || "null".equals(sOriginalBatteryStatsConsts)) { // battery_stats_constants is initially empty, so just assign the desired value. newBatteryStatsConstants = newConstant; } else if (sOriginalBatteryStatsConsts.contains(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS)) { // battery_stats_constants contains delay duration, so replace it // with the desired value. newBatteryStatsConstants = sOriginalBatteryStatsConsts.replaceAll( KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + "=\\d+", newConstant); } else { // battery_stats_constants didn't contain any delay, so append the desired value. newBatteryStatsConstants = sOriginalBatteryStatsConsts + "," + newConstant; } Settings.Global.putString(sContext.getContentResolver(), Settings.Global.BATTERY_STATS_CONSTANTS, newBatteryStatsConstants); sBatteryStatsConstsUpdated = true; } // Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state // and /proc/uid/<uid>/time_in_state kernel nodes are available. private static void checkCpuTimesAvailability() throws Exception { Loading @@ -132,9 +168,9 @@ public class BstatsCpuTimesValidationTest { batteryOff(); final long[] totalCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID); sCpuFreqTimesAvailable = totalCpuTimes != null; final long[] fgSvcCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID, final long[] fgCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID, PROCESS_STATE_FOREGROUND); sPerProcStateTimesAvailable = fgSvcCpuTimes != null; sPerProcStateTimesAvailable = fgCpuTimes != null; } @Test Loading core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -160,8 +160,8 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { } @Override public Future<?> scheduleReadProcStateCpuTimes( boolean onBattery, boolean onBatteryScreenOff) { public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff, long delayMillis) { return null; } Loading services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +5 −3 Original line number Diff line number Diff line Loading @@ -139,7 +139,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } @Override public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff) { public Future<?> scheduleReadProcStateCpuTimes( boolean onBattery, boolean onBatteryScreenOff, long delayMillis) { synchronized (mStats) { if (!mStats.trackPerProcStateCpuTimes()) { return null; Loading @@ -147,9 +148,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } synchronized (BatteryExternalStatsWorker.this) { if (!mExecutorService.isShutdown()) { return mExecutorService.submit(PooledLambda.obtainRunnable( return mExecutorService.schedule(PooledLambda.obtainRunnable( BatteryStatsImpl::updateProcStateCpuTimes, mStats, onBattery, onBatteryScreenOff).recycleOnUse()); mStats, onBattery, onBatteryScreenOff).recycleOnUse(), delayMillis, TimeUnit.MILLISECONDS); } } return null; Loading Loading
core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -10479,6 +10479,7 @@ public final class Settings { * track_cpu_times_by_proc_state (boolean) * track_cpu_active_cluster_time (boolean) * read_binary_cpu_time (boolean) * proc_state_cpu_times_read_delay_ms (long) * </pre> * * <p> Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +42 −3 Original line number Diff line number Diff line Loading @@ -230,6 +230,13 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting protected final SparseIntArray mPendingUids = new SparseIntArray(); @GuardedBy("this") private long mNumCpuTimeReads; @GuardedBy("this") private long mNumBatchedCpuTimeReads; @GuardedBy("this") private long mCpuTimeReadsTrackingStartTime = SystemClock.uptimeMillis(); /** Container for Resource Power Manager stats. Updated by updateRpmStatsLocked. */ private final RpmStats mTmpRpmStats = new RpmStats(); /** The soonest the RPM stats can be updated after it was last updated. */ Loading Loading @@ -485,7 +492,8 @@ public class BatteryStatsImpl extends BatteryStats { Future<?> scheduleSync(String reason, int flags); Future<?> scheduleCpuSyncDueToRemovedUid(int uid); Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff); Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff, long delayMillis); Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff); Future<?> scheduleCpuSyncDueToSettingChange(); Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery, Loading Loading @@ -9694,7 +9702,11 @@ public class BatteryStatsImpl extends BatteryStats { if (mBsi.mPendingUids.size() == 0) { mBsi.mExternalSync.scheduleReadProcStateCpuTimes( mBsi.mOnBatteryTimeBase.isRunning(), mBsi.mOnBatteryScreenOffTimeBase.isRunning()); mBsi.mOnBatteryScreenOffTimeBase.isRunning(), mBsi.mConstants.PROC_STATE_CPU_TIMES_READ_DELAY_MS); mBsi.mNumCpuTimeReads++; } else { mBsi.mNumBatchedCpuTimeReads++; } if (mBsi.mPendingUids.indexOfKey(mUid) < 0 || ArrayUtils.contains(CRITICAL_PROC_STATES, mProcessState)) { Loading Loading @@ -13167,15 +13179,19 @@ public class BatteryStatsImpl extends BatteryStats { = "track_cpu_active_cluster_time"; public static final String KEY_READ_BINARY_CPU_TIME = "read_binary_cpu_time"; public static final String KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS = "proc_state_cpu_times_read_delay_ms"; private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false; private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000; public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; // Not used right now. public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME; public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); Loading Loading @@ -13215,7 +13231,9 @@ public class BatteryStatsImpl extends BatteryStats { KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME); READ_BINARY_CPU_TIME = mParser.getBoolean( KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME); updateProcStateCpuTimesReadDelayMs(PROC_STATE_CPU_TIMES_READ_DELAY_MS, mParser.getLong(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS, DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS)); } } Loading @@ -13224,6 +13242,19 @@ public class BatteryStatsImpl extends BatteryStats { if (isEnabled && !wasEnabled) { mKernelSingleUidTimeReader.markDataAsStale(true); mExternalSync.scheduleCpuSyncDueToSettingChange(); mNumCpuTimeReads = 0; mNumBatchedCpuTimeReads = 0; mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); } } private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) { PROC_STATE_CPU_TIMES_READ_DELAY_MS = newDelayMillis; if (oldDelayMillis != newDelayMillis) { mNumCpuTimeReads = 0; mNumBatchedCpuTimeReads = 0; mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis(); } } Loading @@ -13234,6 +13265,8 @@ public class BatteryStatsImpl extends BatteryStats { pw.println(TRACK_CPU_ACTIVE_CLUSTER_TIME); pw.print(KEY_READ_BINARY_CPU_TIME); pw.print("="); pw.println(READ_BINARY_CPU_TIME); pw.print(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print("="); pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS); } } Loading Loading @@ -14943,5 +14976,11 @@ public class BatteryStatsImpl extends BatteryStats { mCameraOnTimer.logState(pr, " "); } super.dumpLocked(context, pw, flags, reqUid, histStart); pw.print("Total cpu time reads: "); pw.println(mNumCpuTimeReads); pw.print("Batched cpu time reads: "); pw.println(mNumBatchedCpuTimeReads); pw.print("Batching Duration (min): "); pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTime) / (60 * 1000)); } }
core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +38 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING; import static android.os.BatteryStats.Uid.UID_PROCESS_TYPES; import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS; import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_TRACK_CPU_TIMES_BY_PROC_STATE; import static junit.framework.Assert.assertNotNull; Loading Loading @@ -101,6 +102,11 @@ public class BstatsCpuTimesValidationTest { private static final int WORK_DURATION_MS = 2000; private static final String DESIRED_PROC_STATE_CPU_TIMES_DELAY = "0"; private static boolean sBatteryStatsConstsUpdated; private static String sOriginalBatteryStatsConsts; private static Context sContext; private static UiDevice sUiDevice; private static int sTestPkgUid; Loading @@ -117,13 +123,43 @@ public class BstatsCpuTimesValidationTest { PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0); checkCpuTimesAvailability(); if (sPerProcStateTimesAvailable && sCpuFreqTimesAvailable) { setDesiredReadyDelay(); } } @AfterClass public static void tearDownOnce() throws Exception { if (sBatteryStatsConstsUpdated) { Settings.Global.putString(sContext.getContentResolver(), Settings.Global.BATTERY_STATS_CONSTANTS, sOriginalBatteryStatsConsts); } batteryReset(); } private static void setDesiredReadyDelay() { sOriginalBatteryStatsConsts = Settings.Global.getString(sContext.getContentResolver(), Settings.Global.BATTERY_STATS_CONSTANTS); String newBatteryStatsConstants; final String newConstant = KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + "=" + DESIRED_PROC_STATE_CPU_TIMES_DELAY; if (sOriginalBatteryStatsConsts == null || "null".equals(sOriginalBatteryStatsConsts)) { // battery_stats_constants is initially empty, so just assign the desired value. newBatteryStatsConstants = newConstant; } else if (sOriginalBatteryStatsConsts.contains(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS)) { // battery_stats_constants contains delay duration, so replace it // with the desired value. newBatteryStatsConstants = sOriginalBatteryStatsConsts.replaceAll( KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + "=\\d+", newConstant); } else { // battery_stats_constants didn't contain any delay, so append the desired value. newBatteryStatsConstants = sOriginalBatteryStatsConsts + "," + newConstant; } Settings.Global.putString(sContext.getContentResolver(), Settings.Global.BATTERY_STATS_CONSTANTS, newBatteryStatsConstants); sBatteryStatsConstsUpdated = true; } // Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state // and /proc/uid/<uid>/time_in_state kernel nodes are available. private static void checkCpuTimesAvailability() throws Exception { Loading @@ -132,9 +168,9 @@ public class BstatsCpuTimesValidationTest { batteryOff(); final long[] totalCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID); sCpuFreqTimesAvailable = totalCpuTimes != null; final long[] fgSvcCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID, final long[] fgCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID, PROCESS_STATE_FOREGROUND); sPerProcStateTimesAvailable = fgSvcCpuTimes != null; sPerProcStateTimesAvailable = fgCpuTimes != null; } @Test Loading
core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -160,8 +160,8 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { } @Override public Future<?> scheduleReadProcStateCpuTimes( boolean onBattery, boolean onBatteryScreenOff) { public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff, long delayMillis) { return null; } Loading
services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +5 −3 Original line number Diff line number Diff line Loading @@ -139,7 +139,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } @Override public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff) { public Future<?> scheduleReadProcStateCpuTimes( boolean onBattery, boolean onBatteryScreenOff, long delayMillis) { synchronized (mStats) { if (!mStats.trackPerProcStateCpuTimes()) { return null; Loading @@ -147,9 +148,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } synchronized (BatteryExternalStatsWorker.this) { if (!mExecutorService.isShutdown()) { return mExecutorService.submit(PooledLambda.obtainRunnable( return mExecutorService.schedule(PooledLambda.obtainRunnable( BatteryStatsImpl::updateProcStateCpuTimes, mStats, onBattery, onBatteryScreenOff).recycleOnUse()); mStats, onBattery, onBatteryScreenOff).recycleOnUse(), delayMillis, TimeUnit.MILLISECONDS); } } return null; Loading