blob: 7db06c4ed6091177949a547fa78da8ebbb4a9392 [file] [log] [blame]
Serik Beketayev1a503e42018-06-15 12:04:50 -07001/*
2 * Copyright (C) 2018 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
17package com.android.car.garagemode;
18
19import android.content.Context;
20
Eric Jeong4531c912021-05-04 10:54:35 -070021import com.android.car.CarLog;
Serik Beketayev1a503e42018-06-15 12:04:50 -070022import com.android.car.R;
23import com.android.internal.annotations.VisibleForTesting;
Eric Jeong4531c912021-05-04 10:54:35 -070024import com.android.server.utils.Slogf;
Serik Beketayev1a503e42018-06-15 12:04:50 -070025
26import java.util.HashMap;
27import java.util.LinkedList;
28import java.util.Map;
29
30/**
31 * Default garage mode policy.
32 *
33 * The first wake up time is set to be 1am the next day. And it keeps waking up every day for a
34 * week. After that, wake up every 7 days for a month, and wake up every 30 days thereafter.
35 */
36class WakeupPolicy {
Eric Jeong4531c912021-05-04 10:54:35 -070037
38 private static final String TAG = CarLog.tagFor(GarageMode.class) + "_"
39 + WakeupPolicy.class.getSimpleName();
Serik Beketayevc6ab8be2018-08-28 21:20:53 -070040 private static final Map<Character, Integer> TIME_UNITS_LOOKUP_SEC;
Serik Beketayev1a503e42018-06-15 12:04:50 -070041 static {
Serik Beketayevc6ab8be2018-08-28 21:20:53 -070042 TIME_UNITS_LOOKUP_SEC = new HashMap<>();
43 TIME_UNITS_LOOKUP_SEC.put('m', 60);
44 TIME_UNITS_LOOKUP_SEC.put('h', 3600);
45 TIME_UNITS_LOOKUP_SEC.put('d', 86400);
Serik Beketayev1a503e42018-06-15 12:04:50 -070046 }
47 private LinkedList<WakeupInterval> mWakeupIntervals;
48 @VisibleForTesting protected int mIndex;
49
50 WakeupPolicy(String[] policy) {
51 mWakeupIntervals = parsePolicy(policy);
52 mIndex = 0;
53 }
54
55 /**
56 * Initializes Policy from config_garageModeCadence resource array.
57 * @param context to access resources
58 * @return Policy instance, created from values in resources
59 */
60 public static WakeupPolicy initFromResources(Context context) {
Eric Jeong4531c912021-05-04 10:54:35 -070061 Slogf.d(TAG, "Initiating WakupPolicy from resources ...");
Serik Beketayev1a503e42018-06-15 12:04:50 -070062 return new WakeupPolicy(
63 context.getResources().getStringArray(R.array.config_garageModeCadence));
64 }
65
66 /**
Serik Beketayevc6ab8be2018-08-28 21:20:53 -070067 * Returns the interval in seconds, which defines next wake up time.
68 * @return the interval in seconds
Serik Beketayev1a503e42018-06-15 12:04:50 -070069 */
70 public int getNextWakeUpInterval() {
71 if (mWakeupIntervals.size() == 0) {
Eric Jeong4531c912021-05-04 10:54:35 -070072 Slogf.e(TAG, "No wake up policy configuration was loaded.");
Serik Beketayev1a503e42018-06-15 12:04:50 -070073 return 0;
74 }
75
76 int index = mIndex;
77 for (WakeupInterval wakeupTime : mWakeupIntervals) {
78 if (index <= wakeupTime.getNumAttempts()) {
Serik Beketayevc6ab8be2018-08-28 21:20:53 -070079 return wakeupTime.getWakeupInterval();
Serik Beketayev1a503e42018-06-15 12:04:50 -070080 }
81 index -= wakeupTime.getNumAttempts();
82 }
Eric Jeong4531c912021-05-04 10:54:35 -070083 Slogf.w(TAG, "No more garage mode wake ups scheduled; been sleeping too long.");
Serik Beketayev1a503e42018-06-15 12:04:50 -070084 return 0;
85 }
86
87 protected int getWakupIntervalsAmount() {
88 return mWakeupIntervals.size();
89 }
90
91 private LinkedList<WakeupInterval> parsePolicy(String[] policy) {
92 LinkedList<WakeupInterval> intervals = new LinkedList<>();
93 if (policy == null || policy.length == 0) {
Eric Jeong4531c912021-05-04 10:54:35 -070094 Slogf.e(TAG, "Trying to parse empty policies!");
Serik Beketayev1a503e42018-06-15 12:04:50 -070095 return intervals;
96 }
97
98 for (String rule : policy) {
99 WakeupInterval interval = parseRule(rule);
100 if (interval == null) {
Eric Jeong4531c912021-05-04 10:54:35 -0700101 Slogf.e(TAG, "Invalid Policy! This rule has bad format: %s", rule);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700102 return new LinkedList<>();
103 }
104 intervals.add(interval);
105 }
106 return intervals;
107 }
108
109 private WakeupInterval parseRule(String rule) {
110 String[] str = rule.split(",");
111
112 if (str.length != 2) {
Eric Jeong4531c912021-05-04 10:54:35 -0700113 Slogf.e(TAG, "Policy has bad format: %s", rule);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700114 return null;
115 }
116
117 String intervalStr = str[0];
118 String timesStr = str[1];
119
120 if (intervalStr.isEmpty() || timesStr.isEmpty()) {
Eric Jeong4531c912021-05-04 10:54:35 -0700121 Slogf.e(TAG, "One of the values is empty. Please check format: %s", rule);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700122 return null;
123 }
124
125 char unit = intervalStr.charAt(intervalStr.length() - 1);
126
127 // Removing last letter extension from string
128 intervalStr = intervalStr.substring(0, intervalStr.length() - 1);
129
130 int interval, times;
131 try {
132 interval = Integer.parseInt(intervalStr);
133 times = Integer.parseInt(timesStr);
134 } catch (NumberFormatException ex) {
Eric Jeong4531c912021-05-04 10:54:35 -0700135 Slogf.d(TAG, "Invalid input Rule for interval %s", rule);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700136 return null;
137 }
138
Serik Beketayevc6ab8be2018-08-28 21:20:53 -0700139 if (!TIME_UNITS_LOOKUP_SEC.containsKey(unit)) {
Eric Jeong4531c912021-05-04 10:54:35 -0700140 Slogf.e(TAG, "Time units map does not contain extension %c", unit);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700141 return null;
142 }
143
144 if (interval <= 0) {
Eric Jeong4531c912021-05-04 10:54:35 -0700145 Slogf.e(TAG, "Wake up policy time(%d) must be > 0!", interval);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700146 return null;
147 }
148
149 if (times <= 0) {
Eric Jeong4531c912021-05-04 10:54:35 -0700150 Slogf.e(TAG, "Wake up attempts(%d) in policy must be > 0!", times);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700151 return null;
152 }
153
Serik Beketayevc6ab8be2018-08-28 21:20:53 -0700154 interval *= TIME_UNITS_LOOKUP_SEC.get(unit);
Serik Beketayev1a503e42018-06-15 12:04:50 -0700155
156 return new WakeupInterval(interval, times);
157 }
158
159 public void incrementCounter() {
160 mIndex++;
161 }
162
163 public void resetCounter() {
164 mIndex = 0;
165 }
166
167 /**
168 * Defines wake up interval which then will be used by
Serik Beketayevc6ab8be2018-08-28 21:20:53 -0700169 * {@link com.android.car.garagemode.GarageModeService} to schedule next wake up time in
170 * {@link android.car.hardware.power.CarPowerManager}
Serik Beketayev1a503e42018-06-15 12:04:50 -0700171 */
172 private class WakeupInterval {
Serik Beketayevc6ab8be2018-08-28 21:20:53 -0700173 private int mWakeupInterval;
Serik Beketayev1a503e42018-06-15 12:04:50 -0700174 private int mNumAttempts;
175
176 WakeupInterval(int wakeupTime, int numAttempts) {
Serik Beketayevc6ab8be2018-08-28 21:20:53 -0700177 mWakeupInterval = wakeupTime;
Serik Beketayev1a503e42018-06-15 12:04:50 -0700178 mNumAttempts = numAttempts;
179 }
180
181 /**
Serik Beketayevc6ab8be2018-08-28 21:20:53 -0700182 * Returns interval between now and next wakeup.
Serik Beketayev1a503e42018-06-15 12:04:50 -0700183 * @return interval in seconds
184 */
Serik Beketayevc6ab8be2018-08-28 21:20:53 -0700185 public int getWakeupInterval() {
186 return mWakeupInterval;
Serik Beketayev1a503e42018-06-15 12:04:50 -0700187 }
188
189 /**
190 * Returns amount of attempts to wake up with mWakeupInterval
191 * @return amount of attempts
192 */
193 public int getNumAttempts() {
194 return mNumAttempts;
195 }
196 }
197
198}