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

Commit 2c6bdae4 authored by Jack Yu's avatar Jack Yu Committed by android-build-merger
Browse files

Merge "Added access networks manager"

am: 3ed84465

Change-Id: I422e8f47c4555cd674f1a13cf6c9ee276971e2ad
parents 94cf1192 3ed84465
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -230,6 +230,7 @@ public class GsmCdmaPhone extends Phone {

        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
        mDeviceStateMonitor = mTelephonyComponentFactory.makeDeviceStateMonitor(this);
        mAccessNetworksManager = mTelephonyComponentFactory.makeAccessNetworksManager(this);
        logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
    }

+2 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import com.android.ims.ImsCall;
import com.android.ims.ImsConfig;
import com.android.ims.ImsManager;
import com.android.internal.R;
import com.android.internal.telephony.dataconnection.AccessNetworksManager;
import com.android.internal.telephony.dataconnection.DataConnectionReasons;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
@@ -279,6 +280,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface {
    private final String mActionDetached;
    private final String mActionAttached;
    protected DeviceStateMonitor mDeviceStateMonitor;
    protected AccessNetworksManager mAccessNetworksManager;

    protected int mPhoneId;

+5 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.telephony.AccessNetworkConstants.TransportType;

import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriManager;
import com.android.internal.telephony.dataconnection.AccessNetworksManager;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
@@ -171,6 +172,10 @@ public class TelephonyComponentFactory {
        return new DeviceStateMonitor(phone);
    }

    public AccessNetworksManager makeAccessNetworksManager(Phone phone) {
        return new AccessNetworksManager(phone);
    }

    public CdmaSubscriptionSourceManager
    getCdmaSubscriptionSourceManagerInstance(Context context, CommandsInterface ci, Handler h,
                                             int what, Object obj) {
+285 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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.dataconnection;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.os.RegistrantList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.ApnType;
import android.telephony.data.IQualifiedNetworksService;
import android.telephony.data.IQualifiedNetworksServiceCallback;
import android.telephony.data.QualifiedNetworksService;
import android.text.TextUtils;
import android.util.SparseArray;

import com.android.internal.telephony.Phone;

import java.util.Arrays;

/**
 * Access network manager manages the qualified/available networks for mobile data connection.
 * It binds to the vendor's qualified networks service and actively monitors the qualified
 * networks changes.
 */
public class AccessNetworksManager {
    private static final String TAG = AccessNetworksManager.class.getSimpleName();
    private static final boolean DBG = false;

    private final Phone mPhone;

    private final CarrierConfigManager mCarrierConfigManager;

    private IQualifiedNetworksService mIQualifiedNetworksService;

    private AccessNetworksManagerDeathRecipient mDeathRecipient;

    // The bound qualified networks service component name
    private ComponentName mBoundQualifiedNetworksServiceComponent;

    private QualifiedNetworksServiceConnection mServiceConnection;

    private final SparseArray<int[]> mAvailableNetworks = new SparseArray<>();

    private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList();

    private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)
                    && mPhone.getPhoneId() == intent.getIntExtra(
                    CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) {
                // When carrier config changes, we need to evaluate and see if we should unbind
                // the existing service and bind to a new one.
                if (DBG) log("Carrier config changed.");
                bindQualifiedNetworksService();
            }
        }
    };

    /**
     * Represents qualified network types list on a specific APN type.
     */
    public static class QualifiedNetworks {
        @ApnType
        public final int apnType;
        public final int[] qualifiedNetworks;
        public QualifiedNetworks(@ApnType int apnType, int[] qualifiedNetworks) {
            this.apnType = apnType;
            this.qualifiedNetworks = qualifiedNetworks;
        }
    }

    private class AccessNetworksManagerDeathRecipient implements IBinder.DeathRecipient {
        @Override
        public void binderDied() {
            // TODO: try to rebind the service.
            loge("QualifiedNetworksService(" + mBoundQualifiedNetworksServiceComponent + ") died.");
        }
    }

    private final class QualifiedNetworksServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (DBG) log("onServiceConnected");
            mBoundQualifiedNetworksServiceComponent = name;
            mIQualifiedNetworksService = IQualifiedNetworksService.Stub.asInterface(service);
            mDeathRecipient = new AccessNetworksManagerDeathRecipient();

            try {
                service.linkToDeath(mDeathRecipient, 0 /* flags */);
                mIQualifiedNetworksService.createNetworkAvailabilityUpdater(mPhone.getPhoneId(),
                        new QualifiedNetworksServiceCallback());
            } catch (RemoteException e) {
                mDeathRecipient.binderDied();
                loge("Remote exception. " + e);
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            if (DBG) log("onServiceDisconnected");
            mIQualifiedNetworksService.asBinder().unlinkToDeath(mDeathRecipient, 0);
        }
    }

    private final class QualifiedNetworksServiceCallback extends
            IQualifiedNetworksServiceCallback.Stub {
        @Override
        public void onQualifiedNetworkTypesChanged(int apnType, int[] qualifiedNetworkTypesList) {
            log("onQualifiedNetworkTypesChanged. apnType = "
                    + ApnSetting.getApnTypesStringFromBitmask(apnType)
                    + ", networks = " + Arrays.toString(qualifiedNetworkTypesList));

            // TODO: Verify the preference from data settings manager to make sure the order
            // of the networks do not violate users/carrier's preference.
            if (mAvailableNetworks.get(apnType) != null) {
                if (Arrays.equals(mAvailableNetworks.get(apnType), qualifiedNetworkTypesList)) {
                    log("Available networks for "
                            + ApnSetting.getApnTypesStringFromBitmask(apnType) + " not changed.");
                    return;
                }
            }
            mAvailableNetworks.put(apnType, qualifiedNetworkTypesList);
            mQualifiedNetworksChangedRegistrants.notifyRegistrants(
                    new AsyncResult(null,
                            new QualifiedNetworks(apnType, qualifiedNetworkTypesList), null));
        }
    }

    /**
     * Constructor
     *
     * @param phone The phone object
     */
    public AccessNetworksManager(Phone phone) {
        mPhone = phone;
        mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService(
                Context.CARRIER_CONFIG_SERVICE);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        phone.getContext().registerReceiverAsUser(mConfigChangedReceiver, UserHandle.ALL,
                intentFilter, null, null);

        bindQualifiedNetworksService();
    }

    /**
     * Find the qualified network service from configuration and binds to it. It reads the
     * configuration from carrier config if it exists. If not, read it from resources.
     */
    private void bindQualifiedNetworksService() {
        String packageName = getQualifiedNetworksServicePackageName();

        if (DBG) log("Qualified network service package = " + packageName);
        if (TextUtils.isEmpty(packageName)) {
            loge("Can't find the binding package");
            return;
        }

        if (mIQualifiedNetworksService != null
                && mIQualifiedNetworksService.asBinder().isBinderAlive()) {
            if (mBoundQualifiedNetworksServiceComponent.getPackageName().equals(packageName)) {
                if (DBG) log("Service " + packageName + " already bound.");
                return;
            }

            // Remove the network availability updater and then unbind the service.
            try {
                mIQualifiedNetworksService.removeNetworkAvailabilityUpdater(mPhone.getPhoneId());
            } catch (RemoteException e) {
                loge("Cannot remove network availability updater. " + e);
            }

            mPhone.getContext().unbindService(mServiceConnection);
        }

        try {
            mServiceConnection = new QualifiedNetworksServiceConnection();
            log("bind to " + packageName);
            if (!mPhone.getContext().bindService(
                    new Intent(QualifiedNetworksService.QUALIFIED_NETWORKS_SERVICE_INTERFACE)
                            .setPackage(packageName),
                    mServiceConnection,
                    Context.BIND_AUTO_CREATE)) {
                loge("Cannot bind to the qualified networks service.");
            }
        } catch (Exception e) {
            loge("Cannot bind to the qualified networks service. Exception: " + e);
        }
    }

    /**
     * Get the qualified network service package.
     *
     * @return package name of the qualified networks service package. Return empty string when in
     * legacy mode (i.e. Dedicated IWLAN data/network service is not supported).
     */
    private String getQualifiedNetworksServicePackageName() {
        // Read package name from the resource
        String packageName = mPhone.getContext().getResources().getString(
                com.android.internal.R.string.config_qualified_networks_service_package);

        PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());

        if (b != null) {
            // If carrier config overrides it, use the one from carrier config
            String carrierConfigPackageName =  b.getString(CarrierConfigManager
                    .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING);
            if (!TextUtils.isEmpty(carrierConfigPackageName)) {
                if (DBG) log("Found carrier config override " + carrierConfigPackageName);
                packageName = carrierConfigPackageName;
            }
        }

        return packageName;
    }

    /**
     * Register for qualified networks changed event.
     *
     * @param h The target to post the event message to.
     * @param what The event.
     */
    public void registerForQualifiedNetworksChanged(Handler h, int what) {
        if (h != null) {
            mQualifiedNetworksChangedRegistrants.addUnique(h, what, null);
        }
    }

    /**
     * Unregister for qualified networks changed event.
     *
     * @param h The handler
     */
    public void unregisterForQualifiedNetworksChanged(Handler h) {
        if (h != null) {
            mQualifiedNetworksChangedRegistrants.remove(h);
        }
    }

    /**
     * @return True if IWLAN legacy mode is used. No qualified network service there to provide
     * information for platform to setup data connection. All data connection requests will be
     * routed to the default (i.e. cellular) data/network service.
     */
    public boolean isInLegacyMode() {
        return TextUtils.isEmpty(getQualifiedNetworksServicePackageName());
    }

    private void log(String s) {
        Rlog.d(TAG, s);
    }

    private void loge(String s) {
        Rlog.e(TAG, s);
    }

}
+5 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import com.android.ims.ImsEcbm;
import com.android.ims.ImsManager;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriManager;
import com.android.internal.telephony.dataconnection.AccessNetworksManager;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
@@ -190,6 +191,8 @@ public abstract class TelephonyTest {
    @Mock
    protected DeviceStateMonitor mDeviceStateMonitor;
    @Mock
    protected AccessNetworksManager mAccessNetworksManager;
    @Mock
    protected IntentBroadcaster mIntentBroadcaster;
    @Mock
    protected NitzStateMachine mNitzStateMachine;
@@ -371,6 +374,8 @@ public abstract class TelephonyTest {
                .makeCarrierActionAgent(nullable(Phone.class));
        doReturn(mDeviceStateMonitor).when(mTelephonyComponentFactory)
                .makeDeviceStateMonitor(nullable(Phone.class));
        doReturn(mAccessNetworksManager).when(mTelephonyComponentFactory)
                .makeAccessNetworksManager(nullable(Phone.class));
        doReturn(mNitzStateMachine).when(mTelephonyComponentFactory)
                .makeNitzStateMachine(nullable(GsmCdmaPhone.class));
        doReturn(mLocaleTracker).when(mTelephonyComponentFactory)