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.os.SystemClock;
26 import android.util.IndentingPrintWriter;
27 import android.util.Log;
28 import android.util.Slog;
29 
30 /** Modifier that makes things more expensive in adaptive and full battery saver are active. */
31 class PowerSaveModeModifier extends Modifier {
32     private static final String TAG = "TARE-" + PowerSaveModeModifier.class.getSimpleName();
33     private static final boolean DEBUG = InternalResourceService.DEBUG
34             || Log.isLoggable(TAG, Log.DEBUG);
35 
36     private final InternalResourceService mIrs;
37     private final PowerSaveModeTracker mPowerSaveModeTracker;
38 
PowerSaveModeModifier(@onNull InternalResourceService irs)39     PowerSaveModeModifier(@NonNull InternalResourceService irs) {
40         super();
41         mIrs = irs;
42         mPowerSaveModeTracker = new PowerSaveModeTracker();
43     }
44 
45     @Override
setup()46     public void setup() {
47         mPowerSaveModeTracker.startTracking(mIrs.getContext());
48     }
49 
50     @Override
tearDown()51     public void tearDown() {
52         mPowerSaveModeTracker.stopTracking(mIrs.getContext());
53     }
54 
55     @Override
getModifiedCostToProduce(long ctp)56     long getModifiedCostToProduce(long ctp) {
57         if (mPowerSaveModeTracker.mPowerSaveModeEnabled) {
58             return (long) (1.5 * ctp);
59         }
60         // TODO: get adaptive power save mode
61         if (mPowerSaveModeTracker.mPowerSaveModeEnabled) {
62             return (long) (1.25 * ctp);
63         }
64         return ctp;
65     }
66 
67     @Override
dump(IndentingPrintWriter pw)68     void dump(IndentingPrintWriter pw) {
69         pw.print("power save=");
70         pw.println(mPowerSaveModeTracker.mPowerSaveModeEnabled);
71     }
72 
73     // TODO: migrate to relying on PowerSaveState and ServiceType.TARE
74     private final class PowerSaveModeTracker extends BroadcastReceiver {
75         private boolean mIsSetup = false;
76 
77         private final PowerManager mPowerManager;
78         private volatile boolean mPowerSaveModeEnabled;
79 
PowerSaveModeTracker()80         private PowerSaveModeTracker() {
81             mPowerManager = mIrs.getContext().getSystemService(PowerManager.class);
82         }
83 
startTracking(@onNull Context context)84         public void startTracking(@NonNull Context context) {
85             if (mIsSetup) {
86                 return;
87             }
88 
89             final IntentFilter filter = new IntentFilter();
90             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
91             context.registerReceiver(this, filter);
92 
93             // Initialise tracker state.
94             mPowerSaveModeEnabled = mPowerManager.isPowerSaveMode();
95 
96             mIsSetup = true;
97         }
98 
stopTracking(@onNull Context context)99         public void stopTracking(@NonNull Context context) {
100             if (!mIsSetup) {
101                 return;
102             }
103 
104             context.unregisterReceiver(this);
105             mIsSetup = false;
106         }
107 
108         @Override
onReceive(Context context, Intent intent)109         public void onReceive(Context context, Intent intent) {
110             final String action = intent.getAction();
111             if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
112                 final boolean enabled = mPowerManager.isPowerSaveMode();
113                 if (DEBUG) {
114                     Slog.d(TAG, "Power save mode changed to " + enabled
115                             + ", fired @ " + SystemClock.elapsedRealtime());
116                 }
117                 if (mPowerSaveModeEnabled != enabled) {
118                     mPowerSaveModeEnabled = enabled;
119                     mIrs.onDeviceStateChanged();
120                 }
121             }
122         }
123     }
124 }
125