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