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

Commit a16b1ab3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "aosp-mock-modem-cts"

* changes:
  Fix phone crash for AIDL service die cases
  Fix phone crash by NullPointerException
  Fix phone crash by multiple result messages
  Add MockModem to bind/unbind the mock service with different interfaces
  Add API for MockModemService overriding mechanism
parents ef439d39 740c7679
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -2679,6 +2679,25 @@ public interface CommandsInterface {
     */
    default void getSlicingConfig(Message result) {};

    /**
     * Request to enable/disable the mock modem service.
     * This is used in shell commands during CTS testing only.
     *
     * @param serviceName the service name which telephony wants to bind to
     */
    default boolean setModemService(String serviceName) {
        return true;
    };

   /**
     * Return the class name of the currently bound modem service.
     *
     * @return the class name of the modem service.
     */
    default String getModemService() {
        return "default";
    };

   /**
     * Request the SIM phonebook records of all activated UICC applications
     *
+356 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;

import com.android.telephony.Rlog;

/** This class provides wrapper APIs for binding interfaces to mock service. */
public class MockModem {
    private static final String TAG = "MockModem";
    private static final String BIND_IRADIOMODEM = "android.telephony.cts.iradiomodem";
    private static final String BIND_IRADIOSIM = "android.telephony.cts.iradiosim";
    private static final String BIND_IRADIOMESSAGING = "android.telephony.cts.iradiomessaging";
    private static final String BIND_IRADIODATA = "android.telephony.cts.iradiodata";
    private static final String BIND_IRADIONETWORK = "android.telephony.cts.iradionetwork";
    private static final String BIND_IRADIOVOICE = "android.telephony.cts.iradiovoice";
    private static final String BIND_IRADIOCONFIG = "android.telephony.cts.iradioconfig";
    private static final String PHONE_ID = "phone_id";

    private static final byte DEFAULT_PHONE_ID = 0x00;

    static final int RADIOCONFIG_SERVICE = RIL.MAX_SERVICE_IDX + 1;

    static final int BINDER_RETRY_MILLIS = 3 * 100;
    static final int BINDER_MAX_RETRY = 3;

    private Context mContext;
    private String mServiceName;
    private String mPackageName;

    private IBinder mModemBinder;
    private IBinder mSimBinder;
    private IBinder mMessagingBinder;
    private IBinder mDataBinder;
    private IBinder mNetworkBinder;
    private IBinder mVoiceBinder;
    private IBinder mConfigBinder;
    private ServiceConnection mModemServiceConnection;
    private ServiceConnection mSimServiceConnection;
    private ServiceConnection mMessagingServiceConnection;
    private ServiceConnection mDataServiceConnection;
    private ServiceConnection mNetworkServiceConnection;
    private ServiceConnection mVoiceServiceConnection;
    private ServiceConnection mConfigServiceConnection;

    private byte mPhoneId;

    MockModem(Context context, String serviceName) {
        this(context, serviceName, 0);
    }

    MockModem(Context context, String serviceName, int phoneId) {
        mPhoneId = (byte) phoneId;
        mContext = context;
        mServiceName = serviceName;
        mPackageName = serviceName.substring(0, serviceName.lastIndexOf('.'));
    }

    private class MockModemConnection implements ServiceConnection {
        private int mService;

        MockModemConnection(int module) {
            mService = module;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            Rlog.d(TAG, "IRadio " + getModuleName(mService) + "  - onServiceConnected");

            if (mService == RIL.MODEM_SERVICE) {
                mModemBinder = binder;
            } else if (mService == RIL.SIM_SERVICE) {
                mSimBinder = binder;
            } else if (mService == RIL.MESSAGING_SERVICE) {
                mMessagingBinder = binder;
            } else if (mService == RIL.DATA_SERVICE) {
                mDataBinder = binder;
            } else if (mService == RIL.NETWORK_SERVICE) {
                mNetworkBinder = binder;
            } else if (mService == RIL.VOICE_SERVICE) {
                mVoiceBinder = binder;
            } else if (mService == RADIOCONFIG_SERVICE) {
                mConfigBinder = binder;
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Rlog.d(TAG, "IRadio " + getModuleName(mService) + "  - onServiceDisconnected");

            if (mService == RIL.MODEM_SERVICE) {
                mModemBinder = null;
            } else if (mService == RIL.SIM_SERVICE) {
                mSimBinder = null;
            } else if (mService == RIL.MESSAGING_SERVICE) {
                mMessagingBinder = null;
            } else if (mService == RIL.DATA_SERVICE) {
                mDataBinder = null;
            } else if (mService == RIL.NETWORK_SERVICE) {
                mNetworkBinder = null;
            } else if (mService == RIL.VOICE_SERVICE) {
                mVoiceBinder = null;
            } else if (mService == RADIOCONFIG_SERVICE) {
                mConfigBinder = null;
            }
        }
    }

    private boolean bindModuleToMockModemService(
            String actionName, ServiceConnection serviceConnection) {
        return bindModuleToMockModemService(DEFAULT_PHONE_ID, actionName, serviceConnection);
    }

    private boolean bindModuleToMockModemService(
            byte phoneId, String actionName, ServiceConnection serviceConnection) {
        boolean status = false;

        Intent intent = new Intent();
        intent.setClassName(mPackageName, mServiceName);
        intent.setAction(actionName);
        intent.putExtra(PHONE_ID, phoneId);

        status = mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
        return status;
    }

    /** waitForBinder */
    public IBinder getServiceBinder(int service) {
        switch (service) {
            case RIL.MODEM_SERVICE:
                return mModemBinder;
            case RIL.SIM_SERVICE:
                return mSimBinder;
            case RIL.MESSAGING_SERVICE:
                return mMessagingBinder;
            case RIL.DATA_SERVICE:
                return mDataBinder;
            case RIL.NETWORK_SERVICE:
                return mNetworkBinder;
            case RIL.VOICE_SERVICE:
                return mVoiceBinder;
            case RADIOCONFIG_SERVICE:
                return mConfigBinder;
            default:
                return null;
        }
    }

    /** Binding interfaces with mock modem service */
    public void bindAllMockModemService() {
        for (int service = RIL.MIN_SERVICE_IDX; service <= RIL.MAX_SERVICE_IDX; service++) {
            bindToMockModemService(service);
        }
    }

    /** bindToMockModemService */
    public void bindToMockModemService(int service) {
        if (service == RADIOCONFIG_SERVICE) {
            if (mConfigBinder == null) {
                mConfigServiceConnection = new MockModemConnection(RADIOCONFIG_SERVICE);

                boolean status =
                        bindModuleToMockModemService(BIND_IRADIOCONFIG, mConfigServiceConnection);
                if (!status) {
                    Rlog.d(TAG, "IRadio Config bind fail");
                    mConfigServiceConnection = null;
                }
            } else {
                Rlog.d(TAG, "IRadio Config is bound");
            }
        } else if (service == RIL.MODEM_SERVICE) {
            if (mModemBinder == null) {
                mModemServiceConnection = new MockModemConnection(RIL.MODEM_SERVICE);

                boolean status =
                        bindModuleToMockModemService(
                                mPhoneId, BIND_IRADIOMODEM, mModemServiceConnection);
                if (!status) {
                    Rlog.d(TAG, "IRadio Modem bind fail");
                    mModemServiceConnection = null;
                }
            } else {
                Rlog.d(TAG, "IRadio Modem is bound");
            }
        } else if (service == RIL.SIM_SERVICE) {
            if (mSimBinder == null) {
                mSimServiceConnection = new MockModemConnection(RIL.SIM_SERVICE);

                boolean status =
                        bindModuleToMockModemService(
                                mPhoneId, BIND_IRADIOSIM, mSimServiceConnection);
                if (!status) {
                    Rlog.d(TAG, "IRadio Sim bind fail");
                    mSimServiceConnection = null;
                }
            } else {
                Rlog.d(TAG, "IRadio Sim is bound");
            }
        } else if (service == RIL.MESSAGING_SERVICE) {
            if (mMessagingBinder == null) {
                mMessagingServiceConnection = new MockModemConnection(RIL.MESSAGING_SERVICE);

                boolean status =
                        bindModuleToMockModemService(
                                mPhoneId, BIND_IRADIOMESSAGING, mMessagingServiceConnection);
                if (!status) {
                    Rlog.d(TAG, "IRadio Messaging bind fail");
                    mMessagingServiceConnection = null;
                }
            } else {
                Rlog.d(TAG, "IRadio Messaging is bound");
            }
        } else if (service == RIL.DATA_SERVICE) {
            if (mDataBinder == null) {
                mDataServiceConnection = new MockModemConnection(RIL.DATA_SERVICE);

                boolean status =
                        bindModuleToMockModemService(
                                mPhoneId, BIND_IRADIODATA, mDataServiceConnection);
                if (!status) {
                    Rlog.d(TAG, "IRadio Data bind fail");
                    mDataServiceConnection = null;
                }
            } else {
                Rlog.d(TAG, "IRadio Data is bound");
            }
        } else if (service == RIL.NETWORK_SERVICE) {
            if (mNetworkBinder == null) {
                mNetworkServiceConnection = new MockModemConnection(RIL.NETWORK_SERVICE);

                boolean status =
                        bindModuleToMockModemService(
                                mPhoneId, BIND_IRADIONETWORK, mNetworkServiceConnection);
                if (!status) {
                    Rlog.d(TAG, "IRadio Network bind fail");
                    mNetworkServiceConnection = null;
                }
            } else {
                Rlog.d(TAG, "IRadio Network is bound");
            }
        } else if (service == RIL.VOICE_SERVICE) {
            if (mVoiceBinder == null) {
                mVoiceServiceConnection = new MockModemConnection(RIL.VOICE_SERVICE);

                boolean status =
                        bindModuleToMockModemService(
                                mPhoneId, BIND_IRADIOVOICE, mVoiceServiceConnection);
                if (!status) {
                    Rlog.d(TAG, "IRadio Voice bind fail");
                    mVoiceServiceConnection = null;
                }
            } else {
                Rlog.d(TAG, "IRadio Voice is bound");
            }
        }
    }

    /** unbindMockModemService */
    public void unbindMockModemService(int service) {

        if (service == RADIOCONFIG_SERVICE) {
            if (mConfigServiceConnection != null) {
                mContext.unbindService(mConfigServiceConnection);
                mConfigServiceConnection = null;
                mConfigBinder = null;
                Rlog.d(TAG, "unbind IRadio Config");
            }
        } else if (service == RIL.MODEM_SERVICE) {
            if (mModemServiceConnection != null) {
                mContext.unbindService(mModemServiceConnection);
                mModemServiceConnection = null;
                mModemBinder = null;
                Rlog.d(TAG, "unbind IRadio Modem");
            }
        } else if (service == RIL.SIM_SERVICE) {
            if (mSimServiceConnection != null) {
                mContext.unbindService(mSimServiceConnection);
                mSimServiceConnection = null;
                mSimBinder = null;
                Rlog.d(TAG, "unbind IRadio Sim");
            }
        } else if (service == RIL.MESSAGING_SERVICE) {
            if (mMessagingServiceConnection != null) {
                mContext.unbindService(mMessagingServiceConnection);
                mMessagingServiceConnection = null;
                mMessagingBinder = null;
                Rlog.d(TAG, "unbind IRadio Messaging");
            }
        } else if (service == RIL.DATA_SERVICE) {
            if (mDataServiceConnection != null) {
                mContext.unbindService(mDataServiceConnection);
                mDataServiceConnection = null;
                mDataBinder = null;
                Rlog.d(TAG, "unbind IRadio Data");
            }
        } else if (service == RIL.NETWORK_SERVICE) {
            if (mNetworkServiceConnection != null) {
                mContext.unbindService(mNetworkServiceConnection);
                mNetworkServiceConnection = null;
                mNetworkBinder = null;
                Rlog.d(TAG, "unbind IRadio Network");
            }
        } else if (service == RIL.VOICE_SERVICE) {
            if (mVoiceServiceConnection != null) {
                mContext.unbindService(mVoiceServiceConnection);
                mVoiceServiceConnection = null;
                mVoiceBinder = null;
                Rlog.d(TAG, "unbind IRadio Voice");
            }
        }
    }

    public String getServiceName() {
        return mServiceName;
    }

    private String getModuleName(int service) {
        switch (service) {
            case RIL.MODEM_SERVICE:
                return "modem";
            case RIL.SIM_SERVICE:
                return "sim";
            case RIL.MESSAGING_SERVICE:
                return "messaging";
            case RIL.DATA_SERVICE:
                return "data";
            case RIL.NETWORK_SERVICE:
                return "network";
            case RIL.VOICE_SERVICE:
                return "voice";
            case RADIOCONFIG_SERVICE:
                return "config";
            default:
                return "none";
        }
    }
}
+47 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ public class PhoneConfigurationManager {
    public static final String DSDS = "dsds";
    public static final String TSTS = "tsts";
    public static final String SSSS = "";
    public static final String CTS_MOCK_MODEM_SERVICE = "android.telephony.cts.MockModemService";
    private static final String LOG_TAG = "PhoneCfgMgr";
    private static final int EVENT_SWITCH_DSDS_CONFIG_DONE = 100;
    private static final int EVENT_GET_MODEM_STATUS = 101;
@@ -444,6 +445,52 @@ public class PhoneConfigurationManager {
        intent.putExtra(EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, numOfActiveModems);
        mContext.sendBroadcast(intent);
    }
    /**
     * This is invoked from shell commands during CTS testing only.
     * @return true if the modem service is set successfully, false otherwise.
     */
    public boolean setModemService(String serviceName) {
        if (mRadioConfig == null || mPhones[0] == null) {
            return false;
        }

        log("setModemService: " + serviceName);
        boolean statusRadioConfig = false;
        boolean statusRil = false;

        if (serviceName != null) {
            // Only CTS mock modem service is allowed to swith.
            if (!serviceName.equals(CTS_MOCK_MODEM_SERVICE)) {
                loge(serviceName + " is not allowed to switch");
                return false;
            }

            statusRadioConfig = mRadioConfig.setModemService(serviceName);

            //TODO: consider multi-sim case (b/210073692)
            statusRil = mPhones[0].mCi.setModemService(serviceName);
        } else {
            statusRadioConfig = mRadioConfig.setModemService(null);

            //TODO: consider multi-sim case
            statusRil = mPhones[0].mCi.setModemService(null);
        }

        return statusRadioConfig && statusRil;
    }

     /**
     * This is invoked from shell commands to query during CTS testing only.
     * @return the service name of the connected service.
     */
    public String getModemService() {
        //TODO: consider multi-sim case
        if (mPhones[0] == null) {
            return "";
        }

        return mPhones[0].mCi.getModemService();
    }

    /**
     * A wrapper class that wraps some methods so that they can be replaced or mocked in unit-tests.
+168 −46

File changed.

Preview size limit exceeded, changes collapsed.

+75 −5
Original line number Diff line number Diff line
@@ -57,7 +57,8 @@ public class RadioConfig extends Handler {
    private static final boolean VDBG = false; //STOPSHIP if true
    private static final Object sLock = new Object();

    static final int EVENT_SERVICE_DEAD = 1;
    static final int EVENT_HIDL_SERVICE_DEAD = 1;
    static final int EVENT_AIDL_SERVICE_DEAD = 2;
    static final HalVersion RADIO_CONFIG_HAL_VERSION_UNKNOWN = new HalVersion(-1, -1);
    static final HalVersion RADIO_CONFIG_HAL_VERSION_1_0 = new HalVersion(1, 0);
    static final HalVersion RADIO_CONFIG_HAL_VERSION_1_1 = new HalVersion(1, 1);
@@ -71,6 +72,8 @@ public class RadioConfig extends Handler {
    private final int[] mDeviceNrCapabilities;
    private final AtomicLong mRadioConfigProxyCookie = new AtomicLong(0);
    private final RadioConfigProxy mRadioConfigProxy;
    private MockModem mMockModem;
    private static Context sContext;

    private static RadioConfig sRadioConfig;

@@ -127,6 +130,7 @@ public class RadioConfig extends Handler {
            if (sRadioConfig != null) {
                throw new RuntimeException("RadioConfig.make() should only be called once");
            }
            sContext = c;
            sRadioConfig = new RadioConfig(c, radioHalVersion);
            return sRadioConfig;
        }
@@ -134,12 +138,16 @@ public class RadioConfig extends Handler {

    @Override
    public void handleMessage(Message message) {
        if (message.what == EVENT_SERVICE_DEAD) {
            logd("handleMessage: EVENT_SERVICE_DEAD cookie = " + message.obj
        if (message.what == EVENT_HIDL_SERVICE_DEAD) {
            logd("handleMessage: EVENT_HIDL_SERVICE_DEAD cookie = " + message.obj
                    + " mRadioConfigProxyCookie = " + mRadioConfigProxyCookie.get());
            if ((long) message.obj == mRadioConfigProxyCookie.get()) {
                resetProxyAndRequestList("EVENT_SERVICE_DEAD", null);
                resetProxyAndRequestList("EVENT_HIDL_SERVICE_DEAD", null);
            }
        } else if (message.what == EVENT_AIDL_SERVICE_DEAD) {
            logd("handleMessage: EVENT_AIDL_SERVICE_DEAD mRadioConfigProxyCookie = "
                    + mRadioConfigProxyCookie.get());
            resetProxyAndRequestList("EVENT_AIDL_SERVICE_DEAD", null);
        }
    }

@@ -215,9 +223,71 @@ public class RadioConfig extends Handler {
        return mRadioConfigProxy;
    }

    /**
     * Request to enable/disable the mock modem service.
     * This is invoked from shell commands during CTS testing only.
     *
     * @param serviceName the service name we want to bind to
     */
    public boolean setModemService(String serviceName) {
        boolean serviceBound = true;

        if (serviceName != null) {
            logd("Overriding connected service to MockModemService");
            mMockModem = null;

            mMockModem = new MockModem(sContext, serviceName);
            if (mMockModem == null) {
                loge("MockModem creation failed.");
                return false;
            }

            mMockModem.bindToMockModemService(MockModem.RADIOCONFIG_SERVICE);

            int retryCount = 0;
            IBinder binder;
            do {
                binder = mMockModem.getServiceBinder(MockModem.RADIOCONFIG_SERVICE);

                retryCount++;
                if (binder == null) {
                    logd("Retry(" + retryCount + ") Mock RadioConfig");
                    try {
                        Thread.sleep(MockModem.BINDER_RETRY_MILLIS);
                    } catch (InterruptedException e) {
                    }
                }
            } while ((binder == null) && (retryCount < MockModem.BINDER_MAX_RETRY));

            if (binder == null) {
                loge("Mock RadioConfig bind fail");
                serviceBound = false;
            }

            if (serviceBound) resetProxyAndRequestList("EVENT_HIDL_SERVICE_DEAD", null);
        }

        if ((serviceName == null) || (!serviceBound)) {
            if (serviceBound) logd("Unbinding to mock RadioConfig service");

            if (mMockModem != null) {
                mMockModem.unbindMockModemService(MockModem.RADIOCONFIG_SERVICE);
                mMockModem = null;
            }
        }

        return serviceBound;
    }

    private void updateRadioConfigProxy() {
        IBinder service = ServiceManager.waitForDeclaredService(
        IBinder service;
        if (mMockModem == null) {
            service = ServiceManager.waitForDeclaredService(
                android.hardware.radio.config.IRadioConfig.DESCRIPTOR + "/default");
        } else {
            // Binds to Mock RadioConfig Service
            service = mMockModem.getServiceBinder(MockModem.RADIOCONFIG_SERVICE);
        }

        if (service != null) {
            mRadioConfigProxy.setAidl(
Loading