• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.annotation.NonNull;
20 import android.os.AsyncResult;
21 import android.os.Handler;
22 import android.os.HandlerThread;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.util.ArraySet;
26 import android.util.Log;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.telephony.Rlog;
30 
31 import java.util.Collections;
32 import java.util.Set;
33 
34 /**
35  * Provides the capabilities that the Radio Interface supports on the current device.
36  */
37 public class RadioInterfaceCapabilityController extends Handler {
38     private static final String LOG_TAG =
39             RadioInterfaceCapabilityController.class.getSimpleName();
40 
41     private static RadioInterfaceCapabilityController sInstance;
42     private final RadioConfig mRadioConfig;
43     private final CommandsInterface mCommandsInterface;
44     private Set<String> mRadioInterfaceCapabilities;
45     private final Object mLockRadioInterfaceCapabilities = new Object();
46     private static final int EVENT_GET_HAL_DEVICE_CAPABILITIES_DONE = 100;
47 
48     /**
49      * Init method to instantiate the object
50      * Should only be called once.
51      */
init(final RadioConfig radioConfig, final CommandsInterface commandsInterface)52     public static RadioInterfaceCapabilityController init(final RadioConfig radioConfig,
53             final CommandsInterface commandsInterface) {
54         synchronized (RadioInterfaceCapabilityController.class) {
55             if (sInstance == null) {
56                 final HandlerThread handlerThread = new HandlerThread("RHC");
57                 handlerThread.start();
58                 sInstance = new RadioInterfaceCapabilityController(radioConfig, commandsInterface,
59                         handlerThread.getLooper());
60             } else {
61                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
62             }
63             return sInstance;
64         }
65     }
66 
67     /**
68      * Static method to get instance.
69      */
getInstance()70     public static RadioInterfaceCapabilityController getInstance() {
71         if (sInstance == null) {
72             Log.wtf(LOG_TAG, "getInstance null");
73         }
74 
75         return sInstance;
76     }
77 
78     @VisibleForTesting
RadioInterfaceCapabilityController(final RadioConfig radioConfig, final CommandsInterface commandsInterface, final Looper looper)79     public RadioInterfaceCapabilityController(final RadioConfig radioConfig,
80             final CommandsInterface commandsInterface, final Looper looper) {
81         super(looper);
82         mRadioConfig = radioConfig;
83         mCommandsInterface = commandsInterface;
84         register();
85     }
86 
87     /**
88      * Gets the radio interface capabilities for the device
89      */
90     @NonNull
getCapabilities()91     public Set<String> getCapabilities() {
92         if (mRadioInterfaceCapabilities == null) {
93             // Only incur cost of synchronization block if mRadioInterfaceCapabilities isn't null
94             synchronized (mLockRadioInterfaceCapabilities) {
95                 if (mRadioInterfaceCapabilities == null) {
96                     mRadioConfig.getHalDeviceCapabilities(
97                             obtainMessage(EVENT_GET_HAL_DEVICE_CAPABILITIES_DONE));
98                     try {
99                         if (Looper.myLooper() != getLooper()) {
100                             mLockRadioInterfaceCapabilities.wait(2000);
101                         }
102                     } catch (final InterruptedException ignored) {
103                     }
104 
105                     if (mRadioInterfaceCapabilities == null) {
106                         loge("getRadioInterfaceCapabilities: Radio Capabilities not "
107                                 + "loaded in time");
108                         return new ArraySet<>();
109                     }
110                 }
111             }
112         }
113         return mRadioInterfaceCapabilities;
114     }
115 
setupCapabilities(final @NonNull AsyncResult ar)116     private void setupCapabilities(final @NonNull AsyncResult ar) {
117         if (mRadioInterfaceCapabilities == null) {
118             synchronized (mLockRadioInterfaceCapabilities) {
119                 if (mRadioInterfaceCapabilities == null) {
120                     if (ar.exception != null) {
121                         loge("setupRadioInterfaceCapabilities: " + ar.exception);
122                     }
123                     if (ar.result == null) {
124                         loge("setupRadioInterfaceCapabilities: ar.result is null");
125                         return;
126                     }
127                     log("setupRadioInterfaceCapabilities: "
128                             + "mRadioInterfaceCapabilities now setup");
129                     mRadioInterfaceCapabilities =
130                             Collections.unmodifiableSet((Set<String>) ar.result);
131                     if (mRadioInterfaceCapabilities != null) {
132                         unregister();
133                     }
134                 }
135                 mLockRadioInterfaceCapabilities.notify();
136             }
137         }
138     }
139 
register()140     private void register() {
141         // There is no radio HAL, capabilities are irrelevant in this case.
142         if (mCommandsInterface == null) {
143             mRadioInterfaceCapabilities = Collections.unmodifiableSet(new ArraySet<>());
144             return;
145         }
146 
147         mCommandsInterface.registerForAvailable(this, Phone.EVENT_RADIO_AVAILABLE, null);
148     }
149 
unregister()150     private void unregister() {
151         mCommandsInterface.unregisterForAvailable(this);
152     }
153 
154     @Override
handleMessage(final Message msg)155     public void handleMessage(final Message msg) {
156         switch (msg.what) {
157             case Phone.EVENT_RADIO_AVAILABLE:
158             case Phone.EVENT_RADIO_ON:
159                 getCapabilities();
160                 break;
161             case EVENT_GET_HAL_DEVICE_CAPABILITIES_DONE:
162                 setupCapabilities((AsyncResult) msg.obj);
163                 break;
164         }
165     }
166 
log(final String s)167     private static void log(final String s) {
168         Rlog.d(LOG_TAG, s);
169     }
170 
loge(final String s)171     private static void loge(final String s) {
172         Rlog.e(LOG_TAG, s);
173     }
174 }
175