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

Commit 34a09a4c authored by Jack Yu's avatar Jack Yu
Browse files

Refactored precise data connection state

Instead of triggering the data connection state changed
event from outside, now the event is triggering from
DataConnection. Whenever detecting data connection
state changes, the event will be triggered. This significantly
reduced the unnecessary redundant events sent to telephony registry,
even though it has a duplicate detection mechanism.

This are also two behavioral changes.

1. Previously if a data connection supports multiple APN types,
there will be multiple data connection state changed event for
each APN type. Now there is only one. The listener should use
PreciseDataConnectionState.getApnSetting().getApnTypeBitmask()
to check which APN types this data connection supports.

2. If setup data call fails before a data connection instance
can be created, there won't be any event with fail cause.

Fix: 161572838
Test: FrameworksTelephonyTests and manual
Change-Id: I9723d5284c2a8fbae9f63179dc30ddc42da1d0fc
parent fe59b726
Loading
Loading
Loading
Loading
+3 −26
Original line number Diff line number Diff line
@@ -26,10 +26,8 @@ import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.CallState;
import android.telephony.Annotation.DataActivityType;
import android.telephony.Annotation.DataFailureCause;
import android.telephony.Annotation.DisconnectCauses;
import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.PreciseCallStates;
@@ -37,7 +35,6 @@ import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.util.Log;
@@ -402,17 +399,16 @@ public class TelephonyRegistryManager {
     * @param subId for which data connection state changed.
     * @param slotIndex for which data connections state changed. Can be derived from subId except
     * when subId is invalid.
     * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
     * @param preciseState the PreciseDataConnectionState
     *
     * @see android.telephony.PreciseDataConnection
     * @see PreciseDataConnectionState
     * @see TelephonyManager#DATA_DISCONNECTED
     */
    public void notifyDataConnectionForSubscriber(int slotIndex, int subId,
            @ApnType int apnType, @Nullable PreciseDataConnectionState preciseState) {
            @NonNull PreciseDataConnectionState preciseState) {
        try {
            sRegistry.notifyDataConnectionForSubscriber(
                    slotIndex, subId, apnType, preciseState);
                    slotIndex, subId, preciseState);
        } catch (RemoteException ex) {
            // system process is dead
        }
@@ -611,25 +607,6 @@ public class TelephonyRegistryManager {
        }
    }

    /**
     * Notify precise data connection failed cause on certain subscription.
     *
     * @param subId for which data connection failed.
     * @param slotIndex for which data conenction failed. Can be derived from subId except when
     * subId is invalid.
     * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
     * @param apn the APN {@link ApnSetting#getApnName()} of this data connection.
     * @param failCause data fail cause.
     */
    public void notifyPreciseDataConnectionFailed(int subId, int slotIndex, @ApnType int apnType,
            @Nullable String apn, @DataFailureCause int failCause) {
        try {
            sRegistry.notifyPreciseDataConnectionFailed(slotIndex, subId, apnType, apn, failCause);
        } catch (RemoteException ex) {
            // system process is dead
        }
    }

    /**
     * Notify single Radio Voice Call Continuity (SRVCC) state change for the currently active call
     * on certain subscription.
+1 −5
Original line number Diff line number Diff line
@@ -65,9 +65,7 @@ interface ITelephonyRegistry {
    void notifyDataActivity(int state);
    void notifyDataActivityForSubscriber(in int subId, int state);
    void notifyDataConnectionForSubscriber(
            int phoneId, int subId, int apnType, in PreciseDataConnectionState preciseState);
    @UnsupportedAppUsage
    void notifyDataConnectionFailed(String apnType);
            int phoneId, int subId, in PreciseDataConnectionState preciseState);
    // Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
    void notifyCellLocation(in CellIdentity cellLocation);
    void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
@@ -77,8 +75,6 @@ interface ITelephonyRegistry {
            int foregroundCallState, int backgroundCallState);
    void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
            int preciseDisconnectCause);
    void notifyPreciseDataConnectionFailed(int phoneId, int subId, int apnType, String apn,
            int failCause);
    void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
    void notifySrvccStateChanged(in int subId, in int lteState);
    void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
+46 −129
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.LinkProperties;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -46,8 +45,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telephony.Annotation;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.DataFailureCause;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState;
import android.telephony.BarringInfo;
@@ -80,7 +77,9 @@ import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Pair;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
@@ -103,6 +102,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;

/**
 * Since phone process can be restarted, this class provides a centralized place
@@ -302,13 +302,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
    @RadioPowerState
    private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;

    private final LocalLog mLocalLog = new LocalLog(100);
    private final LocalLog mLocalLog = new LocalLog(200);

    private final LocalLog mListenLog = new LocalLog(100);
    private final LocalLog mListenLog = new LocalLog(00);

    // Per-phoneMap of APN Type to DataConnectionState
    private List<Map<Integer, PreciseDataConnectionState>> mPreciseDataConnectionStates =
            new ArrayList<Map<Integer, PreciseDataConnectionState>>();
    /**
     * Per-phone map of precise data connection state. The key of the map is the pair of transport
     * type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
     * A precise data connection with state {@link TelephonyManager#DATA_DISCONNECTED} removes
     * its entry from the map.
     */
    private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
            mPreciseDataConnectionStates;

    static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
            PhoneStateListener.LISTEN_REGISTRATION_FAILURE
