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

Commit f1062230 authored by James.cf Lin's avatar James.cf Lin Committed by Automerger Merge Worker
Browse files

Add the throttling mechanism to get rate limited for the PUBLISH requests. am: 5c6f9e3c

Original change: https://android-review.googlesource.com/c/platform/frameworks/opt/net/ims/+/1635159

Change-Id: I8bf945db2c7a24f05acf31f61373d130c15ee3f7
parents e362fbb0 5c6f9e3c
Loading
Loading
Loading
Loading
+2 −25
Original line number Diff line number Diff line
@@ -116,17 +116,6 @@ public class UceController {
         */
        void refreshCapabilities(@NonNull List<Uri> contactNumbers,
                @NonNull IRcsUceControllerCallback callback) throws RemoteException;

        /**
         * The method is called when the EabController and the PublishController want to receive
         * published state changes.
         */
        void registerPublishStateCallback(@NonNull IRcsUcePublishStateCallback c);

        /**
         * Remove the existing PublishStateCallback.
         */
        void unregisterPublishStateCallback(@NonNull IRcsUcePublishStateCallback c);
    }

    /**
@@ -358,18 +347,6 @@ public class UceController {
            logd("refreshCapabilities: " + contactNumbers.size());
            UceController.this.requestCapabilitiesInternal(contactNumbers, true, callback);
        }

        @Override
        public void registerPublishStateCallback(@NonNull IRcsUcePublishStateCallback c) {
            logd("UceControllerCallback: registerPublishStateCallback");
            UceController.this.registerPublishStateCallback(c);
        }

        @Override
        public void unregisterPublishStateCallback(@NonNull IRcsUcePublishStateCallback c) {
            logd("UceControllerCallback: unregisterPublishStateCallback");
            UceController.this.unregisterPublishStateCallback(c);
        }
    };

    @VisibleForTesting
@@ -467,7 +444,7 @@ public class UceController {
        if (mServerState.isRequestForbidden()) {
            Integer errorCode = mServerState.getForbiddenErrorCode();
            long retryAfter = mServerState.getRetryAfterMillis();
            logw("requestCapabilities: The request is forbidden, errorCode=" + errorCode
            logw("requestAvailability: The request is forbidden, errorCode=" + errorCode
                + ", retryAfter=" + retryAfter);
            errorCode = (errorCode != null) ? errorCode : RcsUceAdapter.ERROR_FORBIDDEN;
            c.onError(errorCode, retryAfter);
@@ -539,7 +516,7 @@ public class UceController {

    /**
     * Check if the UceController is available.
     * @return true if the RCS is connected without destroyed.
     * @return true if RCS is connected without destroyed.
     */
    public boolean isUnavailable() {
        if (!mIsRcsConnected || mIsDestroyedFlag) {
+130 −47
Original line number Diff line number Diff line
@@ -23,11 +23,14 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.provider.Telephony;
import android.telecom.TelecomManager;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsMmTelManager;
@@ -57,9 +60,7 @@ public class DeviceCapabilityListener {

    private static final String LOG_TAG = UceUtils.getLogPrefix() + "DeviceCapListener";

    // Delay to send the registered changed because the registered state changed of MMTEL and RCS
    // may be called at the same time.
    private static final long DELAY_SEND_IMS_REGISTERED_CHANGED_MSG = 500L;
    private static final long REGISTER_IMS_CHANGED_DELAY = 15000L;  // 15 seconds

    /**
     * Used to inject ImsMmTelManager instances for testing.
@@ -85,49 +86,78 @@ public class DeviceCapabilityListener {
        ProvisioningManager getProvisioningManager(int subId);
    }

    // The handler to re-register ims provision callback.
    private class RegisterCallbackHandler extends Handler {
    /*
     * Handle registering IMS callback and triggering the publish request because of the
     * capabilities changed.
     */
    private class DeviceCapabilityHandler extends Handler {
        private static final long TRIGGER_PUBLISH_REQUEST_DELAY_MS = 500L;

        private static final int EVENT_REGISTER_IMS_CONTENT_CHANGE = 1;
        private static final long REGISTER_IMS_CHANGED_DELAY = 5000L;  // 5 seconds
        private static final int EVENT_UNREGISTER_IMS_CHANGE = 2;
        private static final int EVENT_REQUEST_PUBLISH = 3;

        RegisterCallbackHandler(Looper looper) {
        DeviceCapabilityHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            logd("handleMessage: " + msg.what);
            if (mIsDestroyed) return;
            switch (msg.what) {
                case EVENT_REGISTER_IMS_CONTENT_CHANGE:
                    registerImsProvisionCallback();
                    break;
                case EVENT_UNREGISTER_IMS_CHANGE:
                    unregisterImsProvisionCallback();
                    break;
                case EVENT_REQUEST_PUBLISH:
                    int triggerType = msg.arg1;
                    mCallback.requestPublishFromInternal(triggerType);
                    break;
            }
        }

        public void sendRegisterImsContentChangedMessage() {
        public void sendRegisterImsContentChangedMessage(long delay) {
            // Remove the existing message and send a new one with the delayed time.
            removeMessages(EVENT_REGISTER_IMS_CONTENT_CHANGE);
            Message msg = obtainMessage(EVENT_REGISTER_IMS_CONTENT_CHANGE);
            sendMessageDelayed(msg, REGISTER_IMS_CHANGED_DELAY);
            sendMessageDelayed(msg, delay);
        }

        public void removeRegisterImsContentChangedMessage() {
            removeMessages(EVENT_REGISTER_IMS_CONTENT_CHANGE);
        }

        public void sendUnregisterImsCallbackMessage() {
            removeMessages(EVENT_REGISTER_IMS_CONTENT_CHANGE);
            sendEmptyMessage(EVENT_UNREGISTER_IMS_CHANGE);
        }

        public void sendTriggeringPublishMessage(int type) {
            // Remove the existing message and resend a new message.
            removeMessages(EVENT_REQUEST_PUBLISH);
            Message message = obtainMessage();
            message.what = EVENT_REQUEST_PUBLISH;
            message.arg1 = type;
            sendMessageDelayed(message, TRIGGER_PUBLISH_REQUEST_DELAY_MS);
        }
    }

    private final int mSubId;
    private final Context mContext;
    private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE);
    private volatile boolean mInitialized;

    // The listener is destroyed
    private volatile boolean mIsDestroyed;
    private volatile boolean mIsRcsConnected;
    private volatile boolean mIsImsCallbackRegistered;

    // The callback to trigger the internal publish request
    private final PublishControllerCallback mCallback;
    private final DeviceCapabilityInfo mCapabilityInfo;
    private final RegisterCallbackHandler mHandler;
    private final HandlerThread mHandlerThread;
    private final DeviceCapabilityHandler mHandler;
    private final HandlerExecutor mHandlerExecutor;

    private ImsMmTelManager mImsMmTelManager;
@@ -146,7 +176,7 @@ public class DeviceCapabilityListener {
    private final Object mLock = new Object();

    public DeviceCapabilityListener(Context context, int subId, DeviceCapabilityInfo info,
            PublishControllerCallback callback, Looper looper) {
            PublishControllerCallback callback) {
        mSubId = subId;
        logi("create");

@@ -154,7 +184,10 @@ public class DeviceCapabilityListener {
        mCallback = callback;
        mCapabilityInfo = info;
        mInitialized = false;
        mHandler = new RegisterCallbackHandler(looper);

        mHandlerThread = new HandlerThread("DeviceCapListenerThread");
        mHandlerThread.start();
        mHandler = new DeviceCapabilityHandler(mHandlerThread.getLooper());
        mHandlerExecutor = new HandlerExecutor(mHandler);
    }

@@ -180,6 +213,18 @@ public class DeviceCapabilityListener {
        }
    }

    // The RcsFeature has been connected to the framework
    public void onRcsConnected() {
        mIsRcsConnected = true;
        mHandler.sendRegisterImsContentChangedMessage(0L);
    }

    // The framework has lost the binding to the RcsFeature.
    public void onRcsDisconnected() {
        mIsRcsConnected = false;
        mHandler.sendUnregisterImsCallbackMessage();
    }

    /**
     * Notify the instance is destroyed
     */
@@ -192,6 +237,7 @@ public class DeviceCapabilityListener {
            mInitialized = false;
            unregisterReceivers();
            unregisterImsProvisionCallback();
            mHandlerThread.quit();
        }
    }

@@ -228,6 +274,11 @@ public class DeviceCapabilityListener {
    }

    private void registerImsProvisionCallback() {
        if (mIsImsCallbackRegistered) {
            logd("registerImsProvisionCallback: already registered.");
            return;
        }

        logd("registerImsProvisionCallback");
        try {
            // Register mmtel callback
@@ -247,12 +298,18 @@ public class DeviceCapabilityListener {
            // Register provisioning changed callback
            mProvisioningManager.registerProvisioningChangedCallback(mHandlerExecutor,
                    mProvisionChangedCallback);

            // Set the IMS callback is registered.
            mIsImsCallbackRegistered = true;
        } catch (ImsException e) {
            logw("registerImsProvisionCallback error: " + e);
            // Unregister the callback
            unregisterImsProvisionCallback();
            // Retry registering IMS content change callback
            mHandler.sendRegisterImsContentChangedMessage();

            // Retry registering IMS callback only when the RCS is connected.
            if (mIsRcsConnected) {
                mHandler.sendRegisterImsContentChangedMessage(REGISTER_IMS_CHANGED_DELAY);
            }
        }
    }

@@ -291,6 +348,9 @@ public class DeviceCapabilityListener {
        } catch (RuntimeException e) {
            logw("unregister provisioning callback error: " + e.getMessage());
        }

        // Clear the IMS callback registered flag.
        mIsImsCallbackRegistered = false;
    }

    @VisibleForTesting
@@ -382,6 +442,7 @@ public class DeviceCapabilityListener {
                public void onRegistered(ImsRegistrationAttributes attributes) {
                    synchronized (mLock) {
                        logi("onRcsRegistered: " + attributes);
                        if (!mIsImsCallbackRegistered) return;
                        handleImsRcsRegistered(attributes);
                    }
                }
@@ -390,6 +451,7 @@ public class DeviceCapabilityListener {
                public void onUnregistered(ImsReasonInfo info) {
                    synchronized (mLock) {
                        logi("onRcsUnregistered: " + info);
                        if (!mIsImsCallbackRegistered) return;
                        handleImsRcsUnregistered();
                    }
                }
@@ -399,10 +461,12 @@ public class DeviceCapabilityListener {
    public final RegistrationManager.RegistrationCallback mMmtelRegistrationCallback =
            new RegistrationManager.RegistrationCallback() {
                @Override
                public void onRegistered(int imsTransportType) {
                public void onRegistered(@TransportType int transportType) {
                    synchronized (mLock) {
                        logi("onMmTelRegistered: " + imsTransportType);
                        handleImsMmtelRegistered(imsTransportType);
                        String type = AccessNetworkConstants.transportTypeToString(transportType);
                        logi("onMmTelRegistered: " + type);
                        if (!mIsImsCallbackRegistered) return;
                        handleImsMmtelRegistered(transportType);
                    }
                }

@@ -410,6 +474,7 @@ public class DeviceCapabilityListener {
                public void onUnregistered(ImsReasonInfo info) {
                    synchronized (mLock) {
                        logi("onMmTelUnregistered: " + info);
                        if (!mIsImsCallbackRegistered) return;
                        handleImsMmtelUnregistered();
                    }
                }
@@ -441,44 +506,46 @@ public class DeviceCapabilityListener {
                        case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
                        case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
                            handleProvisioningChanged();
                        case ProvisioningManager.KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS:
                            handlePublishThrottleChanged(value);
                            break;
                    }
                }
            };

    private void handleTtyPreferredModeChanged(int preferredMode) {
        logi("TTY preferred mode changed: " + preferredMode);
        boolean isChanged = mCapabilityInfo.updateTtyPreferredMode(preferredMode);
        logi("TTY preferred mode changed: " + preferredMode + ", isChanged=" + isChanged);
        if (isChanged) {
            mCallback.requestPublishFromInternal(
                    PublishController.PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE, 0L);
            mHandler.sendTriggeringPublishMessage(
                PublishController.PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE);
        }
    }

    private void handleAirplaneModeChanged(boolean state) {
        logi("Airplane mode changed: " + state);
        boolean isChanged = mCapabilityInfo.updateAirplaneMode(state);
        logi("Airplane mode changed: " + state + ", isChanged="+ isChanged);
        if (isChanged) {
            mCallback.requestPublishFromInternal(
                    PublishController.PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE, 0L);
            mHandler.sendTriggeringPublishMessage(
                    PublishController.PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE);
        }
    }

    private void handleMobileDataChanged(boolean isEnabled) {
        logi("Mobile data changed: " + isEnabled);
        boolean isChanged = mCapabilityInfo.updateMobileData(isEnabled);
        logi("Mobile data changed: " + isEnabled + ", isChanged=" + isChanged);
        if (isChanged) {
            mCallback.requestPublishFromInternal(
                    PublishController.PUBLISH_TRIGGER_MOBILE_DATA_CHANGE, 0L);
            mHandler.sendTriggeringPublishMessage(
                    PublishController.PUBLISH_TRIGGER_MOBILE_DATA_CHANGE);
        }
    }

    private void handleVtSettingChanged(boolean isEnabled) {
        logi("VT setting changed: " + isEnabled);
        boolean isChanged = mCapabilityInfo.updateVtSetting(isEnabled);
        logi("VT setting changed: " + isEnabled + ", isChanged=" + isChanged);
        if (isChanged) {
            mCallback.requestPublishFromInternal(
                    PublishController.PUBLISH_TRIGGER_VT_SETTING_CHANGE, 0L);
            mHandler.sendTriggeringPublishMessage(
                    PublishController.PUBLISH_TRIGGER_VT_SETTING_CHANGE);
        }
    }

@@ -487,9 +554,8 @@ public class DeviceCapabilityListener {
     */
    private void handleImsMmtelRegistered(int imsTransportType) {
        mCapabilityInfo.updateImsMmtelRegistered(imsTransportType);
        mCallback.requestPublishFromInternal(
                PublishController.PUBLISH_TRIGGER_MMTEL_REGISTERED,
                DELAY_SEND_IMS_REGISTERED_CHANGED_MSG);
        mHandler.sendTriggeringPublishMessage(
                PublishController.PUBLISH_TRIGGER_MMTEL_REGISTERED);
    }

    /*
@@ -497,41 +563,53 @@ public class DeviceCapabilityListener {
     */
    private void handleImsMmtelUnregistered() {
        mCapabilityInfo.updateImsMmtelUnregistered();
        mCallback.requestPublishFromInternal(
                PublishController.PUBLISH_TRIGGER_MMTEL_UNREGISTERED, 0L);
        mHandler.sendTriggeringPublishMessage(
                PublishController.PUBLISH_TRIGGER_MMTEL_UNREGISTERED);
    }

    private void handleMmtelCapabilitiesStatusChanged(MmTelCapabilities capabilities) {
        boolean isChanged = mCapabilityInfo.updateMmtelCapabilitiesChanged(capabilities);
        logi("MMTel capabilities status changed: isChanged=" + isChanged);
        if (isChanged) {
            mCallback.requestPublishFromInternal(
                    PublishController.PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE, 0L);
            mHandler.sendTriggeringPublishMessage(
                    PublishController.PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE);
        }
    }

    /*
     * This method is called when the RCS is registered.
     * This method is called when RCS is registered.
     */
    private void handleImsRcsRegistered(ImsRegistrationAttributes attr) {
        mCapabilityInfo.updateImsRcsRegistered(attr);
        mCallback.requestPublishFromInternal(
                PublishController.PUBLISH_TRIGGER_RCS_REGISTERED,
                DELAY_SEND_IMS_REGISTERED_CHANGED_MSG);
        mHandler.sendTriggeringPublishMessage(PublishController.PUBLISH_TRIGGER_RCS_REGISTERED);
    }

    /*
     * This method is called when the RCS is unregistered.
     * This method is called when RCS is unregistered.
     */
    private void handleImsRcsUnregistered() {
        mCapabilityInfo.updateImsRcsUnregistered();
        mCallback.requestPublishFromInternal(
                PublishController.PUBLISH_TRIGGER_RCS_UNREGISTERED, 0L);
        mHandler.sendTriggeringPublishMessage(PublishController.PUBLISH_TRIGGER_RCS_UNREGISTERED);
    }

    /*
     * This method is called when the provisioning is changed
     */
    private void handleProvisioningChanged() {
        mCallback.requestPublishFromInternal(
                PublishController.PUBLISH_TRIGGER_PROVISIONING_CHANGE, 0L);
        mHandler.sendTriggeringPublishMessage(
                PublishController.PUBLISH_TRIGGER_PROVISIONING_CHANGE);
    }

    /*
     * Update the publish throttle.
     */
    private void handlePublishThrottleChanged(int value) {
        mCallback.updatePublishThrottle(value);
    }

    @VisibleForTesting
    public Handler getHandler() {
        return mHandler;
    }

    @VisibleForTesting
@@ -549,6 +627,11 @@ public class DeviceCapabilityListener {
        mProvisioningMgrFactory = factory;
    }

    @VisibleForTesting
    public void setImsCallbackRegistered(boolean registered) {
        mIsImsCallbackRegistered = registered;
    }

    private void logd(String log) {
        Log.d(LOG_TAG, getLogPrefix().append(log).toString());
        mLocalLog.log("[D] " + log);
+6 −1
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ public interface PublishController extends ControllerBase {
        /**
         * Request publish from local.
         */
        void requestPublishFromInternal(@PublishTriggerType int type, long delay);
        void requestPublishFromInternal(@PublishTriggerType int type);

        /**
         * Receive the command error callback of the request from ImsService.
@@ -122,6 +122,11 @@ public interface PublishController extends ControllerBase {
         * Update the publish request result.
         */
        void updatePublishRequestResult(int publishState, Instant updatedTimestamp, String pidfXml);

        /**
         * Update the value of the publish throttle.
         */
        void updatePublishThrottle(int value);
    }

    /**
+47 −44

File changed.

Preview size limit exceeded, changes collapsed.

+116 −93

File changed.

Preview size limit exceeded, changes collapsed.

Loading