1 /* 2 * Copyright (C) 2013 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.internal.telephony; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.os.Message; 24 import android.os.PowerManager; 25 26 import com.android.internal.telephony.util.TelephonyUtils; 27 import com.android.internal.util.State; 28 import com.android.internal.util.StateMachine; 29 import com.android.telephony.Rlog; 30 31 import java.util.concurrent.atomic.AtomicInteger; 32 33 /** 34 * Generic state machine for handling messages and waiting for ordered broadcasts to complete. 35 * Subclasses implement {@link #handleSmsMessage}, which returns true to transition into waiting 36 * state, or false to remain in idle state. The wakelock is acquired on exit from idle state, 37 * and is released a few seconds after returning to idle state, or immediately upon calling 38 * {@link #quit}. 39 */ 40 public abstract class WakeLockStateMachine extends StateMachine { 41 protected static final boolean DBG = TelephonyUtils.IS_DEBUGGABLE; 42 43 private final PowerManager.WakeLock mWakeLock; 44 45 /** New message to process. */ 46 public static final int EVENT_NEW_SMS_MESSAGE = 1; 47 48 /** Result receiver called for current cell broadcast. */ 49 protected static final int EVENT_BROADCAST_COMPLETE = 2; 50 51 /** Release wakelock after a short timeout when returning to idle state. */ 52 static final int EVENT_RELEASE_WAKE_LOCK = 3; 53 54 /** Broadcast not required due to geo-fencing check */ 55 static final int EVENT_BROADCAST_NOT_REQUIRED = 4; 56 57 @UnsupportedAppUsage 58 protected Phone mPhone; 59 60 @UnsupportedAppUsage 61 protected Context mContext; 62 63 protected AtomicInteger mReceiverCount = new AtomicInteger(0); 64 65 /** Wakelock release delay when returning to idle state. */ 66 private static final int WAKE_LOCK_TIMEOUT = 3000; 67 68 private final DefaultState mDefaultState = new DefaultState(); 69 @UnsupportedAppUsage 70 private final IdleState mIdleState = new IdleState(); 71 private final WaitingState mWaitingState = new WaitingState(); 72 WakeLockStateMachine(String debugTag, Context context, Phone phone)73 protected WakeLockStateMachine(String debugTag, Context context, Phone phone) { 74 super(debugTag); 75 76 mContext = context; 77 mPhone = phone; 78 79 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 80 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, debugTag); 81 // wake lock released after we enter idle state 82 mWakeLock.acquire(); 83 84 addState(mDefaultState); 85 addState(mIdleState, mDefaultState); 86 addState(mWaitingState, mDefaultState); 87 setInitialState(mIdleState); 88 } 89 releaseWakeLock()90 private void releaseWakeLock() { 91 if (mWakeLock.isHeld()) { 92 mWakeLock.release(); 93 } 94 95 if (mWakeLock.isHeld()) { 96 loge("Wait lock is held after release."); 97 } 98 } 99 100 /** 101 * Tell the state machine to quit after processing all messages. 102 */ dispose()103 public final void dispose() { 104 quit(); 105 } 106 107 @Override onQuitting()108 protected void onQuitting() { 109 // fully release the wakelock 110 while (mWakeLock.isHeld()) { 111 mWakeLock.release(); 112 } 113 } 114 115 /** 116 * Send a message with the specified object for {@link #handleSmsMessage}. 117 * @param obj the object to pass in the msg.obj field 118 */ dispatchSmsMessage(Object obj)119 public final void dispatchSmsMessage(Object obj) { 120 sendMessage(EVENT_NEW_SMS_MESSAGE, obj); 121 } 122 123 /** 124 * This parent state throws an exception (for debug builds) or prints an error for unhandled 125 * message types. 126 */ 127 class DefaultState extends State { 128 @Override processMessage(Message msg)129 public boolean processMessage(Message msg) { 130 switch (msg.what) { 131 default: { 132 String errorText = "processMessage: unhandled message type " + msg.what; 133 if (TelephonyUtils.IS_DEBUGGABLE) { 134 throw new RuntimeException(errorText); 135 } else { 136 loge(errorText); 137 } 138 break; 139 } 140 } 141 return HANDLED; 142 } 143 } 144 145 /** 146 * Idle state delivers Cell Broadcasts to receivers. It acquires the wakelock, which is 147 * released when the broadcast completes. 148 */ 149 class IdleState extends State { 150 @Override enter()151 public void enter() { 152 sendMessageDelayed(EVENT_RELEASE_WAKE_LOCK, WAKE_LOCK_TIMEOUT); 153 } 154 155 @Override exit()156 public void exit() { 157 mWakeLock.acquire(); 158 if (DBG) log("Idle: acquired wakelock, leaving Idle state"); 159 } 160 161 @Override processMessage(Message msg)162 public boolean processMessage(Message msg) { 163 switch (msg.what) { 164 case EVENT_NEW_SMS_MESSAGE: 165 log("Idle: new cell broadcast message"); 166 // transition to waiting state if we sent a broadcast 167 if (handleSmsMessage(msg)) { 168 transitionTo(mWaitingState); 169 } 170 return HANDLED; 171 172 case EVENT_RELEASE_WAKE_LOCK: 173 log("Idle: release wakelock"); 174 releaseWakeLock(); 175 return HANDLED; 176 177 case EVENT_BROADCAST_NOT_REQUIRED: 178 log("Idle: broadcast not required"); 179 return HANDLED; 180 181 default: 182 return NOT_HANDLED; 183 } 184 } 185 } 186 187 /** 188 * Waiting state waits for the result receiver to be called for the current cell broadcast. 189 * In this state, any new cell broadcasts are deferred until we return to Idle state. 190 */ 191 class WaitingState extends State { 192 @Override processMessage(Message msg)193 public boolean processMessage(Message msg) { 194 switch (msg.what) { 195 case EVENT_NEW_SMS_MESSAGE: 196 log("Waiting: deferring message until return to idle"); 197 deferMessage(msg); 198 return HANDLED; 199 200 case EVENT_BROADCAST_COMPLETE: 201 log("Waiting: broadcast complete, returning to idle"); 202 transitionTo(mIdleState); 203 return HANDLED; 204 205 case EVENT_RELEASE_WAKE_LOCK: 206 log("Waiting: release wakelock"); 207 releaseWakeLock(); 208 return HANDLED; 209 210 case EVENT_BROADCAST_NOT_REQUIRED: 211 log("Waiting: broadcast not required"); 212 if (mReceiverCount.get() == 0) { 213 transitionTo(mIdleState); 214 } 215 return HANDLED; 216 217 default: 218 return NOT_HANDLED; 219 } 220 } 221 } 222 223 /** 224 * Implemented by subclass to handle messages in {@link IdleState}. 225 * @param message the message to process 226 * @return true to transition to {@link WaitingState}; false to stay in {@link IdleState} 227 */ handleSmsMessage(Message message)228 protected abstract boolean handleSmsMessage(Message message); 229 230 /** 231 * BroadcastReceiver to send message to return to idle state. 232 */ 233 protected final BroadcastReceiver mReceiver = new BroadcastReceiver() { 234 @Override 235 public void onReceive(Context context, Intent intent) { 236 if (mReceiverCount.decrementAndGet() == 0) { 237 sendMessage(EVENT_BROADCAST_COMPLETE); 238 } 239 } 240 }; 241 242 /** 243 * Log with debug level. 244 * @param s the string to log 245 */ 246 @UnsupportedAppUsage 247 @Override log(String s)248 protected void log(String s) { 249 Rlog.d(getName(), s); 250 } 251 252 /** 253 * Log with error level. 254 * @param s the string to log 255 */ 256 @Override loge(String s)257 protected void loge(String s) { 258 Rlog.e(getName(), s); 259 } 260 261 /** 262 * Log with error level. 263 * @param s the string to log 264 * @param e is a Throwable which logs additional information. 265 */ 266 @Override loge(String s, Throwable e)267 protected void loge(String s, Throwable e) { 268 Rlog.e(getName(), s, e); 269 } 270 } 271