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.R; 22 import com.android.internal.annotations.VisibleForTesting; 23 24 import java.util.HashMap; 25 import java.util.LinkedList; 26 import java.util.Map; 27 28 /** 29 * Default garage mode policy. 30 * 31 * The first wake up time is set to be 1am the next day. And it keeps waking up every day for a 32 * week. After that, wake up every 7 days for a month, and wake up every 30 days thereafter. 33 */ 34 class WakeupPolicy { 35 private static final Logger LOG = new Logger("WakeupPolicy"); 36 private static final Map<Character, Integer> TIME_UNITS_LOOKUP_SEC; 37 static { 38 TIME_UNITS_LOOKUP_SEC = new HashMap<>(); 39 TIME_UNITS_LOOKUP_SEC.put('m', 60); 40 TIME_UNITS_LOOKUP_SEC.put('h', 3600); 41 TIME_UNITS_LOOKUP_SEC.put('d', 86400); 42 } 43 private LinkedList<WakeupInterval> mWakeupIntervals; 44 @VisibleForTesting protected int mIndex; 45 WakeupPolicy(String[] policy)46 WakeupPolicy(String[] policy) { 47 mWakeupIntervals = parsePolicy(policy); 48 mIndex = 0; 49 } 50 51 /** 52 * Initializes Policy from config_garageModeCadence resource array. 53 * @param context to access resources 54 * @return Policy instance, created from values in resources 55 */ initFromResources(Context context)56 public static WakeupPolicy initFromResources(Context context) { 57 LOG.d("Initiating WakupPolicy from resources ..."); 58 return new WakeupPolicy( 59 context.getResources().getStringArray(R.array.config_garageModeCadence)); 60 } 61 62 /** 63 * Returns the interval in seconds, which defines next wake up time. 64 * @return the interval in seconds 65 */ getNextWakeUpInterval()66 public int getNextWakeUpInterval() { 67 if (mWakeupIntervals.size() == 0) { 68 LOG.e("No wake up policy configuration was loaded."); 69 return 0; 70 } 71 72 int index = mIndex; 73 for (WakeupInterval wakeupTime : mWakeupIntervals) { 74 if (index <= wakeupTime.getNumAttempts()) { 75 return wakeupTime.getWakeupInterval(); 76 } 77 index -= wakeupTime.getNumAttempts(); 78 } 79 LOG.w("No more garage mode wake ups scheduled; been sleeping too long."); 80 return 0; 81 } 82 getWakupIntervalsAmount()83 protected int getWakupIntervalsAmount() { 84 return mWakeupIntervals.size(); 85 } 86 parsePolicy(String[] policy)87 private LinkedList<WakeupInterval> parsePolicy(String[] policy) { 88 LinkedList<WakeupInterval> intervals = new LinkedList<>(); 89 if (policy == null || policy.length == 0) { 90 LOG.e("Trying to parse empty policies!"); 91 return intervals; 92 } 93 94 for (String rule : policy) { 95 WakeupInterval interval = parseRule(rule); 96 if (interval == null) { 97 LOG.e("Invalid Policy! This rule has bad format: " + rule); 98 return new LinkedList<>(); 99 } 100 intervals.add(interval); 101 } 102 return intervals; 103 } 104 parseRule(String rule)105 private WakeupInterval parseRule(String rule) { 106 String[] str = rule.split(","); 107 108 if (str.length != 2) { 109 LOG.e("Policy has bad format: " + rule); 110 return null; 111 } 112 113 String intervalStr = str[0]; 114 String timesStr = str[1]; 115 116 if (intervalStr.isEmpty() || timesStr.isEmpty()) { 117 LOG.e("One of the values is empty. Please check format: " + rule); 118 return null; 119 } 120 121 char unit = intervalStr.charAt(intervalStr.length() - 1); 122 123 // Removing last letter extension from string 124 intervalStr = intervalStr.substring(0, intervalStr.length() - 1); 125 126 int interval, times; 127 try { 128 interval = Integer.parseInt(intervalStr); 129 times = Integer.parseInt(timesStr); 130 } catch (NumberFormatException ex) { 131 LOG.d("Invalid input Rule for interval " + rule); 132 return null; 133 } 134 135 if (!TIME_UNITS_LOOKUP_SEC.containsKey(unit)) { 136 LOG.e("Time units map does not contain extension " + unit); 137 return null; 138 } 139 140 if (interval <= 0) { 141 LOG.e("Wake up policy time must be > 0!" + interval); 142 return null; 143 } 144 145 if (times <= 0) { 146 LOG.e("Wake up attempts in policy must be > 0!" + times); 147 return null; 148 } 149 150 interval *= TIME_UNITS_LOOKUP_SEC.get(unit); 151 152 return new WakeupInterval(interval, times); 153 } 154 incrementCounter()155 public void incrementCounter() { 156 mIndex++; 157 } 158 resetCounter()159 public void resetCounter() { 160 mIndex = 0; 161 } 162 163 /** 164 * Defines wake up interval which then will be used by 165 * {@link com.android.car.garagemode.GarageModeService} to schedule next wake up time in 166 * {@link android.car.hardware.power.CarPowerManager} 167 */ 168 private class WakeupInterval { 169 private int mWakeupInterval; 170 private int mNumAttempts; 171 WakeupInterval(int wakeupTime, int numAttempts)172 WakeupInterval(int wakeupTime, int numAttempts) { 173 mWakeupInterval = wakeupTime; 174 mNumAttempts = numAttempts; 175 } 176 177 /** 178 * Returns interval between now and next wakeup. 179 * @return interval in seconds 180 */ getWakeupInterval()181 public int getWakeupInterval() { 182 return mWakeupInterval; 183 } 184 185 /** 186 * Returns amount of attempts to wake up with mWakeupInterval 187 * @return amount of attempts 188 */ getNumAttempts()189 public int getNumAttempts() { 190 return mNumAttempts; 191 } 192 } 193 194 } 195