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

Commit 0780dded authored by Hakjun Choi's avatar Hakjun Choi
Browse files

Executor Pattern for ImsSmsImplBase

Provide a flexibility by adding a constructor and a method setDefaultExecutor(), both provide a way that vendors can set executor for ImsSmsImplBase as desired while implementation

Bug: 257553898
Test: cts ImsServiceTest#testMmTelSendSmsExecutor
Test: e2e Messaging regression test with testcode b/261572901
Change-Id: I6d6fdf4d28597cc34074e4f2e3cec651ec67a0e4
parent d333c91c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15932,6 +15932,7 @@ package android.telephony.ims.stub {
  public class ImsSmsImplBase {
    ctor public ImsSmsImplBase();
    ctor public ImsSmsImplBase(@NonNull java.util.concurrent.Executor);
    method public void acknowledgeSms(int, @IntRange(from=0, to=65535) int, int);
    method public void acknowledgeSms(int, @IntRange(from=0, to=65535) int, int, @NonNull byte[]);
    method public void acknowledgeSmsReport(int, @IntRange(from=0, to=65535) int, int);
+69 −26
Original line number Diff line number Diff line
@@ -75,8 +75,10 @@ public class MmTelFeature extends ImsFeature {

    private static final String LOG_TAG = "MmTelFeature";
    private Executor mExecutor;
    private ImsSmsImplBase mSmsImpl;

    /**
     * Creates a new MmTelFeature using the Executor set in {@link ImsService#getExecutor}
     * @hide
     */
    @SystemApi
@@ -258,50 +260,54 @@ public class MmTelFeature extends ImsFeature {
        @Override
        public void setSmsListener(IImsSmsListener l) {
            executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l),
                    "setSmsListener");
                    "setSmsListener", getImsSmsImpl().getExecutor());
        }

        @Override
        public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
                byte[] pdu) {
            executeMethodAsyncNoException(() -> MmTelFeature.this
                    .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms");
                    .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms",
                    getImsSmsImpl().getExecutor());
        }

        @Override
        public void onMemoryAvailable(int token) {
            executeMethodAsyncNoException(() -> MmTelFeature.this
                    .onMemoryAvailable(token), "onMemoryAvailable");
                    .onMemoryAvailable(token), "onMemoryAvailable", getImsSmsImpl().getExecutor());
        }

        @Override
        public void acknowledgeSms(int token, int messageRef, int result) {
            executeMethodAsyncNoException(() -> MmTelFeature.this
                    .acknowledgeSms(token, messageRef, result), "acknowledgeSms");
                    .acknowledgeSms(token, messageRef, result), "acknowledgeSms",
                    getImsSmsImpl().getExecutor());
        }

        @Override
        public void acknowledgeSmsWithPdu(int token, int messageRef, int result, byte[] pdu) {
            executeMethodAsyncNoException(() -> MmTelFeature.this
                    .acknowledgeSms(token, messageRef, result, pdu), "acknowledgeSms");
                    .acknowledgeSms(token, messageRef, result, pdu), "acknowledgeSms",
                    getImsSmsImpl().getExecutor());
        }

        @Override
        public void acknowledgeSmsReport(int token, int messageRef, int result) {
            executeMethodAsyncNoException(() -> MmTelFeature.this
                    .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport");
                    .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport",
                    getImsSmsImpl().getExecutor());
        }

        @Override
        public String getSmsFormat() {
            return executeMethodAsyncForResultNoException(() -> MmTelFeature.this
                    .getSmsFormat(), "getSmsFormat");
                    .getSmsFormat(), "getSmsFormat", getImsSmsImpl().getExecutor());
        }

        @Override
        public void onSmsReady() {
            executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(),
                    "onSmsReady");
                    "onSmsReady", getImsSmsImpl().getExecutor());
        }

        @Override
@@ -336,6 +342,19 @@ public class MmTelFeature extends ImsFeature {
                    () -> MmTelFeature.this.notifySrvccCanceled(), "notifySrvccCanceled");
        }

        @Override
        public void setTerminalBasedCallWaitingStatus(boolean enabled) throws RemoteException {
            synchronized (mLock) {
                try {
                    MmTelFeature.this.setTerminalBasedCallWaitingStatus(enabled);
                } catch (ServiceSpecificException se) {
                    throw new ServiceSpecificException(se.errorCode, se.getMessage());
                } catch (Exception e) {
                    throw new RemoteException(e.getMessage());
                }
            }
        }

        // Call the methods with a clean calling identity on the executor and wait indefinitely for
        // the future to return.
        private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
