• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.car.garagemode;
18 
19 import android.content.Context;
20 
21 import com.android.car.CarLog;
22 import com.android.car.R;
23 import com.android.internal.annotations.VisibleForTesting;
24 import com.android.server.utils.Slogf;
25 
26 import java.util.HashMap;
27 import java.util.LinkedList;
28 import 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  */
36 class WakeupPolicy {
37 
38     private static final String TAG = CarLog.tagFor(GarageMode.class) + "_"
39             + WakeupPolicy.class.getSimpleName();
40     private static final Map<Character, Integer> TIME_UNITS_LOOKUP_SEC;
41     static {
42         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);
46     }
47     private LinkedList<WakeupInterval> mWakeupIntervals;
48     @VisibleForTesting protected int mIndex;
49 
WakeupPolicy(String[] policy)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      */
initFromResources(Context context)60     public static WakeupPolicy initFromResources(Context context) {
61         Slogf.d(TAG, "Initiating WakupPolicy from resources ...");
62         return new WakeupPolicy(
63                 context.getResources().getStringArray(R.array.config_garageModeCadence));
64     }
65 
66     /**
67      * Returns the interval in seconds, which defines next wake up time.
68      * @return the interval in seconds
69      */
getNextWakeUpInterval()70     public int getNextWakeUpInterval() {
71         if (mWakeupIntervals.size() == 0) {
72             Slogf.e(TAG, "No wake up policy configuration was loaded.");
73             return 0;
74         }
75 
76         int index = mIndex;
77         for (WakeupInterval wakeupTime : mWakeupIntervals) {
78             if (index <= wakeupTime.getNumAttempts()) {
79                 return wakeupTime.getWakeupInterval();
80             }
81             index -= wakeupTime.getNumAttempts();
82         }
83         Slogf.w(TAG, "No more garage mode wake ups scheduled; been sleeping too long.");
84         return 0;
85     }
86 
getWakupIntervalsAmount()87     protected int getWakupIntervalsAmount() {
88         return mWakeupIntervals.size();
89     }
90 
parsePolicy(String[] policy)91     private LinkedList<WakeupInterval> parsePolicy(String[] policy) {
92         LinkedList<WakeupInterval> intervals = new LinkedList<>();
93         if (policy == null || policy.length == 0) {
94             Slogf.e(TAG, "Trying to parse empty policies!");
95             return intervals;
96         }
97 
98         for (String rule : policy) {
99             WakeupInterval interval = parseRule(rule);
100             if (interval == null) {
101                 Slogf.e(TAG, "Invalid Policy! This rule has bad format: %s", rule);
102                 return new LinkedList<>();
103             }
104             intervals.add(interval);
105         }
106         return intervals;
107     }
108 
parseRule(String rule)109     private WakeupInterval parseRule(String rule) {
110         String[] str = rule.split(",");
111 
112         if (str.length != 2) {
113             Slogf.e(TAG, "Policy has bad format: %s", rule);
114             return null;
115         }
116 
117         String intervalStr = str[0];
118         String timesStr = str[1];
119 
120         if (intervalStr.isEmpty() || timesStr.isEmpty()) {
121             Slogf.e(TAG, "One of the values is empty. Please check format: %s", rule);
122             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)  {
135             Slogf.d(TAG, "Invalid input Rule for interval %s", rule);
136             return null;
137         }
138 
139         if (!TIME_UNITS_LOOKUP_SEC.containsKey(unit)) {
140             Slogf.e(TAG, "Time units map does not contain extension %c", unit);
141             return null;
142         }
143 
144         if (interval <= 0) {
145             Slogf.e(TAG, "Wake up policy time(%d) must be > 0!", interval);
146             return null;
147         }
148 
149         if (times <= 0) {
150             Slogf.e(TAG, "Wake up attempts(%d) in policy must be > 0!", times);
151             return null;
152         }
153 
154         interval *= TIME_UNITS_LOOKUP_SEC.get(unit);
155 
156         return new WakeupInterval(interval, times);
157     }
158 
incrementCounter()159     public void incrementCounter() {
160         mIndex++;
161     }
162 
resetCounter()163     public void resetCounter() {
164         mIndex = 0;
165     }
166 
167     /**
168      * Defines wake up interval which then will be used by
169      * {@link com.android.car.garagemode.GarageModeService} to schedule next wake up time in
170      * {@link android.car.hardware.power.CarPowerManager}
171      */
172     private class WakeupInterval {
173         private int mWakeupInterval;
174         private int mNumAttempts;
175 
WakeupInterval(int wakeupTime, int numAttempts)176         WakeupInterval(int wakeupTime, int numAttempts) {
177             mWakeupInterval = wakeupTime;
178             mNumAttempts = numAttempts;
179         }
180 
181         /**
182          * Returns interval between now and next wakeup.
183          * @return interval in seconds
184          */
getWakeupInterval()185         public int getWakeupInterval() {
186             return mWakeupInterval;
187         }
188 
189         /**
190          * Returns amount of attempts to wake up with mWakeupInterval
191          * @return amount of attempts
192          */
getNumAttempts()193         public int getNumAttempts() {
194             return mNumAttempts;
195         }
196     }
197 
198 }
199