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

Commit 18e40d07 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6621766 from 0670127a to rvc-release

Change-Id: I07dcc26bab05ccde634fe88da5092f02a03b2538
parents 404f3d89 0670127a
Loading
Loading
Loading
Loading
+89 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.Registrant;
import android.os.SystemClock;
import android.telephony.CarrierConfigManager;
@@ -74,6 +75,8 @@ public class GsmCdmaConnection extends Connection {

    Handler mHandler;

    private PowerManager.WakeLock mPartialWakeLock;

    // The cached delay to be used between DTMF tones fetched from carrier config.
    private int mDtmfToneDelay = 0;

@@ -83,11 +86,13 @@ public class GsmCdmaConnection extends Connection {
    static final int EVENT_DTMF_DONE = 1;
    static final int EVENT_PAUSE_DONE = 2;
    static final int EVENT_NEXT_POST_DIAL = 3;
    static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
    static final int EVENT_DTMF_DELAY_DONE = 5;

    //***** Constants
    static final int PAUSE_DELAY_MILLIS_GSM = 3 * 1000;
    static final int PAUSE_DELAY_MILLIS_CDMA = 2 * 1000;
    static final int WAKE_LOCK_TIMEOUT_MILLIS = 60 * 1000;

    //***** Inner Classes

@@ -104,6 +109,9 @@ public class GsmCdmaConnection extends Connection {
                case EVENT_PAUSE_DONE:
                    processNextPostDialChar();
                    break;
                case EVENT_WAKE_LOCK_TIMEOUT:
                    releaseWakeLock();
                    break;
                case EVENT_DTMF_DONE:
                    // We may need to add a delay specified by carrier between DTMF tones that are
                    // sent out.
@@ -119,6 +127,8 @@ public class GsmCdmaConnection extends Connection {
    /** This is probably an MT call that we first saw in a CLCC response or a hand over. */
    public GsmCdmaConnection (GsmCdmaPhone phone, DriverCall dc, GsmCdmaCallTracker ct, int index) {
        super(phone.getPhoneType());
        createWakeLock(phone.getContext());
        acquireWakeLock();

        mOwner = ct;
        mHandler = new MyHandler(mOwner.getLooper());
@@ -149,6 +159,8 @@ public class GsmCdmaConnection extends Connection {
    public GsmCdmaConnection (GsmCdmaPhone phone, String dialString, GsmCdmaCallTracker ct,
                              GsmCdmaCall parent, boolean isEmergencyCall) {
        super(phone.getPhoneType());
        createWakeLock(phone.getContext());
        acquireWakeLock();

        mOwner = ct;
        mHandler = new MyHandler(mOwner.getLooper());
@@ -203,6 +215,8 @@ public class GsmCdmaConnection extends Connection {
    public GsmCdmaConnection(Context context, CdmaCallWaitingNotification cw, GsmCdmaCallTracker ct,
                             GsmCdmaCall parent) {
        super(parent.getPhone().getPhoneType());
        createWakeLock(context);
        acquireWakeLock();

        mOwner = ct;
        mHandler = new MyHandler(mOwner.getLooper());
@@ -226,6 +240,7 @@ public class GsmCdmaConnection extends Connection {
        if (mParent != null) {
            mParent.detach(this);
        }
        releaseAllWakeLocks();
    }

    static boolean equalsHandlesNulls(Object a, Object b) {
@@ -618,6 +633,7 @@ public class GsmCdmaConnection extends Connection {
            mOrigConnection = null;
        }
        clearPostDialListeners();
        releaseWakeLock();
        return changed;
    }

@@ -633,6 +649,7 @@ public class GsmCdmaConnection extends Connection {
                mParent.detach(this);
            }
        }
        releaseWakeLock();
    }

    // Returns true if state has changed, false if nothing changed
@@ -774,7 +791,21 @@ public class GsmCdmaConnection extends Connection {
        if (!mIsIncoming) {
            // outgoing calls only
            processNextPostDialChar();
        } else {
            // Only release wake lock for incoming calls, for outgoing calls the wake lock
            // will be released after any pause-dial is completed
            releaseWakeLock();
        }
    }

    /**
     * We have completed the migration of another connection to this GsmCdmaConnection (for example,
     * in the case of SRVCC) and not still DIALING/ALERTING/INCOMING/WAITING.
     */
    void onConnectedConnectionMigrated() {
        // We can release the wakelock in this case, the migrated call is not still
        // DIALING/ALERTING/INCOMING/WAITING.
        releaseWakeLock();
    }

    private void
@@ -861,7 +892,17 @@ public class GsmCdmaConnection extends Connection {
    @Override
    protected void finalize()
    {
        /**
         * It is understood that This finalizer is not guaranteed
         * to be called and the release lock call is here just in
         * case there is some path that doesn't call onDisconnect
         * and or onConnectedInOrOut.
         */
        if (mPartialWakeLock != null && mPartialWakeLock.isHeld()) {
            Rlog.e(LOG_TAG, "UNEXPECTED; mPartialWakeLock is held when finalizing.");
        }
        clearPostDialListeners();
        releaseWakeLock();
    }

    private void
@@ -870,6 +911,7 @@ public class GsmCdmaConnection extends Connection {
        Registrant postDialHandler;

        if (mPostDialState == PostDialState.CANCELLED) {
            releaseWakeLock();
            return;
        }

@@ -877,6 +919,9 @@ public class GsmCdmaConnection extends Connection {
                mPostDialString.length() <= mNextPostDialChar) {
            setPostDialState(PostDialState.COMPLETE);

            // We were holding a wake lock until pause-dial was complete, so give it up now
            releaseWakeLock();

            // notifyMessage.arg1 is 0 on complete
            c = 0;
        } else {
@@ -970,18 +1015,60 @@ public class GsmCdmaConnection extends Connection {
     * @param s new PostDialState
     */
    private void setPostDialState(PostDialState s) {
        if (s == PostDialState.STARTED
                || s == PostDialState.PAUSE) {
            synchronized (mPartialWakeLock) {
                if (mPartialWakeLock.isHeld()) {
                    mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
                } else {
                    acquireWakeLock();
                }
                Message msg = mHandler.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
                mHandler.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
            }
        } else {
            mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
            releaseWakeLock();
        }
        mPostDialState = s;
        notifyPostDialListeners();
    }

    @UnsupportedAppUsage
    private void createWakeLock(Context context) {
        // no-op
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
    }

    @UnsupportedAppUsage
    private void acquireWakeLock() {
        // no-op
        if (mPartialWakeLock != null) {
            synchronized (mPartialWakeLock) {
                log("acquireWakeLock");
                mPartialWakeLock.acquire();
            }
        }
    }

    private void releaseWakeLock() {
        if (mPartialWakeLock != null) {
            synchronized (mPartialWakeLock) {
                if (mPartialWakeLock.isHeld()) {
                    log("releaseWakeLock");
                    mPartialWakeLock.release();
                }
            }
        }
    }

    private void releaseAllWakeLocks() {
        if (mPartialWakeLock != null) {
            synchronized (mPartialWakeLock) {
                while (mPartialWakeLock.isHeld()) {
                    mPartialWakeLock.release();
                }
            }
        }
    }

    @UnsupportedAppUsage
+78 −21
Original line number Diff line number Diff line
@@ -3903,20 +3903,62 @@ public class SubscriptionController extends ISub.Stub {
    // They are doing similar things except operating on different cache.
    private List<SubscriptionInfo> getSubscriptionInfoListFromCacheHelper(
            String callingPackage, String callingFeatureId, List<SubscriptionInfo> cacheSubList) {
        synchronized (mSubInfoListLock) {
            // Filter the list to only include subscriptions which the caller can manage.
            return cacheSubList.stream()
                    .filter(subscriptionInfo -> {
        boolean canReadPhoneState = false;
        boolean canReadIdentifiers = false;
        boolean canReadPhoneNumber = false;
        try {
                            return TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext,
                                    subscriptionInfo.getSubscriptionId(), callingPackage,
            canReadPhoneState = TelephonyPermissions.checkReadPhoneState(mContext,
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID, Binder.getCallingPid(),
                    Binder.getCallingUid(), callingPackage, callingFeatureId,
                    "getSubscriptionInfoList");
            // If the calling package has the READ_PHONE_STATE permission then check if the caller
            // also has access to subscriber identifiers and the phone number to ensure that the ICC
            // ID and any other unique identifiers are removed if the caller should not have access.
            if (canReadPhoneState) {
                canReadIdentifiers = hasSubscriberIdentifierAccess(
                        SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
                        callingFeatureId, "getSubscriptionInfoList");
                canReadPhoneNumber = hasPhoneNumberAccess(
                        SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
                        callingFeatureId, "getSubscriptionInfoList");
            }
        } catch (SecurityException e) {
                            return false;
            // If a SecurityException is thrown during the READ_PHONE_STATE check then the only way
            // to access a subscription is to have carrier privileges for its subId; an app with
            // carrier privileges for a subscription is also granted access to all identifiers so
            // the identifier and phone number access checks are not required.
        }
                    }).map(subscriptionInfo -> conditionallyRemoveIdentifiers(subscriptionInfo,
                            callingPackage, callingFeatureId, "getSubscriptionInfoList"))
                    .collect(Collectors.toList());

        synchronized (mSubInfoListLock) {
            // If the caller can read all phone state, just return the full list.
            if (canReadIdentifiers && canReadPhoneNumber) {
                return new ArrayList<>(cacheSubList);
            }
            // Filter the list to only include subscriptions which the caller can manage.
            List<SubscriptionInfo> subscriptions = new ArrayList<>(cacheSubList.size());
            for (SubscriptionInfo subscriptionInfo : cacheSubList) {
                int subId = subscriptionInfo.getSubscriptionId();
                boolean hasCarrierPrivileges = TelephonyPermissions.checkCarrierPrivilegeForSubId(
                        mContext, subId);
                // If the caller does not have the READ_PHONE_STATE permission nor carrier
                // privileges then they cannot access the current subscription.
                if (!canReadPhoneState && !hasCarrierPrivileges) {
                    continue;
                }
                // If the caller has carrier privileges then they are granted access to all
                // identifiers for their subscription.
                if (hasCarrierPrivileges) {
                    subscriptions.add(subscriptionInfo);
                } else {
                    // The caller does not have carrier privileges for this subId, filter the
                    // identifiers in the subscription based on the results of the initial
                    // permission checks.
                    subscriptions.add(
                            conditionallyRemoveIdentifiers(subscriptionInfo, canReadIdentifiers,
                                    canReadPhoneNumber));
                }
            }
            return subscriptions;
        }
    }

@@ -3937,8 +3979,24 @@ public class SubscriptionController extends ISub.Stub {
                callingFeatureId, message);
        boolean hasPhoneNumberAccess = hasPhoneNumberAccess(subId, callingPackage, callingFeatureId,
                message);
        if (!hasIdentifierAccess || !hasPhoneNumberAccess) {
            result = new SubscriptionInfo(subInfo);
        return conditionallyRemoveIdentifiers(subInfo, hasIdentifierAccess, hasPhoneNumberAccess);
    }

    /**
     * Conditionally removes identifiers from the provided {@code subInfo} based on if the calling
     * package {@code hasIdentifierAccess} and {@code hasPhoneNumberAccess} and returns the
     * potentially modified object.
     *
     * <p>If the caller specifies the package does not have identifier or phone number access
     * a clone of the provided SubscriptionInfo is created and modified to avoid altering
     * SubscriptionInfo objects in a cache.
     */
    private SubscriptionInfo conditionallyRemoveIdentifiers(SubscriptionInfo subInfo,
            boolean hasIdentifierAccess, boolean hasPhoneNumberAccess) {
        if (hasIdentifierAccess && hasPhoneNumberAccess) {
            return subInfo;
        }
        SubscriptionInfo result = new SubscriptionInfo(subInfo);
        if (!hasIdentifierAccess) {
            result.clearIccId();
            result.clearCardString();
@@ -3946,7 +4004,6 @@ public class SubscriptionController extends ISub.Stub {
        if (!hasPhoneNumberAccess) {
            result.clearNumber();
        }
        }
        return result;
    }

+55 −3
Original line number Diff line number Diff line
@@ -1273,6 +1273,54 @@ public class SubscriptionControllerTest extends TelephonyTest {
        }
    }

    @Test
    public void testGetActiveSubscriptionInfoListWithCarrierPrivilegesOnOneSubId()
            throws Exception {
        // If an app does not have the READ_PHONE_STATE permission but has carrier privileges on one
        // out of multiple sub IDs then the SubscriptionInfo for that subId should be returned with
        // the ICC ID and phone number.
        testInsertSim();
        doReturn(2).when(mTelephonyManager).getPhoneCount();
        mSubscriptionControllerUT.addSubInfoRecord("test2", 1);
        int firstSubId = getFirstSubId();
        int secondSubId = getSubIdAtIndex(1);
        mSubscriptionControllerUT.setDisplayNumber(DISPLAY_NUMBER, secondSubId);
        setupIdentifierCarrierPrivilegesTest();
        mContextFixture.removeCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE);
        setCarrierPrivilegesForSubId(false, firstSubId);
        setCarrierPrivilegesForSubId(true, secondSubId);

        List<SubscriptionInfo> subInfoList =
                mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage,
                        mCallingFeature);

        assertEquals(1, subInfoList.size());
        SubscriptionInfo subInfo = subInfoList.get(0);
        assertEquals("test2", subInfo.getIccId());
        assertEquals(DISPLAY_NUMBER, subInfo.getNumber());
    }

    @Test
    public void testGetActiveSubscriptionInfoListWithIdentifierAccessWithoutNumberAccess()
            throws Exception {
        // An app with access to device identifiers may not have access to the device phone number
        // (ie an app that passes the device / profile owner check or an app that has been granted
        // the device identifiers appop); this test verifies that an app with identifier access
        // can read the ICC ID but does not receive the phone number.
        testInsertSim();
        setupReadPhoneNumbersTest();
        setIdentifierAccess(true);

        List<SubscriptionInfo> subInfoList =
                mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage,
                        mCallingFeature);

        assertEquals(1, subInfoList.size());
        SubscriptionInfo subInfo = subInfoList.get(0);
        assertEquals("test", subInfo.getIccId());
        assertEquals(UNAVAILABLE_NUMBER, subInfo.getNumber());
    }

    @Test
    public void testGetActiveSubscriptionInfoListWithPrivilegedPermission() throws Exception {
        // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier
@@ -1403,9 +1451,13 @@ public class SubscriptionControllerTest extends TelephonyTest {
    }

    private int getFirstSubId() throws Exception {
        int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false);
        assertTrue(subIds != null && subIds.length != 0);
        return subIds[0];
        return getSubIdAtIndex(0);
    }

    private int getSubIdAtIndex(int index) throws Exception {
        int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibileOnly*/false);
        assertTrue(subIds != null && subIds.length > index);
        return subIds[index];
    }

    @Test
+9 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ import com.android.server.pm.PackageManagerService;
import com.android.server.pm.permission.PermissionManagerService;

import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -839,6 +840,14 @@ public abstract class TelephonyTest {
                mTelephonyManager).getCarrierPrivilegeStatus(anyInt());
    }

    protected void setCarrierPrivilegesForSubId(boolean hasCarrierPrivileges, int subId) {
        TelephonyManager mockTelephonyManager = Mockito.mock(TelephonyManager.class);
        doReturn(mockTelephonyManager).when(mTelephonyManager).createForSubscriptionId(subId);
        doReturn(hasCarrierPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
                : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS).when(
                mockTelephonyManager).getCarrierPrivilegeStatus(anyInt());
    }

    protected final void waitForHandlerAction(Handler h, long timeoutMillis) {
        final CountDownLatch lock = new CountDownLatch(1);
        h.post(lock::countDown);