Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 074b759f authored by Daniel Bright's avatar Daniel Bright
Browse files

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
Change-Id: I5d213ccc7554a7be2c42f2b9cc23fb15577bab00
parent 0b3566ff
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ java_library {
        "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",
+64 −0
Original line number Diff line number Diff line
@@ -19,16 +19,19 @@ package com.android.internal.telephony;
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 @@ public class PhoneConfigurationManager {
    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 @@ public class PhoneConfigurationManager {
    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 @@ public class PhoneConfigurationManager {
                                + "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 @@ public class PhoneConfigurationManager {
                    } else {
                        log(msg.what + " failure. Not getting phone capability." + ar.exception);
                    }
                    break;
                case EVENT_GET_HAL_DEVICE_CAPABILITIES_DONE:
                    setupRadioInterfaceCapabilities((AsyncResult) msg.obj);
                    break;
            }
        }
    }
@@ -303,6 +314,51 @@ public class PhoneConfigurationManager {
        return mStaticCapability;
    }

    /**
     * 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.
     */
@@ -497,4 +553,12 @@ public class PhoneConfigurationManager {
    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);
    }
}
+85 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.telephony;

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.Message;
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 @@ public class RadioConfig extends Handler {

    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,6 +198,17 @@ public class RadioConfig extends Handler {

    private void updateRadioConfigProxy() {
        try {

            // Try to get service from different versions.
            try {
                mRadioConfigProxy = android.hardware.radio.config.V1_3.IRadioConfig.getService(
                        true);
                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(
@@ -201,6 +216,7 @@ public class RadioConfig extends Handler {
                    mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_1;
                } catch (NoSuchElementException e) {
                }
            }

            if (mRadioConfigProxy == null) {
                try {
@@ -272,6 +288,31 @@ public class RadioConfig extends Handler {
        return rr;
    }

    /**
     * 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().
     */
@@ -403,6 +444,8 @@ public class RadioConfig extends Handler {
                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 @@ public class RadioConfig extends Handler {
        }
    }

    /**
     * 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());
+40 −2
Original line number Diff line number Diff line
@@ -19,12 +19,14 @@ package com.android.internal.telephony;
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 @@ public class RadioConfigResponse extends IRadioConfigResponse.Stub {
            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());
        }
    }
}
+44 −0
Original line number Diff line number Diff line
/*
 * 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"));
    }
}