@@ -521,7 +526,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
            mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
            mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
            mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
            mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
            mPreciseDataConnectionStates.add(new ArrayMap<>());
            mBarringInfo.add(i, new BarringInfo());
            mTelephonyDisplayInfos[i] = null;
        }
@@ -610,7 +615,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
            mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
            mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
            mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
            mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
            mPreciseDataConnectionStates.add(new ArrayMap<>());
            mBarringInfo.add(i, new BarringInfo());
            mTelephonyDisplayInfos[i] = null;
        }
@@ -1687,38 +1692,25 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
     *
     * @param phoneId the phoneId carrying the data connection
     * @param subId the subscriptionId for the data connection
     * @param apnType the apn type bitmask, defined with {@code ApnSetting#TYPE_*} flags.
     * @param preciseState a PreciseDataConnectionState that has info about the data connection
     */
    @Override
    public void notifyDataConnectionForSubscriber(
            int phoneId, int subId, @ApnType int apnType, PreciseDataConnectionState preciseState) {
    public void notifyDataConnectionForSubscriber(int phoneId, int subId,
            @NonNull PreciseDataConnectionState preciseState) {
        if (!checkNotifyPermission("notifyDataConnection()" )) {
            return;
        }

        String apn = "";
        int state = TelephonyManager.DATA_UNKNOWN;
        int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
        LinkProperties linkProps = null;
        ApnSetting apnSetting = preciseState.getApnSetting();

        if (preciseState != null) {
            apn = preciseState.getDataConnectionApn();
            state = preciseState.getState();
            networkType = preciseState.getNetworkType();
            linkProps = preciseState.getLinkProperties();
        }
        if (VDBG) {
            log("notifyDataConnectionForSubscriber: subId=" + subId
                    + " state=" + state + "' apn='" + apn
                    + "' apnType=" + apnType + " networkType=" + networkType
                    + "' preciseState=" + preciseState);
        }
        int apnTypes = apnSetting.getApnTypeBitmask();
        int state = preciseState.getState();
        int networkType = preciseState.getNetworkType();

        synchronized (mRecords) {
            if (validatePhoneId(phoneId)) {
                // We only call the callback when the change is for default APN type.
                if ((ApnSetting.TYPE_DEFAULT & apnType) != 0
                if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0
                        && (mDataConnectionState[phoneId] != state
                        || mDataConnectionNetworkType[phoneId] != networkType)) {
                    String str = "onDataConnectionStateChanged("
@@ -1747,19 +1739,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
                    mDataConnectionNetworkType[phoneId] = networkType;
                }

                boolean needsNotify = false;
                // State has been cleared for this APN Type
                if (preciseState == null) {
                    // We try clear the state and check if the state was previously not cleared
                    needsNotify = mPreciseDataConnectionStates.get(phoneId).remove(apnType) != null;
                } else {
                    // We need to check to see if the state actually changed
                    PreciseDataConnectionState oldPreciseState =
                            mPreciseDataConnectionStates.get(phoneId).put(apnType, preciseState);
                    needsNotify = !preciseState.equals(oldPreciseState);
                }

                if (needsNotify) {
                Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
                        preciseState.getApnSetting());
                PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
                        .remove(key);
                if (!Objects.equals(oldState, preciseState)) {
                    for (Record r : mRecords) {
                        if (r.matchPhoneStateListenerEvent(
                                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
@@ -1771,57 +1755,25 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
                            }
                        }
                    }
                }
            }
                    handleRemoveListLocked();
        }

        broadcastDataConnectionStateChanged(state, apn, apnType, subId);
    }
                    broadcastDataConnectionStateChanged(phoneId, subId, preciseState);

    /**
     * Stub to satisfy the ITelephonyRegistry aidl interface; do not use this function.
     * @see #notifyDataConnectionFailedForSubscriber
     */
    public void notifyDataConnectionFailed(String apnType) {
        loge("This function should not be invoked");
                    String str = "notifyDataConnectionForSubscriber: phoneId=" + phoneId + " subId="
                            + subId + " " + preciseState;
                    log(str);
                    mLocalLog.log(str);
                }

    private void notifyDataConnectionFailedForSubscriber(int phoneId, int subId, int apnType) {
        if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
            return;
        }
        if (VDBG) {
            log("notifyDataConnectionFailedForSubscriber: subId=" + subId
                    + " apnType=" + apnType);
        }
        synchronized (mRecords) {
            if (validatePhoneId(phoneId)) {
                mPreciseDataConnectionStates.get(phoneId).put(
                        apnType,
                        new PreciseDataConnectionState.Builder()
                                .setApnSetting(new ApnSetting.Builder()
                                        .setApnTypeBitmask(apnType)
                                        .build())
                                .build());
                for (Record r : mRecords) {
                    if (r.matchPhoneStateListenerEvent(
                            PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
                            && idMatch(r.subId, subId, phoneId)) {
                        try {
                            r.callback.onPreciseDataConnectionStateChanged(
                                    mPreciseDataConnectionStates.get(phoneId).get(apnType));
                        } catch (RemoteException ex) {
                            mRemoveList.add(r.binder);
                // If the state is disconnected, it would be the end of life cycle of a data
                // connection, so remove it from the cache.
                if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) {
                    mPreciseDataConnectionStates.get(phoneId).put(key, preciseState);
                }
            }
        }
    }

            handleRemoveListLocked();
        }
    }

    @Override
    public void notifyCellLocation(CellIdentity cellLocation) {
        notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation);
@@ -1971,43 +1923,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
        }
    }

    @Override
    public void notifyPreciseDataConnectionFailed(int phoneId, int subId, @ApnType int apnType,
            String apn, @DataFailureCause int failCause) {
        if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
            return;
        }

        // precise notify invokes imprecise notify
        notifyDataConnectionFailedForSubscriber(phoneId, subId, apnType);

        synchronized (mRecords) {
            if (validatePhoneId(phoneId)) {
                mPreciseDataConnectionStates.get(phoneId).put(
                        apnType,
                        new PreciseDataConnectionState.Builder()
                                .setApnSetting(new ApnSetting.Builder()
                                        .setApnTypeBitmask(apnType)
                                        .build())
                                .setFailCause(failCause)
                                .build());
                for (Record r : mRecords) {
                    if (r.matchPhoneStateListenerEvent(
                            PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
                            && idMatch(r.subId, subId, phoneId)) {
                        try {
                            r.callback.onPreciseDataConnectionStateChanged(
                                    mPreciseDataConnectionStates.get(phoneId).get(apnType));
                        } catch (RemoteException ex) {
                            mRemoveList.add(r.binder);
                        }
                    }
                }
            }
            handleRemoveListLocked();
        }
    }

    @Override
    public void notifySrvccStateChanged(int subId, @SrvccState int state) {
        if (!checkNotifyPermission("notifySrvccStateChanged()")) {
@@ -2578,16 +2493,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
        }
    }

    private void broadcastDataConnectionStateChanged(int state, String apn,
                                                     int apnType, int subId) {
    private void broadcastDataConnectionStateChanged(int slotIndex, int subId,
            @NonNull PreciseDataConnectionState pdcs) {
        // Note: not reporting to the battery stats service here, because the
        // status bar takes care of that after taking into account all of the
        // required info.
        Intent intent = new Intent(ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
        intent.putExtra(PHONE_CONSTANTS_STATE_KEY, TelephonyUtils.dataStateToString(state));
        intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, apn);
        intent.putExtra(PHONE_CONSTANTS_STATE_KEY,
                TelephonyUtils.dataStateToString(pdcs.getState()));
        intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, pdcs.getApnSetting().getApnName());
        intent.putExtra(PHONE_CONSTANTS_DATA_APN_TYPE_KEY,
                ApnSetting.getApnTypesStringFromBitmask(apnType));
                ApnSetting.getApnTypesStringFromBitmask(pdcs.getApnSetting().getApnTypeBitmask()));
        intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, slotIndex);
        intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE);
    }
