Add Radio Interface Capabilities
* Introduces a set of capabilities specific for the radio interface
that are determined by the vendor and are then surfaced through
TelephonyManager.
* There are no capabilities yet defined and will come later in S
* Modified the phone boot up process to read these from the HAL first
Test: Added cts, ran cts, and std tests
Test: Tested that the proper log messages on the device both
during boot up and cts (eg. the logs were just shown once)
Bug: 163085807
Merged-In: I5d213ccc7554a7be2c42f2b9cc23fb15577bab00
Change-Id: Ie75fab418c5db9d18af932ae7e4b82a3fad47c75
diff --git a/Android.bp b/Android.bp
index aff9f6a..9bdb15d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -84,6 +84,7 @@
"android.hardware.radio.config-V1.0-java-shallow",
"android.hardware.radio.config-V1.1-java-shallow",
"android.hardware.radio.config-V1.2-java-shallow",
+ "android.hardware.radio.config-V1.3-java-shallow",
"android.hardware.radio.deprecated-V1.0-java-shallow",
"ecc-protos-lite",
"libphonenumber-nogeocoder",
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index 03c6cbe..e68f8a9 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -19,16 +19,19 @@
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
import static android.telephony.TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncResult;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RegistrantList;
import android.os.storage.StorageManager;
import android.sysprop.TelephonyProperties;
import android.telephony.PhoneCapability;
+import android.telephony.RadioInterfaceCapabilities;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -56,6 +59,7 @@
private static final int EVENT_GET_MODEM_STATUS = 101;
private static final int EVENT_GET_MODEM_STATUS_DONE = 102;
private static final int EVENT_GET_PHONE_CAPABILITY_DONE = 103;
+ private static final int EVENT_GET_HAL_DEVICE_CAPABILITIES_DONE = 104;
private static PhoneConfigurationManager sInstance = null;
private final Context mContext;
@@ -69,6 +73,8 @@
private MockableInterface mMi = new MockableInterface();
private TelephonyManager mTelephonyManager;
private static final RegistrantList sMultiSimConfigChangeRegistrants = new RegistrantList();
+ private RadioInterfaceCapabilities mRadioInterfaceCapabilities;
+ private final Object mLockRadioInterfaceCapabilities = new Object();
/**
* Init method to instantiate the object
@@ -157,6 +163,7 @@
+ "No phone object provided for event " + msg.what);
}
getStaticPhoneCapability();
+ getRadioInterfaceCapabilities();
break;
case EVENT_SWITCH_DSDS_CONFIG_DONE:
ar = (AsyncResult) msg.obj;
@@ -186,6 +193,10 @@
} else {
log(msg.what + " failure. Not getting phone capability." + ar.exception);
}
+ break;
+ case EVENT_GET_HAL_DEVICE_CAPABILITIES_DONE:
+ setupRadioInterfaceCapabilities((AsyncResult) msg.obj);
+ break;
}
}
}
@@ -304,6 +315,51 @@
}
/**
+ * Gets the radio interface capabilities for the device
+ */
+ @NonNull
+ public synchronized RadioInterfaceCapabilities getRadioInterfaceCapabilities() {
+ if (mRadioInterfaceCapabilities == null) {
+ //Only incur cost of synchronization block if mRadioInterfaceCapabilities isn't null
+ synchronized (mLockRadioInterfaceCapabilities) {
+ if (mRadioInterfaceCapabilities == null) {
+ mRadioConfig.getHalDeviceCapabilities(
+ mHandler.obtainMessage(EVENT_GET_HAL_DEVICE_CAPABILITIES_DONE));
+ try {
+ if (Looper.myLooper() == this.mHandler.getLooper()) {
+ //Expected if this is called after the radio just turns on
+ log("getRadioInterfaceCapabilities: myLoop == handler.getLooper "
+ + "returning non-available capabilities.");
+ } else {
+ mLockRadioInterfaceCapabilities.wait(2000);
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+ if (mRadioInterfaceCapabilities == null) return new RadioInterfaceCapabilities();
+ else return mRadioInterfaceCapabilities;
+ }
+
+ private void setupRadioInterfaceCapabilities(@NonNull AsyncResult ar) {
+ if (mRadioInterfaceCapabilities == null) {
+ synchronized (mLockRadioInterfaceCapabilities) {
+ if (mRadioInterfaceCapabilities == null) {
+ if (ar.exception != null) {
+ loge("setupRadioInterfaceCapabilities: " + ar.exception);
+ }
+ log("setupRadioInterfaceCapabilities: "
+ + "mRadioInterfaceCapabilities now setup");
+
+ mRadioInterfaceCapabilities = (RadioInterfaceCapabilities) ar.result;
+ }
+ mLockRadioInterfaceCapabilities.notify();
+ }
+ }
+ }
+
+ /**
* get configuration related status of each phone.
*/
public PhoneCapability getCurrentPhoneCapability() {
@@ -497,4 +553,12 @@
private static void log(String s) {
Rlog.d(LOG_TAG, s);
}
+
+ private static void loge(String s) {
+ Rlog.e(LOG_TAG, s);
+ }
+
+ private static void loge(String s, Exception ex) {
+ Rlog.e(LOG_TAG, s, ex);
+ }
}
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index 3ee4d48..ac49f56 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -18,6 +18,7 @@
import static com.android.internal.telephony.RILConstants.RADIO_NOT_AVAILABLE;
import static com.android.internal.telephony.RILConstants.REQUEST_NOT_SUPPORTED;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PHONE_CAPABILITY;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLOT_STATUS;
import static com.android.internal.telephony.RILConstants
@@ -38,6 +39,7 @@
import android.os.Registrant;
import android.os.RemoteException;
import android.os.WorkSource;
+import android.telephony.RadioInterfaceCapabilities;
import android.util.SparseArray;
import com.android.internal.telephony.uicc.IccSlotStatus;
@@ -64,6 +66,8 @@
private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_1 = new HalVersion(1, 1);
+ private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_3 = new HalVersion(1, 3);
+
private final boolean mIsMobileNetworkSupported;
private volatile IRadioConfig mRadioConfigProxy = null;
// IRadioConfig version
@@ -194,14 +198,26 @@
private void updateRadioConfigProxy() {
try {
+
// Try to get service from different versions.
try {
- mRadioConfigProxy = android.hardware.radio.config.V1_1.IRadioConfig.getService(
+ mRadioConfigProxy = android.hardware.radio.config.V1_3.IRadioConfig.getService(
true);
- mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_1;
+ mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_3;
} catch (NoSuchElementException e) {
}
+
+ if (mRadioConfigProxy == null) {
+ // Try to get service from different versions.
+ try {
+ mRadioConfigProxy = android.hardware.radio.config.V1_1.IRadioConfig.getService(
+ true);
+ mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_1;
+ } catch (NoSuchElementException e) {
+ }
+ }
+
if (mRadioConfigProxy == null) {
try {
mRadioConfigProxy = android.hardware.radio.config.V1_0
@@ -273,6 +289,31 @@
}
/**
+ * This is a helper function to be called when a RadioConfigResponse callback is called.
+ * It finds and returns RILRequest corresponding to the response if one is found.
+ * @param responseInfo RadioResponseInfo received in response callback
+ * @return RILRequest corresponding to the response
+ */
+ public RILRequest processResponse_1_6(
+ android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
+ int serial = responseInfo.serial;
+ int error = responseInfo.error;
+ int type = responseInfo.type;
+
+ if (type != RadioResponseType.SOLICITED) {
+ loge("processResponse: Unexpected response type " + type);
+ }
+
+ RILRequest rr = findAndRemoveRequestFromList(serial);
+ if (rr == null) {
+ loge("processResponse: Unexpected response! serial: " + serial + " error: " + error);
+ return null;
+ }
+
+ return rr;
+ }
+
+ /**
* Wrapper function for IRadioConfig.getSimSlotsStatus().
*/
public void getSimSlotsStatus(Message result) {
@@ -403,6 +444,8 @@
return "SET_PREFERRED_DATA_MODEM";
case RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG:
return "SWITCH_DUAL_SIM_CONFIG";
+ case RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES:
+ return "GET_HAL_DEVICE_CAPABILITIES";
default:
return "<unknown request " + request + ">";
}
@@ -456,6 +499,46 @@
}
}
+ /**
+ * Gets the hal capabilities from the device.
+ */
+ public void getHalDeviceCapabilities(Message result) {
+ IRadioConfig radioConfigProxy = getRadioConfigProxy(result);
+ if (radioConfigProxy != null
+ && mRadioConfigVersion.greaterOrEqual(RADIO_CONFIG_HAL_VERSION_1_3)) {
+ android.hardware.radio.config.V1_3.IRadioConfig radioConfigProxy13 =
+ (android.hardware.radio.config.V1_3.IRadioConfig) radioConfigProxy;
+ RILRequest rr = obtainRequest(RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES,
+ result, mDefaultWorkSource);
+
+ if (DBG) {
+ logd(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+
+ try {
+ mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_3;
+ radioConfigProxy13.getHalDeviceCapabilities(rr.mSerial);
+
+ } catch (RemoteException | RuntimeException e) {
+ resetProxyAndRequestList("getHalDeviceCapabilities", e);
+ }
+ } else {
+ if (result != null) {
+ if (DBG) {
+ logd("RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES > REQUEST_NOT_SUPPORTED");
+ }
+ AsyncResult.forMessage(result, new RadioInterfaceCapabilities() /* send empty */,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ } else {
+ if (DBG) {
+ logd("RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES > REQUEST_NOT_SUPPORTED "
+ + "on complete message not set.");
+ }
+ }
+ }
+ }
+
static ArrayList<IccSlotStatus> convertHalSlotStatus(
ArrayList<android.hardware.radio.config.V1_0.SimSlotStatus> halSlotStatusList) {
ArrayList<IccSlotStatus> response = new ArrayList<IccSlotStatus>(halSlotStatusList.size());
diff --git a/src/java/com/android/internal/telephony/RadioConfigResponse.java b/src/java/com/android/internal/telephony/RadioConfigResponse.java
index 8e509de..096cdf6 100644
--- a/src/java/com/android/internal/telephony/RadioConfigResponse.java
+++ b/src/java/com/android/internal/telephony/RadioConfigResponse.java
@@ -19,12 +19,14 @@
import android.hardware.radio.V1_0.RadioError;
import android.hardware.radio.V1_0.RadioResponseInfo;
import android.hardware.radio.config.V1_1.ModemsConfig;
-import android.hardware.radio.config.V1_2.IRadioConfigResponse;
+import android.hardware.radio.config.V1_3.HalDeviceCapabilities;
+import android.hardware.radio.config.V1_3.IRadioConfigResponse;
import android.telephony.ModemInfo;
import android.telephony.PhoneCapability;
-import com.android.telephony.Rlog;
+import android.telephony.RadioInterfaceCapabilities;
import com.android.internal.telephony.uicc.IccSlotStatus;
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.List;
@@ -226,4 +228,40 @@
Rlog.e(TAG, "getModemsConfigResponse: Error " + responseInfo.toString());
}
}
+
+ /**
+ * Response function IRadioConfig.getHalDeviceCapabilities()
+ */
+ public void getHalDeviceCapabilitiesResponse(
+ android.hardware.radio.V1_6.RadioResponseInfo responseInfo,
+ HalDeviceCapabilities halDeviceCapabilities) {
+
+ //convert hal device capabilities to RadioInterfaceCapabilities
+
+ RILRequest rr = mRadioConfig.processResponse_1_6(responseInfo);
+ if (rr != null) {
+
+ RadioInterfaceCapabilities ret = new RadioInterfaceCapabilities();
+ /*
+ Code actual capabilities aren't ready yet, but it will look like this:
+ if (halDeviceCapability.cap1 == true) {
+ ret.addAvailableCapability(TelephonyManager.RADIO_INTERFACE_CAPABILITY_CAP1);
+ }
+ */
+
+ if (responseInfo.error == RadioError.NONE) {
+ // send response
+ RadioResponse.sendMessageResponse(rr.mResult, ret);
+ Rlog.d(TAG, rr.serialString() + "< "
+ + mRadioConfig.requestToString(rr.mRequest));
+ } else {
+ rr.onError(responseInfo.error, ret);
+ Rlog.e(TAG, rr.serialString() + "< "
+ + mRadioConfig.requestToString(rr.mRequest) + " error "
+ + responseInfo.error);
+ }
+ } else {
+ Rlog.e(TAG, "getHalDeviceCapabilities: Error " + responseInfo.toString());
+ }
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RadioInterfaceCapabilitiesTest.java b/tests/telephonytests/src/com/android/internal/telephony/RadioInterfaceCapabilitiesTest.java
new file mode 100644
index 0000000..ed52e37
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/RadioInterfaceCapabilitiesTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import static org.junit.Assert.assertTrue;
+
+import android.telephony.RadioInterfaceCapabilities;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RadioInterfaceCapabilitiesTest extends TelephonyTest {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testAddCapability() {
+ RadioInterfaceCapabilities cap = new RadioInterfaceCapabilities();
+ cap.addSupportedCapability("TEST ME");
+ assertTrue(cap.isSupported("TEST ME"));
+ }
+}