1 /*
2  * Copyright (C) 2012 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.bluetooth.btservice;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.os.Looper;
21 import android.os.Message;
22 import android.os.SystemProperties;
23 import android.util.Log;
24 
25 import com.android.bluetooth.flags.Flags;
26 import com.android.internal.util.State;
27 import com.android.internal.util.StateMachine;
28 
29 /**
30  * This state machine handles Bluetooth Adapter State. Stable States: {@link OffState}: Initial
31  * State {@link BleOnState} : Bluetooth Low Energy, Including GATT, is on {@link OnState} :
32  * Bluetooth is on (All supported profiles)
33  *
34  * <p>Transition States: {@link TurningBleOnState} : OffState to BleOnState {@link
35  * TurningBleOffState} : BleOnState to OffState {@link TurningOnState} : BleOnState to OnState
36  * {@link TurningOffState} : OnState to BleOnState
37  *
38  * <p>+------ Off <-----+ | | v | TurningBleOn TO---> TurningBleOff | ^ ^ | | | +-----> ----+ |
39  * BleOn | +------ <---+ O v | T TurningOn TO----> TurningOff | ^ | | +-----> On ------+
40  */
41 final class AdapterState extends StateMachine {
42     private static final String TAG = AdapterState.class.getSimpleName();
43 
44     static final int USER_TURN_ON = 1;
45     static final int USER_TURN_OFF = 2;
46     static final int BLE_TURN_ON = 3;
47     static final int BLE_TURN_OFF = 4;
48     static final int BREDR_STARTED = 5;
49     static final int BREDR_STOPPED = 6;
50     static final int BLE_STARTED = 7;
51     static final int BLE_STOPPED = 8;
52     static final int BREDR_START_TIMEOUT = 9;
53     static final int BREDR_STOP_TIMEOUT = 10;
54     static final int BLE_STOP_TIMEOUT = 11;
55     static final int BLE_START_TIMEOUT = 12;
56 
57     static final String BLE_START_TIMEOUT_DELAY_PROPERTY = "ro.bluetooth.ble_start_timeout_delay";
58     static final String BLE_STOP_TIMEOUT_DELAY_PROPERTY = "ro.bluetooth.ble_stop_timeout_delay";
59 
60     static final int BLE_START_TIMEOUT_DELAY =
61             4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1);
62     static final int BLE_STOP_TIMEOUT_DELAY =
63             4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1);
64     static final int BREDR_START_TIMEOUT_DELAY =
65             4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1);
66     static final int BREDR_STOP_TIMEOUT_DELAY =
67             4000 * SystemProperties.getInt("ro.hw_timeout_multiplier", 1);
68 
69     private AdapterService mAdapterService;
70     private TurningOnState mTurningOnState = new TurningOnState();
71     private TurningBleOnState mTurningBleOnState = new TurningBleOnState();
72     private TurningOffState mTurningOffState = new TurningOffState();
73     private TurningBleOffState mTurningBleOffState = new TurningBleOffState();
74     private OnState mOnState = new OnState();
75     private OffState mOffState = new OffState();
76     private BleOnState mBleOnState = new BleOnState();
77 
78     private int mPrevState = BluetoothAdapter.STATE_OFF;
79 
AdapterState(AdapterService service, Looper looper)80     AdapterState(AdapterService service, Looper looper) {
81         super(TAG, looper);
82         addState(mOnState);
83         addState(mBleOnState);
84         addState(mOffState);
85         addState(mTurningOnState);
86         addState(mTurningOffState);
87         addState(mTurningBleOnState);
88         addState(mTurningBleOffState);
89         mAdapterService = service;
90         setInitialState(mOffState);
91         start();
92     }
93 
messageString(int message)94     private String messageString(int message) {
95         switch (message) {
96             case BLE_TURN_ON:
97                 return "BLE_TURN_ON";
98             case USER_TURN_ON:
99                 return "USER_TURN_ON";
100             case BREDR_STARTED:
101                 return "BREDR_STARTED";
102             case BLE_STARTED:
103                 return "BLE_STARTED";
104             case USER_TURN_OFF:
105                 return "USER_TURN_OFF";
106             case BLE_TURN_OFF:
107                 return "BLE_TURN_OFF";
108             case BLE_STOPPED:
109                 return "BLE_STOPPED";
110             case BREDR_STOPPED:
111                 return "BREDR_STOPPED";
112             case BLE_START_TIMEOUT:
113                 return "BLE_START_TIMEOUT";
114             case BLE_STOP_TIMEOUT:
115                 return "BLE_STOP_TIMEOUT";
116             case BREDR_START_TIMEOUT:
117                 return "BREDR_START_TIMEOUT";
118             case BREDR_STOP_TIMEOUT:
119                 return "BREDR_STOP_TIMEOUT";
120             default:
121                 return "Unknown message (" + message + ")";
122         }
123     }
124 
doQuit()125     public void doQuit() {
126         quitNow();
127     }
128 
cleanup()129     private void cleanup() {
130         if (mAdapterService != null) {
131             mAdapterService = null;
132         }
133     }
134 
135     @Override
onQuitting()136     protected void onQuitting() {
137         cleanup();
138     }
139 
140     @Override
getLogRecString(Message msg)141     protected String getLogRecString(Message msg) {
142         return messageString(msg.what);
143     }
144 
145     private abstract class BaseAdapterState extends State {
146 
getStateValue()147         abstract int getStateValue();
148 
149         @Override
enter()150         public void enter() {
151             int currState = getStateValue();
152             infoLog("entered ");
153             mAdapterService.updateAdapterState(mPrevState, currState);
154             mPrevState = currState;
155         }
156 
infoLog(String msg)157         void infoLog(String msg) {
158             Log.i(TAG, BluetoothAdapter.nameForState(getStateValue()) + " : " + msg);
159         }
160 
errorLog(String msg)161         void errorLog(String msg) {
162             Log.e(TAG, BluetoothAdapter.nameForState(getStateValue()) + " : " + msg);
163         }
164     }
165 
166     private class OffState extends BaseAdapterState {
167 
168         @Override
getStateValue()169         int getStateValue() {
170             return BluetoothAdapter.STATE_OFF;
171         }
172 
173         @Override
enter()174         public void enter() {
175             if (!Flags.explicitKillFromSystemServer()) {
176                 super.enter();
177                 return;
178             }
179             int prevState = mPrevState;
180             super.enter();
181             if (prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
182                 mAdapterService.cleanup();
183             }
184         }
185 
186         @Override
processMessage(Message msg)187         public boolean processMessage(Message msg) {
188             switch (msg.what) {
189                 case BLE_TURN_ON:
190                     transitionTo(mTurningBleOnState);
191                     break;
192 
193                 default:
194                     infoLog("Unhandled message - " + messageString(msg.what));
195                     return false;
196             }
197             return true;
198         }
199     }
200 
201     private class BleOnState extends BaseAdapterState {
202 
203         @Override
getStateValue()204         int getStateValue() {
205             return BluetoothAdapter.STATE_BLE_ON;
206         }
207 
208         @Override
processMessage(Message msg)209         public boolean processMessage(Message msg) {
210             switch (msg.what) {
211                 case USER_TURN_ON:
212                     transitionTo(mTurningOnState);
213                     break;
214 
215                 case BLE_TURN_OFF:
216                     transitionTo(mTurningBleOffState);
217                     break;
218 
219                 default:
220                     infoLog("Unhandled message - " + messageString(msg.what));
221                     return false;
222             }
223             return true;
224         }
225     }
226 
227     private class OnState extends BaseAdapterState {
228 
229         @Override
getStateValue()230         int getStateValue() {
231             return BluetoothAdapter.STATE_ON;
232         }
233 
234         @Override
processMessage(Message msg)235         public boolean processMessage(Message msg) {
236             switch (msg.what) {
237                 case USER_TURN_OFF:
238                     transitionTo(mTurningOffState);
239                     break;
240 
241                 default:
242                     infoLog("Unhandled message - " + messageString(msg.what));
243                     return false;
244             }
245             return true;
246         }
247     }
248 
249     private class TurningBleOnState extends BaseAdapterState {
250 
251         @Override
getStateValue()252         int getStateValue() {
253             return BluetoothAdapter.STATE_BLE_TURNING_ON;
254         }
255 
256         @Override
enter()257         public void enter() {
258             super.enter();
259             final int timeoutDelay =
260                     SystemProperties.getInt(
261                             BLE_START_TIMEOUT_DELAY_PROPERTY, BLE_START_TIMEOUT_DELAY);
262             Log.d(TAG, "Start Timeout Delay: " + timeoutDelay);
263             sendMessageDelayed(BLE_START_TIMEOUT, timeoutDelay);
264             mAdapterService.bringUpBle();
265         }
266 
267         @Override
exit()268         public void exit() {
269             removeMessages(BLE_START_TIMEOUT);
270             super.exit();
271         }
272 
273         @Override
processMessage(Message msg)274         public boolean processMessage(Message msg) {
275             switch (msg.what) {
276                 case BLE_STARTED:
277                     transitionTo(mBleOnState);
278                     break;
279 
280                 case BLE_START_TIMEOUT:
281                     errorLog(messageString(msg.what));
282                     transitionTo(mTurningBleOffState);
283                     break;
284 
285                 default:
286                     infoLog("Unhandled message - " + messageString(msg.what));
287                     return false;
288             }
289             return true;
290         }
291     }
292 
293     private class TurningOnState extends BaseAdapterState {
294 
295         @Override
getStateValue()296         int getStateValue() {
297             return BluetoothAdapter.STATE_TURNING_ON;
298         }
299 
300         @Override
enter()301         public void enter() {
302             super.enter();
303             sendMessageDelayed(BREDR_START_TIMEOUT, BREDR_START_TIMEOUT_DELAY);
304             mAdapterService.startProfileServices();
305         }
306 
307         @Override
exit()308         public void exit() {
309             removeMessages(BREDR_START_TIMEOUT);
310             super.exit();
311         }
312 
313         @Override
processMessage(Message msg)314         public boolean processMessage(Message msg) {
315             switch (msg.what) {
316                 case BREDR_STARTED:
317                     transitionTo(mOnState);
318                     break;
319 
320                 case BREDR_START_TIMEOUT:
321                     errorLog(messageString(msg.what));
322                     transitionTo(mTurningOffState);
323                     break;
324 
325                 default:
326                     infoLog("Unhandled message - " + messageString(msg.what));
327                     return false;
328             }
329             return true;
330         }
331     }
332 
333     private class TurningOffState extends BaseAdapterState {
334 
335         @Override
getStateValue()336         int getStateValue() {
337             return BluetoothAdapter.STATE_TURNING_OFF;
338         }
339 
340         @Override
enter()341         public void enter() {
342             super.enter();
343             sendMessageDelayed(BREDR_STOP_TIMEOUT, BREDR_STOP_TIMEOUT_DELAY);
344             mAdapterService.stopProfileServices();
345         }
346 
347         @Override
exit()348         public void exit() {
349             removeMessages(BREDR_STOP_TIMEOUT);
350             super.exit();
351         }
352 
353         @Override
processMessage(Message msg)354         public boolean processMessage(Message msg) {
355             switch (msg.what) {
356                 case BREDR_STOPPED:
357                     transitionTo(mBleOnState);
358                     break;
359 
360                 case BREDR_STOP_TIMEOUT:
361                     errorLog(messageString(msg.what));
362                     transitionTo(mTurningBleOffState);
363                     break;
364 
365                 default:
366                     infoLog("Unhandled message - " + messageString(msg.what));
367                     return false;
368             }
369             return true;
370         }
371     }
372 
373     private class TurningBleOffState extends BaseAdapterState {
374 
375         @Override
getStateValue()376         int getStateValue() {
377             return BluetoothAdapter.STATE_BLE_TURNING_OFF;
378         }
379 
380         @Override
enter()381         public void enter() {
382             super.enter();
383             final int timeoutDelay =
384                     SystemProperties.getInt(
385                             BLE_STOP_TIMEOUT_DELAY_PROPERTY, BLE_STOP_TIMEOUT_DELAY);
386             Log.d(TAG, "Stop Timeout Delay: " + timeoutDelay);
387             sendMessageDelayed(BLE_STOP_TIMEOUT, timeoutDelay);
388             mAdapterService.bringDownBle();
389         }
390 
391         @Override
exit()392         public void exit() {
393             removeMessages(BLE_STOP_TIMEOUT);
394             super.exit();
395         }
396 
397         @Override
processMessage(Message msg)398         public boolean processMessage(Message msg) {
399             switch (msg.what) {
400                 case BLE_STOPPED:
401                     transitionTo(mOffState);
402                     break;
403 
404                 case BLE_STOP_TIMEOUT:
405                     errorLog(messageString(msg.what));
406                     transitionTo(mOffState);
407                     break;
408 
409                 default:
410                     infoLog("Unhandled message - " + messageString(msg.what));
411                     return false;
412             }
413             return true;
414         }
415     }
416 }
417