@@ -2973,7 +2890,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
    /**
     * Returns a string representation of the radio technology (network type)
     * currently in use on the device.
     * @param subId for which network type is returned
     * @param type for which network type is returned
     * @return the name of the radio technology
     *
     */
+13 −11
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ import android.telephony.Annotation.NetworkType;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;

import com.android.internal.telephony.util.TelephonyUtils;

import java.util.Objects;


@@ -82,6 +84,7 @@ public final class PreciseDataConnectionState implements Parcelable {
                linkProperties, failCause, new ApnSetting.Builder()
                        .setApnTypeBitmask(apnTypes)
                        .setApnName(apn)
                        .setEntryName(apn)
                        .build());
    }

@@ -254,7 +257,9 @@ public final class PreciseDataConnectionState implements Parcelable {
    /**
     * Return the APN Settings for this data connection.
     *
     * @return the ApnSetting that was used to configure this data connection.
     * @return the ApnSetting that was used to configure this data connection. Note that a data
     * connection cannot be established without a valid {@link ApnSetting}. The return value would
     * never be {@code null} even though it has {@link Nullable} annotation.
     */
    public @Nullable ApnSetting getApnSetting() {
        return mApnSetting;
@@ -314,17 +319,14 @@ public final class PreciseDataConnectionState implements Parcelable {
    public String toString() {
        StringBuilder sb = new StringBuilder();

        sb.append("Data Connection state: " + mState);
        sb.append(", Transport type: "
        sb.append(" state: " + TelephonyUtils.dataStateToString(mState));
        sb.append(", transport: "
                + AccessNetworkConstants.transportTypeToString(mTransportType));
        sb.append(", Id: " + mId);
        sb.append(", Network type: " + mNetworkType);
        sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(
                getDataConnectionApnTypeBitMask()));
        sb.append(", APN: " + getDataConnectionApn());
        sb.append(", Link properties: " + mLinkProperties);
        sb.append(", Fail cause: " + DataFailCause.toString(mFailCause));
        sb.append(", Apn Setting: " + mApnSetting);
        sb.append(", id: " + mId);
        sb.append(", network type: " + TelephonyManager.getNetworkTypeName(mNetworkType));
        sb.append(", APN Setting: " + mApnSetting);
        sb.append(", link properties: " + mLinkProperties);
        sb.append(", fail cause: " + DataFailCause.toString(mFailCause));

        return sb.toString();
    }