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

Commit 0dc51ca9 authored by Brad Ebinger's avatar Brad Ebinger
Browse files

Update IMS resolver/binding code to support multiuser

Instead of assuming that we will bind on the system user, improve
the ImsResolver code so that it can take into account the current
user and bind based on the active user + system user to support
HSUM. The code now also supports ImsService packages limited to
a subset of the full users on the device.

This fix also improves logging for validation purposes.

Flag: com.android.internal.telephony.flags.ims_resolver_user_aware
Bug: b/371272669
Test: atest FrameworksTelephonyTests CtsTeleponyTestCases
Test: manual testing using ImsTestApp and switching across users
Change-Id: Ica5166382e8ddc2860306b57efd2727dda133ca6
parent 9659d320
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -138,6 +138,17 @@ flag {
    }
}

# OWNER=breadley TARGET=25Q1
flag {
    name: "ims_resolver_user_aware"
    namespace: "telephony"
    description: "When enabled, it makes ImsResolver mult-user aware for configurations like HSUM."
    bug:"371272669"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

# OWNER=meghapatil TARGET=25Q2
flag {
    name: "support_sms_over_ims_apis"
+393 −113

File changed.

Preview size limit exceeded, changes collapsed.

+29 −17
Original line number Diff line number Diff line
@@ -196,7 +196,7 @@ public class ImsServiceController {
            }
            if (mCallbacks != null) {
                // Will trigger an unbind.
                mCallbacks.imsServiceBindPermanentError(getComponentName());
                mCallbacks.imsServiceBindPermanentError(getComponentName(), mBoundUser);
            }
        }

@@ -217,7 +217,8 @@ public class ImsServiceController {
        /**
         * Called by ImsServiceController when a new MMTEL or RCS feature has been created.
         */
        void imsServiceFeatureCreated(int slotId, int feature, ImsServiceController controller);
        void imsServiceFeatureCreated(int slotId, int subId, int feature,
                ImsServiceController controller);
        /**
         * Called by ImsServiceController when a new MMTEL or RCS feature has been removed.
         */
@@ -234,7 +235,7 @@ public class ImsServiceController {
         * Called by the ImsServiceController when there has been an error binding that is
         * not recoverable, such as the ImsService returning a null binder.
         */
        void imsServiceBindPermanentError(ComponentName name);
        void imsServiceBindPermanentError(ComponentName name, UserHandle user);
    }

    /**
@@ -273,6 +274,7 @@ public class ImsServiceController {

    private boolean mIsBound = false;
    private boolean mIsBinding = false;
    private UserHandle mBoundUser = null;
    // Set of a pair of slotId->feature
    private Set<ImsFeatureConfiguration.FeatureSlotPair> mImsFeatures;
    private SparseIntArray mSlotIdToSubIdMap;
@@ -337,7 +339,7 @@ public class ImsServiceController {
                if (mIsBound) {
                    return;
                }
                bind(mImsFeatures, mSlotIdToSubIdMap);
                bind(mBoundUser, mImsFeatures, mSlotIdToSubIdMap);
            }
        }
    };
@@ -413,17 +415,18 @@ public class ImsServiceController {
     * @return {@link true} if the service is in the process of being bound, {@link false} if it
     * has failed.
     */
    public boolean bind(Set<ImsFeatureConfiguration.FeatureSlotPair> imsFeatureSet,
    public boolean bind(UserHandle user, Set<ImsFeatureConfiguration.FeatureSlotPair> imsFeatureSet,
            SparseIntArray slotIdToSubIdMap) {
        synchronized (mLock) {
            if (!mIsBound && !mIsBinding) {
                mIsBinding = true;
                mBoundUser = user;
                sanitizeFeatureConfig(imsFeatureSet);
                mImsFeatures = imsFeatureSet;
                mSlotIdToSubIdMap = slotIdToSubIdMap;
                // Set the number of slots that support the feature
                mImsEnablementTracker.setNumOfSlots(mSlotIdToSubIdMap.size());
                grantPermissionsToService();
                grantPermissionsToService(user);
                Intent imsServiceIntent = new Intent(getServiceInterface()).setComponent(
                        mComponentName);
                mImsServiceConnection = new ImsServiceConnection();
@@ -432,8 +435,8 @@ public class ImsServiceController {
                mLocalLog.log("binding " + imsFeatureSet);
                Log.i(LOG_TAG, "Binding ImsService:" + mComponentName);
                try {
                    boolean bindSucceeded = mContext.bindService(imsServiceIntent,
                            mImsServiceConnection, serviceFlags);
                    boolean bindSucceeded = mContext.bindServiceAsUser(imsServiceIntent,
                            mImsServiceConnection, serviceFlags, user);
                    if (!bindSucceeded) {
                        mLocalLog.log("    binding failed, retrying in "
                                + mBackoff.getCurrentDelay() + " mS");
@@ -482,6 +485,7 @@ public class ImsServiceController {
            changeImsServiceFeatures(new HashSet<>(), mSlotIdToSubIdMap);
            mIsBound = false;
            mIsBinding = false;
            mBoundUser = null;
            setServiceController(null);
            unbindService();
        }
@@ -607,6 +611,13 @@ public class ImsServiceController {
        return mComponentName;
    }

    /**
     * @return The UserHandle that this controller is bound to or null if bound to no service.
     */
    public UserHandle getBoundUser() {
        return mBoundUser;
    }

    /**
     * Notify ImsService to enable IMS for the framework. This will trigger IMS registration and
     * trigger ImsFeature status updates.
@@ -766,7 +777,7 @@ public class ImsServiceController {

    // Grant runtime permissions to ImsService. PermissionManager ensures that the ImsService is
    // system/signed before granting permissions.
    private void grantPermissionsToService() {
    private void grantPermissionsToService(UserHandle user) {
        mLocalLog.log("grant permissions to " + getComponentName());
        Log.i(LOG_TAG, "Granting Runtime permissions to:" + getComponentName());
        String[] pkgToGrant = {mComponentName.getPackageName()};
@@ -774,8 +785,7 @@ public class ImsServiceController {
            if (mPermissionManager != null) {
                CountDownLatch latch = new CountDownLatch(1);
                mPermissionManager.grantDefaultPermissionsToEnabledImsServices(
                        pkgToGrant, UserHandle.of(UserHandle.myUserId()), Runnable::run,
                        isSuccess -> {
                        pkgToGrant, user, Runnable::run, isSuccess -> {
                            if (isSuccess) {
                                latch.countDown();
                            } else {
@@ -807,7 +817,8 @@ public class ImsServiceController {
            Log.i(LOG_TAG, "supports emergency calling on slot " + featurePair.slotId);
        }
        // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
        mCallbacks.imsServiceFeatureCreated(featurePair.slotId, featurePair.featureType, this);
        mCallbacks.imsServiceFeatureCreated(featurePair.slotId, subId, featurePair.featureType,
                this);
    }

    // This method should only be called when synchronized on mLock
@@ -978,10 +989,11 @@ public class ImsServiceController {
    @Override
    public String toString() {
        synchronized (mLock) {
            return "[ImsServiceController: componentName=" + getComponentName() + ", features="
                    + mImsFeatures + ", isBinding=" + mIsBinding + ", isBound=" + mIsBound
                    + ", serviceController=" + getImsServiceController() + ", rebindDelay="
                    + getRebindDelay() + "]";
            return "[ImsServiceController: componentName=" + getComponentName() + ", boundUser="
                    + mBoundUser + ", features=" + mImsFeatures + ", isBinding=" + mIsBinding
                    + ", isBound=" + mIsBound + ", serviceController=" + getImsServiceController()
                    + ", rebindDelay=" + getRebindDelay() + ", slotToSubIdMap=" + mSlotIdToSubIdMap
                    + "]";
        }
    }

+12 −7
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.UserHandle;
import android.telephony.ims.aidl.IImsServiceController;
import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.util.Log;
@@ -42,14 +43,16 @@ public class ImsServiceFeatureQueryManager {
        private static final String LOG_TAG = "ImsServiceFeatureQuery";

        private final ComponentName mName;
        private final UserHandle mUser;
        private final String mIntentFilter;
        // Track the status of whether or not the Service has died in case we need to permanently
        // unbind (see onNullBinding below).
        private boolean mIsServiceConnectionDead = false;


        ImsServiceFeatureQuery(ComponentName name, String intentFilter) {
        ImsServiceFeatureQuery(ComponentName name, UserHandle user, String intentFilter) {
            mName = name;
            mUser = user;
            mIntentFilter = intentFilter;
        }

@@ -62,7 +65,8 @@ public class ImsServiceFeatureQueryManager {
            Intent imsServiceIntent = new Intent(mIntentFilter).setComponent(mName);
            int serviceFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
                    | Context.BIND_IMPORTANT;
            boolean bindStarted = mContext.bindService(imsServiceIntent, this, serviceFlags);
            boolean bindStarted = mContext.bindServiceAsUser(imsServiceIntent, this,
                    serviceFlags, mUser);
            if (!bindStarted) {
                // Docs say to unbind if this fails.
                cleanup();
@@ -78,7 +82,7 @@ public class ImsServiceFeatureQueryManager {
            } else {
                Log.w(LOG_TAG, "onServiceConnected: " + name + " binder null.");
                cleanup();
                mListener.onPermanentError(name);
                mListener.onPermanentError(name, mUser);
            }
        }

@@ -103,7 +107,7 @@ public class ImsServiceFeatureQueryManager {
            // permanently unbind and instead let the automatic rebind occur.
            if (mIsServiceConnectionDead) return;
            cleanup();
            mListener.onPermanentError(name);
            mListener.onPermanentError(name, mUser);
        }

        private void queryImsFeatures(IImsServiceController controller) {
@@ -154,7 +158,7 @@ public class ImsServiceFeatureQueryManager {
        /**
         * Called when a query has failed due to a permanent error and should not be retried.
         */
        void onPermanentError(ComponentName name);
        void onPermanentError(ComponentName name, UserHandle user);
    }

    // Maps an active ImsService query (by Package Name String) its query.
@@ -171,16 +175,17 @@ public class ImsServiceFeatureQueryManager {
    /**
     * Starts an ImsService feature query for the ComponentName and Intent specified.
     * @param name The ComponentName of the ImsService being queried.
     * @param user The User associated with the request.
     * @param intentFilter The Intent filter that the ImsService specified.
     * @return true if the query started, false if it was unable to start.
     */
    public boolean startQuery(ComponentName name, String intentFilter) {
    public boolean startQuery(ComponentName name, UserHandle user, String intentFilter) {
        synchronized (mLock) {
            if (mActiveQueries.containsKey(name)) {
                // We already have an active query, wait for it to return.
                return true;
            }
            ImsServiceFeatureQuery query = new ImsServiceFeatureQuery(name, intentFilter);
            ImsServiceFeatureQuery query = new ImsServiceFeatureQuery(name, user, intentFilter);
            mActiveQueries.put(name, query);
            return query.start();
        }
+355 −109

File changed.

Preview size limit exceeded, changes collapsed.

Loading