1 /*
2  * Copyright (C) 2021 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.tare;
18 
19 import android.annotation.NonNull;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.os.PowerManager;
25 import android.util.IndentingPrintWriter;
26 import android.util.Log;
27 
28 /** Modifier that makes things more expensive in light and deep doze. */
29 class DeviceIdleModifier extends Modifier {
30     private static final String TAG = "TARE-" + DeviceIdleModifier.class.getSimpleName();
31     private static final boolean DEBUG = InternalResourceService.DEBUG
32             || Log.isLoggable(TAG, Log.DEBUG);
33 
34     private final InternalResourceService mIrs;
35     private final PowerManager mPowerManager;
36     private final DeviceIdleTracker mDeviceIdleTracker;
37 
DeviceIdleModifier(@onNull InternalResourceService irs)38     DeviceIdleModifier(@NonNull InternalResourceService irs) {
39         super();
40         mIrs = irs;
41         mPowerManager = irs.getContext().getSystemService(PowerManager.class);
42         mDeviceIdleTracker = new DeviceIdleTracker();
43     }
44 
45     @Override
setup()46     public void setup() {
47         mDeviceIdleTracker.startTracking(mIrs.getContext());
48     }
49 
50     @Override
tearDown()51     public void tearDown() {
52         mDeviceIdleTracker.stopTracking(mIrs.getContext());
53     }
54 
55     @Override
getModifiedCostToProduce(long ctp)56     long getModifiedCostToProduce(long ctp) {
57         if (mDeviceIdleTracker.mDeviceIdle) {
58             return (long) (1.2 * ctp);
59         }
60         if (mDeviceIdleTracker.mDeviceLightIdle) {
61             return (long) (1.1 * ctp);
62         }
63         return ctp;
64     }
65 
66     @Override
dump(IndentingPrintWriter pw)67     void dump(IndentingPrintWriter pw) {
68         pw.print("idle=");
69         pw.println(mDeviceIdleTracker.mDeviceIdle);
70         pw.print("lightIdle=");
71         pw.println(mDeviceIdleTracker.mDeviceLightIdle);
72     }
73 
74     private final class DeviceIdleTracker extends BroadcastReceiver {
75         private boolean mIsSetup = false;
76 
77         private volatile boolean mDeviceIdle;
78         private volatile boolean mDeviceLightIdle;
79 
DeviceIdleTracker()80         DeviceIdleTracker() {
81         }
82 
startTracking(@onNull Context context)83         void startTracking(@NonNull Context context) {
84             if (mIsSetup) {
85                 return;
86             }
87 
88             IntentFilter filter = new IntentFilter();
89             filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
90             filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
91             context.registerReceiver(this, filter);
92 
93             // Initialise tracker state.
94             mDeviceIdle = mPowerManager.isDeviceIdleMode();
95             mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
96 
97             mIsSetup = true;
98         }
99 
stopTracking(@onNull Context context)100         void stopTracking(@NonNull Context context) {
101             if (!mIsSetup) {
102                 return;
103             }
104 
105             context.unregisterReceiver(this);
106             mIsSetup = false;
107         }
108 
109         @Override
onReceive(Context context, Intent intent)110         public void onReceive(Context context, Intent intent) {
111             final String action = intent.getAction();
112             if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
113                 if (mDeviceIdle != mPowerManager.isDeviceIdleMode()) {
114                     mDeviceIdle = mPowerManager.isDeviceIdleMode();
115                     mIrs.onDeviceStateChanged();
116                 }
117             } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
118                 if (mDeviceLightIdle != mPowerManager.isLightDeviceIdleMode()) {
119                     mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
120                     mIrs.onDeviceStateChanged();
121                 }
122             }
123         }
124     }
125 }
126