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