• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.display;
18 
19 import android.annotation.IntDef;
20 import android.annotation.Nullable;
21 import android.hardware.Sensor;
22 import android.hardware.SensorEvent;
23 import android.hardware.SensorEventListener;
24 import android.hardware.SensorManager;
25 import android.hardware.display.DisplayManagerInternal;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.os.SystemClock;
30 import android.util.Slog;
31 import android.util.TimeUtils;
32 import android.view.Display;
33 
34 import com.android.internal.annotations.GuardedBy;
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.server.display.utils.SensorUtils;
37 
38 import java.io.PrintWriter;
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 
42 /**
43  * Maintains the proximity state of the display.
44  * Internally listens for proximity updates and schedules a power state update when the proximity
45  * state changes.
46  */
47 public final class DisplayPowerProximityStateController {
48     @VisibleForTesting
49     static final int PROXIMITY_UNKNOWN = -1;
50     private static final int PROXIMITY_NEGATIVE = 0;
51     @VisibleForTesting
52     static final int PROXIMITY_POSITIVE = 1;
53 
54     @IntDef(prefix = { "PROXIMITY_" }, value = {
55             PROXIMITY_UNKNOWN,
56             PROXIMITY_NEGATIVE,
57             PROXIMITY_POSITIVE
58     })
59     @Retention(RetentionPolicy.SOURCE)
60     @interface ProximityState {}
61 
62     @VisibleForTesting
63     static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 1;
64     @VisibleForTesting
65     static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
66 
67     private static final int MSG_IGNORE_PROXIMITY = 2;
68 
69     private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
70     // Proximity sensor debounce delay in milliseconds for positive transitions.
71 
72     // Proximity sensor debounce delay in milliseconds for negative transitions.
73     private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
74     // Trigger proximity if distance is less than 5 cm.
75     private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
76 
77     private final String mTag;
78     // A lock to handle the deadlock and race conditions.
79     private final Object mLock = new Object();
80     // The manager which lets us access the device's ProximitySensor
81     private final SensorManager mSensorManager;
82     // An entity which manages the wakelocks.
83     private final WakelockController mWakelockController;
84     // A handler to process all the events on this thread in a synchronous manner
85     private final DisplayPowerProximityStateHandler mHandler;
86     // A runnable to execute the utility to update the power state.
87     private final Runnable mNudgeUpdatePowerState;
88     private final Clock mClock;
89     // A listener which listen's to the events emitted by the proximity sensor.
90     private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
91         @Override
92         public void onSensorChanged(SensorEvent event) {
93             if (mProximitySensorEnabled) {
94                 final long time = mClock.uptimeMillis();
95                 final float distance = event.values[0];
96                 boolean positive = distance >= 0.0f && distance < mProximityThreshold;
97                 handleProximitySensorEvent(time, positive);
98             }
99         }
100 
101         @Override
102         public void onAccuracyChanged(Sensor sensor, int accuracy) {
103             // Not used.
104         }
105     };
106 
107     // The proximity sensor, or null if not available or needed.
108     private Sensor mProximitySensor;
109 
110     // The configurations for the associated display
111     private DisplayDeviceConfig mDisplayDeviceConfig;
112 
113     // True if a request has been made to wait for the proximity sensor to go negative.
114     @GuardedBy("mLock")
115     private boolean mPendingWaitForNegativeProximityLocked;
116 
117     // True if the device should wait for negative proximity sensor before
118     // waking up the screen.  This is set to false as soon as a negative
119     // proximity sensor measurement is observed or when the device is forced to
120     // go to sleep by the user.  While true, the screen remains off.
121     private boolean mWaitingForNegativeProximity;
122 
123     // True if the device should not take into account the proximity sensor
124     // until either the proximity sensor state changes, or there is no longer a
125     // request to listen to proximity sensor.
126     private boolean mIgnoreProximityUntilChanged;
127 
128     // Set to true if the proximity sensor listener has been registered
129     // with the sensor manager.
130     private boolean mProximitySensorEnabled;
131 
132     // -1 if fully debounced. Else, represents the time in ms when the debounce suspend blocker will
133     // be removed. Applies for both positive and negative proximity flips.
134     private long mPendingProximityDebounceTime = -1;
135 
136     // True if the screen was turned off because of the proximity sensor.
137     // When the screen turns on again, we report user activity to the power manager.
138     private boolean mScreenOffBecauseOfProximity;
139 
140     // The raw non-debounced proximity sensor state.
141     private @ProximityState int mPendingProximity = PROXIMITY_UNKNOWN;
142 
143     // The debounced proximity sensor state.
144     private @ProximityState int mProximity = PROXIMITY_UNKNOWN;
145 
146     // The actual proximity sensor threshold value.
147     private float mProximityThreshold;
148 
149     // A flag representing if the ramp is to be skipped when the proximity changes from positive
150     // to negative
151     private boolean mSkipRampBecauseOfProximityChangeToNegative = false;
152 
153     // The DisplayId of the associated Logical Display.
154     private final int mDisplayId;
155 
156     /**
157      * Create a new instance of DisplayPowerProximityStateController.
158      *
159      * @param wakeLockController    WakelockController used to acquire/release wakelocks
160      * @param displayDeviceConfig   DisplayDeviceConfig instance from which the configs(Proximity
161      *                              Sensor) are to be loaded
162      * @param looper                A looper onto which the handler is to be associated.
163      * @param nudgeUpdatePowerState A runnable to execute the utility to update the power state
164      * @param displayId             The DisplayId of the associated Logical Display.
165      * @param sensorManager         The manager which lets us access the display's ProximitySensor
166      */
DisplayPowerProximityStateController(WakelockController wakeLockController, DisplayDeviceConfig displayDeviceConfig, Looper looper, Runnable nudgeUpdatePowerState, int displayId, SensorManager sensorManager)167     public DisplayPowerProximityStateController(WakelockController wakeLockController,
168             DisplayDeviceConfig displayDeviceConfig, Looper looper,
169             Runnable nudgeUpdatePowerState, int displayId, SensorManager sensorManager) {
170         this(wakeLockController, displayDeviceConfig, looper, nudgeUpdatePowerState, displayId,
171                 sensorManager, new Injector());
172     }
173 
174     @VisibleForTesting
DisplayPowerProximityStateController(WakelockController wakeLockController, DisplayDeviceConfig displayDeviceConfig, Looper looper, Runnable nudgeUpdatePowerState, int displayId, SensorManager sensorManager, @Nullable Injector injector)175     DisplayPowerProximityStateController(WakelockController wakeLockController,
176             DisplayDeviceConfig displayDeviceConfig, Looper looper,
177             Runnable nudgeUpdatePowerState, int displayId, SensorManager sensorManager,
178             @Nullable Injector injector) {
179         if (injector == null) {
180             injector = new Injector();
181         }
182         mClock = injector.createClock();
183         mWakelockController = wakeLockController;
184         mHandler = new DisplayPowerProximityStateHandler(looper);
185         mNudgeUpdatePowerState = nudgeUpdatePowerState;
186         mDisplayDeviceConfig = displayDeviceConfig;
187         mDisplayId = displayId;
188         mTag = "DisplayPowerProximityStateController[" + mDisplayId + "]";
189         mSensorManager = sensorManager;
190         loadProximitySensor();
191     }
192 
193     /**
194      * Manages the pending state of the proximity.
195      */
updatePendingProximityRequestsLocked()196     public void updatePendingProximityRequestsLocked() {
197         synchronized (mLock) {
198             mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
199             mPendingWaitForNegativeProximityLocked = false;
200 
201             if (mIgnoreProximityUntilChanged) {
202                 // Also, lets stop waiting for negative proximity if we're ignoring it.
203                 mWaitingForNegativeProximity = false;
204             }
205         }
206     }
207 
208     /**
209      * Clean up all resources that are accessed via the {@link #mHandler} thread.
210      */
cleanup()211     public void cleanup() {
212         setProximitySensorEnabled(false);
213     }
214 
215     /**
216      * Returns true if the proximity sensor screen-off function is available.
217      */
isProximitySensorAvailable()218     public boolean isProximitySensorAvailable() {
219         return mProximitySensor != null;
220     }
221 
222     /**
223      * Sets the flag to indicate that the system is waiting for the negative proximity event
224      */
setPendingWaitForNegativeProximityLocked( boolean requestWaitForNegativeProximity)225     public boolean setPendingWaitForNegativeProximityLocked(
226             boolean requestWaitForNegativeProximity) {
227         synchronized (mLock) {
228             if (requestWaitForNegativeProximity
229                     && !mPendingWaitForNegativeProximityLocked) {
230                 mPendingWaitForNegativeProximityLocked = true;
231                 return true;
232             }
233             return false;
234         }
235     }
236 
237     /**
238      * Updates the proximity state of the display, based on the newly received DisplayPowerRequest
239      * and the target display state
240      */
updateProximityState( DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, int displayState)241     public void updateProximityState(
242             DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
243             int displayState) {
244         mSkipRampBecauseOfProximityChangeToNegative = false;
245         if (mProximitySensor != null) {
246             if (displayPowerRequest.useProximitySensor && displayState != Display.STATE_OFF) {
247                 // At this point the policy says that the screen should be on, but we've been
248                 // asked to listen to the prox sensor to adjust the display state, so lets make
249                 // sure the sensor is on.
250                 setProximitySensorEnabled(true);
251                 if (!mScreenOffBecauseOfProximity
252                         && mProximity == PROXIMITY_POSITIVE
253                         && !mIgnoreProximityUntilChanged) {
254                     // Prox sensor already reporting "near" so we should turn off the screen.
255                     // Also checked that we aren't currently set to ignore the proximity sensor
256                     // temporarily.
257                     mScreenOffBecauseOfProximity = true;
258                     sendOnProximityPositiveWithWakelock();
259                 }
260             } else if (mWaitingForNegativeProximity
261                     && mScreenOffBecauseOfProximity
262                     && mProximity == PROXIMITY_POSITIVE
263                     && displayState != Display.STATE_OFF) {
264                 // The policy says that we should have the screen on, but it's off due to the prox
265                 // and we've been asked to wait until the screen is far from the user to turn it
266                 // back on. Let keep the prox sensor on so we can tell when it's far again.
267                 setProximitySensorEnabled(true);
268             } else {
269                 // We haven't been asked to use the prox sensor and we're not waiting on the screen
270                 // to turn back on...so let's shut down the prox sensor.
271                 setProximitySensorEnabled(false);
272                 mWaitingForNegativeProximity = false;
273             }
274             if (mScreenOffBecauseOfProximity
275                     && (mProximity != PROXIMITY_POSITIVE || mIgnoreProximityUntilChanged)) {
276                 // The screen *was* off due to prox being near, but now it's "far" so lets turn
277                 // the screen back on.  Also turn it back on if we've been asked to ignore the
278                 // prox sensor temporarily.
279                 mScreenOffBecauseOfProximity = false;
280                 mSkipRampBecauseOfProximityChangeToNegative = true;
281                 sendOnProximityNegativeWithWakelock();
282             }
283         } else {
284             setProximitySensorEnabled(false);
285             mWaitingForNegativeProximity = false;
286             mIgnoreProximityUntilChanged = false;
287 
288             if (mScreenOffBecauseOfProximity) {
289                 // The screen *was* off due to prox being near, but now there's no prox sensor, so
290                 // let's turn the screen back on.
291                 mScreenOffBecauseOfProximity = false;
292                 mSkipRampBecauseOfProximityChangeToNegative = true;
293                 sendOnProximityNegativeWithWakelock();
294             }
295         }
296     }
297 
298     /**
299      * A utility to check if the brightness change ramp is to be skipped because the proximity was
300      * changed from positive to negative.
301      */
shouldSkipRampBecauseOfProximityChangeToNegative()302     public boolean shouldSkipRampBecauseOfProximityChangeToNegative() {
303         return mSkipRampBecauseOfProximityChangeToNegative;
304     }
305 
306     /**
307      * Represents of the screen is currently turned off because of the proximity state.
308      */
isScreenOffBecauseOfProximity()309     public boolean isScreenOffBecauseOfProximity() {
310         return mScreenOffBecauseOfProximity;
311     }
312 
313     /**
314      * Ignores the proximity sensor until the sensor state changes, but only if the sensor is
315      * currently enabled and forcing the screen to be dark.
316      */
ignoreProximitySensorUntilChanged()317     public void ignoreProximitySensorUntilChanged() {
318         mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY);
319     }
320 
321     /**
322      * This adjusts the state of this class when a change in the DisplayDevice is detected.
323      */
notifyDisplayDeviceChanged(DisplayDeviceConfig displayDeviceConfig)324     public void notifyDisplayDeviceChanged(DisplayDeviceConfig displayDeviceConfig) {
325         this.mDisplayDeviceConfig = displayDeviceConfig;
326         loadProximitySensor();
327     }
328 
329     /**
330      * Used to dump the state.
331      *
332      * @param pw The PrintWriter used to dump the state.
333      */
dumpLocal(PrintWriter pw)334     public void dumpLocal(PrintWriter pw) {
335         pw.println();
336         pw.println("DisplayPowerProximityStateController:");
337         pw.println("-------------------------------------");
338         synchronized (mLock) {
339             pw.println("  mPendingWaitForNegativeProximityLocked="
340                     + mPendingWaitForNegativeProximityLocked);
341         }
342         pw.println("  mDisplayId=" + mDisplayId);
343         pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
344         pw.println("  mIgnoreProximityUntilChanged=" + mIgnoreProximityUntilChanged);
345         pw.println("  mProximitySensor=" + mProximitySensor);
346         pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
347         pw.println("  mProximityThreshold=" + mProximityThreshold);
348         pw.println("  mProximity=" + proximityToString(mProximity));
349         pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
350         pw.println("  mPendingProximityDebounceTime="
351                 + TimeUtils.formatUptime(mPendingProximityDebounceTime));
352         pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
353         pw.println("  mSkipRampBecauseOfProximityChangeToNegative="
354                 + mSkipRampBecauseOfProximityChangeToNegative);
355     }
356 
ignoreProximitySensorUntilChangedInternal()357     void ignoreProximitySensorUntilChangedInternal() {
358         if (!mIgnoreProximityUntilChanged
359                 && mProximity == PROXIMITY_POSITIVE) {
360             // Only ignore if it is still reporting positive (near)
361             mIgnoreProximityUntilChanged = true;
362             Slog.i(mTag, "Ignoring proximity");
363             mNudgeUpdatePowerState.run();
364         }
365     }
366 
sendOnProximityPositiveWithWakelock()367     private void sendOnProximityPositiveWithWakelock() {
368         mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE);
369         mHandler.post(mWakelockController.getOnProximityPositiveRunnable());
370     }
371 
sendOnProximityNegativeWithWakelock()372     private void sendOnProximityNegativeWithWakelock() {
373         mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE);
374         mHandler.post(mWakelockController.getOnProximityNegativeRunnable());
375     }
376 
loadProximitySensor()377     private void loadProximitySensor() {
378         if (DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT || mDisplayId != Display.DEFAULT_DISPLAY) {
379             return;
380         }
381         mProximitySensor = SensorUtils.findSensor(mSensorManager,
382                 mDisplayDeviceConfig.getProximitySensor(), Sensor.TYPE_PROXIMITY);
383         if (mProximitySensor != null) {
384             mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
385                     TYPICAL_PROXIMITY_THRESHOLD);
386         }
387     }
388 
setProximitySensorEnabled(boolean enable)389     private void setProximitySensorEnabled(boolean enable) {
390         if (enable) {
391             if (!mProximitySensorEnabled) {
392                 // Register the listener.
393                 // Proximity sensor state already cleared initially.
394                 mProximitySensorEnabled = true;
395                 mIgnoreProximityUntilChanged = false;
396                 mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
397                         SensorManager.SENSOR_DELAY_NORMAL, mHandler);
398             }
399         } else {
400             if (mProximitySensorEnabled) {
401                 // Unregister the listener.
402                 // Clear the proximity sensor state for next time.
403                 mProximitySensorEnabled = false;
404                 mProximity = PROXIMITY_UNKNOWN;
405                 mIgnoreProximityUntilChanged = false;
406                 mPendingProximity = PROXIMITY_UNKNOWN;
407                 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
408                 mSensorManager.unregisterListener(mProximitySensorListener);
409                 // release wake lock(must be last)
410                 boolean proxDebounceSuspendBlockerReleased =
411                         mWakelockController.releaseWakelock(
412                                 WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
413                 if (proxDebounceSuspendBlockerReleased) {
414                     mPendingProximityDebounceTime = -1;
415                 }
416             }
417         }
418     }
419 
handleProximitySensorEvent(long time, boolean positive)420     private void handleProximitySensorEvent(long time, boolean positive) {
421         if (mProximitySensorEnabled) {
422             if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
423                 return; // no change
424             }
425             if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
426                 return; // no change
427             }
428 
429             // Only accept a proximity sensor reading if it remains
430             // stable for the entire debounce delay.  We hold a wake lock while
431             // debouncing the sensor.
432             mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
433             if (positive) {
434                 mPendingProximity = PROXIMITY_POSITIVE;
435                 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
436                 mWakelockController.acquireWakelock(
437                         WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock
438             } else {
439                 mPendingProximity = PROXIMITY_NEGATIVE;
440                 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
441                 mWakelockController.acquireWakelock(
442                         WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock
443             }
444 
445             // Debounce the new sensor reading.
446             debounceProximitySensor();
447         }
448     }
449 
debounceProximitySensor()450     private void debounceProximitySensor() {
451         if (mProximitySensorEnabled
452                 && mPendingProximity != PROXIMITY_UNKNOWN
453                 && mPendingProximityDebounceTime >= 0) {
454             final long now = mClock.uptimeMillis();
455             if (mPendingProximityDebounceTime <= now) {
456                 if (mProximity != mPendingProximity) {
457                     // if the status of the sensor changed, stop ignoring.
458                     mIgnoreProximityUntilChanged = false;
459                     Slog.i(mTag, "Applying proximity: " + proximityToString(mPendingProximity));
460                 }
461                 // Sensor reading accepted.  Apply the change then release the wake lock.
462                 mProximity = mPendingProximity;
463                 mNudgeUpdatePowerState.run();
464                 // (must be last)
465                 boolean proxDebounceSuspendBlockerReleased =
466                         mWakelockController.releaseWakelock(
467                                 WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
468                 if (proxDebounceSuspendBlockerReleased) {
469                     mPendingProximityDebounceTime = -1;
470                 }
471 
472             } else {
473                 // Need to wait a little longer.
474                 // Debounce again later.  We continue holding a wake lock while waiting.
475                 Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
476                 mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
477             }
478         }
479     }
480 
481     private class DisplayPowerProximityStateHandler extends Handler {
DisplayPowerProximityStateHandler(Looper looper)482         DisplayPowerProximityStateHandler(Looper looper) {
483             super(looper, null, true /*async*/);
484         }
485 
486         @Override
handleMessage(Message msg)487         public void handleMessage(Message msg) {
488             switch (msg.what) {
489                 case MSG_PROXIMITY_SENSOR_DEBOUNCED:
490                     debounceProximitySensor();
491                     break;
492 
493                 case MSG_IGNORE_PROXIMITY:
494                     ignoreProximitySensorUntilChangedInternal();
495                     break;
496             }
497         }
498     }
499 
proximityToString(@roximityState int state)500     private String proximityToString(@ProximityState int state) {
501         switch (state) {
502             case PROXIMITY_UNKNOWN:
503                 return "Unknown";
504             case PROXIMITY_NEGATIVE:
505                 return "Negative";
506             case PROXIMITY_POSITIVE:
507                 return "Positive";
508             default:
509                 return Integer.toString(state);
510         }
511     }
512 
513     @VisibleForTesting
getPendingWaitForNegativeProximityLocked()514     boolean getPendingWaitForNegativeProximityLocked() {
515         synchronized (mLock) {
516             return mPendingWaitForNegativeProximityLocked;
517         }
518     }
519 
520     @VisibleForTesting
getWaitingForNegativeProximity()521     boolean getWaitingForNegativeProximity() {
522         return mWaitingForNegativeProximity;
523     }
524 
525     @VisibleForTesting
shouldIgnoreProximityUntilChanged()526     boolean shouldIgnoreProximityUntilChanged() {
527         return mIgnoreProximityUntilChanged;
528     }
529 
isProximitySensorEnabled()530     boolean isProximitySensorEnabled() {
531         return mProximitySensorEnabled;
532     }
533 
534     @VisibleForTesting
getHandler()535     Handler getHandler() {
536         return mHandler;
537     }
538 
539     @VisibleForTesting
getPendingProximity()540     @ProximityState int getPendingProximity() {
541         return mPendingProximity;
542     }
543 
544     @VisibleForTesting
getProximity()545     @ProximityState int getProximity() {
546         return mProximity;
547     }
548 
549 
550     @VisibleForTesting
getPendingProximityDebounceTime()551     long getPendingProximityDebounceTime() {
552         return mPendingProximityDebounceTime;
553     }
554 
555     @VisibleForTesting
getProximitySensorListener()556     SensorEventListener getProximitySensorListener() {
557         return mProximitySensorListener;
558     }
559 
560     /** Functional interface for providing time. */
561     @VisibleForTesting
562     interface Clock {
563         /**
564          * Returns current time in milliseconds since boot, not counting time spent in deep sleep.
565          */
uptimeMillis()566         long uptimeMillis();
567     }
568 
569     @VisibleForTesting
570     static class Injector {
createClock()571         Clock createClock() {
572             return SystemClock::uptimeMillis;
573         }
574     }
575 }
576