@@ -359,6 +378,17 @@ public class MmTelFeature extends ImsFeature {
            }
        }

        private void executeMethodAsyncNoException(Runnable r, String errorLogName,
                Executor executor) {
            try {
                CompletableFuture.runAsync(
                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor).join();
            } catch (CancellationException | CompletionException e) {
                Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
                        + e.getMessage());
            }
        }

        private <T> T executeMethodAsyncForResult(Supplier<T> r,
                String errorLogName) throws RemoteException {
            CompletableFuture<T> future = CompletableFuture.supplyAsync(
@@ -385,16 +415,16 @@ public class MmTelFeature extends ImsFeature {
            }
        }

        @Override
        public void setTerminalBasedCallWaitingStatus(boolean enabled) throws RemoteException {
            synchronized (mLock) {
        private <T> T executeMethodAsyncForResultNoException(Supplier<T> r,
                String errorLogName, Executor executor) {
            CompletableFuture<T> future = CompletableFuture.supplyAsync(
                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), executor);
            try {
                    MmTelFeature.this.setTerminalBasedCallWaitingStatus(enabled);
                } catch (ServiceSpecificException se) {
                    throw new ServiceSpecificException(se.errorCode, se.getMessage());
                } catch (Exception e) {
                    throw new RemoteException(e.getMessage());
                }
                return future.get();
            } catch (ExecutionException | InterruptedException e) {
                Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
                        + e.getMessage());
                return null;
            }
        }
    };
@@ -995,6 +1025,19 @@ public class MmTelFeature extends ImsFeature {
        }
    }

    /**
     * @hide
     */
    public @NonNull ImsSmsImplBase getImsSmsImpl() {
        synchronized (mLock) {
            if (mSmsImpl == null) {
                mSmsImpl = getSmsImplementation();
                mSmsImpl.setDefaultExecutor(mExecutor);
            }
            return mSmsImpl;
        }
    }

    /**
     * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service
     * configuration.
@@ -1143,35 +1186,35 @@ public class MmTelFeature extends ImsFeature {
    }

    private void setSmsListener(IImsSmsListener listener) {
        getSmsImplementation().registerSmsListener(listener);
        getImsSmsImpl().registerSmsListener(listener);
    }

    private void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
            byte[] pdu) {
        getSmsImplementation().sendSms(token, messageRef, format, smsc, isRetry, pdu);
        getImsSmsImpl().sendSms(token, messageRef, format, smsc, isRetry, pdu);
    }

    private void onMemoryAvailable(int token) {
        getSmsImplementation().onMemoryAvailable(token);
        getImsSmsImpl().onMemoryAvailable(token);
    }

    private void acknowledgeSms(int token, int messageRef,
            @ImsSmsImplBase.DeliverStatusResult int result) {
        getSmsImplementation().acknowledgeSms(token, messageRef, result);
        getImsSmsImpl().acknowledgeSms(token, messageRef, result);
    }

    private void acknowledgeSms(int token, int messageRef,
            @ImsSmsImplBase.DeliverStatusResult int result, byte[] pdu) {
        getSmsImplementation().acknowledgeSms(token, messageRef, result, pdu);
        getImsSmsImpl().acknowledgeSms(token, messageRef, result, pdu);
    }

    private void acknowledgeSmsReport(int token, int messageRef,
            @ImsSmsImplBase.StatusReportResult int result) {
        getSmsImplementation().acknowledgeSmsReport(token, messageRef, result);
        getImsSmsImpl().acknowledgeSmsReport(token, messageRef, result);
    }

    private void onSmsReady() {
        getSmsImplementation().onReady();
        getImsSmsImpl().onReady();
    }

    /**
@@ -1188,7 +1231,7 @@ public class MmTelFeature extends ImsFeature {
    }

    private String getSmsFormat() {
        return getSmsImplementation().getSmsFormat();
        return getImsSmsImpl().getSmsFormat();
    }

    /**
+42 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.util.Log;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;

/**
 * Base implementation for SMS over IMS.
@@ -129,6 +130,22 @@ public class ImsSmsImplBase {
    // Lock for feature synchronization
    private final Object mLock = new Object();
    private IImsSmsListener mListener;
    private Executor mExecutor;

    /**
     * Create a new ImsSmsImplBase using the Executor set in MmTelFeature
     */
    public ImsSmsImplBase() {
    }

    /**
     * Create a new ImsSmsImplBase with specified executor.
     * <p>
     * @param executor Default executor for ImsSmsImplBase
     */
    public ImsSmsImplBase(@NonNull Executor executor) {
        mExecutor = executor;
    }

    /**
     * Registers a listener responsible for handling tasks like delivering messages.
@@ -482,4 +499,29 @@ public class ImsSmsImplBase {
    public void onReady() {
        // Base Implementation - Should be overridden
    }

    /**
     * Set default Executor for ImsSmsImplBase.
     *
     * @param executor The default executor for the framework to use when executing the methods
     * overridden by the implementation of ImsSms.
     * @hide
     */
    public final void setDefaultExecutor(@NonNull Executor executor) {
        if (mExecutor == null) {
            mExecutor = executor;
        }
    }

    /**
     * Get Executor from ImsSmsImplBase.
     * If there is no settings for the executor, all ImsSmsImplBase method calls will use
     * Runnable::run as default
     *
     * @return an Executor used to execute methods in ImsSms called remotely by the framework.
     * @hide
     */
    public @NonNull Executor getExecutor() {
        return mExecutor != null ? mExecutor : Runnable::run;
    }
}