summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt7
-rw-r--r--core/java/com/android/internal/util/OWNERS1
-rw-r--r--keystore/java/android/security/KeyStore2.java34
-rw-r--r--keystore/java/android/security/KeyStoreException.java10
-rw-r--r--keystore/java/android/security/KeyStoreOperation.java5
-rw-r--r--keystore/java/android/security/KeyStoreSecurityLevel.java6
-rw-r--r--keystore/tests/src/android/security/keystore/KeyStoreExceptionTest.java44
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java7
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java2
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java3
-rw-r--r--telephony/java/android/telephony/ims/ImsService.java133
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java271
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java21
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java146
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java377
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java38
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java37
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java114
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsUtImplBase.java109
-rw-r--r--telephony/java/android/telephony/ims/stub/SipTransportImplBase.java25
23 files changed, 1176 insertions, 271 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4480e041f52c..7fe3703fac0d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12926,6 +12926,7 @@ package android.telephony.ims {
method public void disableIms(int);
method public void enableIms(int);
method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
+ method @NonNull public java.util.concurrent.Executor getExecutor();
method public long getImsServiceCapabilities();
method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
@@ -13546,6 +13547,7 @@ package android.telephony.ims.feature {
public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
ctor public MmTelFeature();
+ ctor public MmTelFeature(@NonNull java.util.concurrent.Executor);
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
method public void changeOfferedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>);
method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
@@ -13579,7 +13581,7 @@ package android.telephony.ims.feature {
}
public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
- ctor @Deprecated public RcsFeature();
+ ctor public RcsFeature();
ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
@@ -13684,6 +13686,7 @@ package android.telephony.ims.stub {
}
public class ImsConfigImplBase {
+ ctor public ImsConfigImplBase(@NonNull java.util.concurrent.Executor);
ctor public ImsConfigImplBase();
method public int getConfigInt(int);
method public String getConfigString(int);
@@ -13736,6 +13739,7 @@ package android.telephony.ims.stub {
public class ImsRegistrationImplBase {
ctor public ImsRegistrationImplBase();
+ ctor public ImsRegistrationImplBase(@NonNull java.util.concurrent.Executor);
method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
method public final void onRegistered(int);
method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
@@ -13848,6 +13852,7 @@ package android.telephony.ims.stub {
}
public class SipTransportImplBase {
+ ctor public SipTransportImplBase();
ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor);
method public void createSipDelegate(int, @NonNull android.telephony.ims.DelegateRequest, @NonNull android.telephony.ims.DelegateStateCallback, @NonNull android.telephony.ims.DelegateMessageCallback);
method public void destroySipDelegate(@NonNull android.telephony.ims.stub.SipDelegate, int);
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 2b7f8b2749fd..354dd9a41586 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -4,3 +4,4 @@ per-file *Notification* = file:/services/core/java/com/android/server/notificati
per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
per-file Protocol* = etancohen@google.com, lorenzo@google.com
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
+per-file *Dump* = file:/core/java/com/android/internal/util/dump/OWNERS
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 1034847b761b..3d53cfb388e1 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -108,7 +108,7 @@ public class KeyStore2 {
try {
return request.execute(service);
} catch (ServiceSpecificException e) {
- throw getKeyStoreException(e.errorCode);
+ throw getKeyStoreException(e.errorCode, e.getMessage());
} catch (RemoteException e) {
if (firstTry) {
Log.w(TAG, "Looks like we may have lost connection to the Keystore "
@@ -120,7 +120,7 @@ public class KeyStore2 {
firstTry = false;
} else {
Log.e(TAG, "Cannot connect to Keystore daemon.", e);
- throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, "");
+ throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, "", e.getMessage());
}
}
}
@@ -322,26 +322,32 @@ public class KeyStore2 {
}
}
- static KeyStoreException getKeyStoreException(int errorCode) {
+ static KeyStoreException getKeyStoreException(int errorCode, String serviceErrorMessage) {
if (errorCode > 0) {
// KeyStore layer error
switch (errorCode) {
case ResponseCode.LOCKED:
- return new KeyStoreException(errorCode, "User authentication required");
+ return new KeyStoreException(errorCode, "User authentication required",
+ serviceErrorMessage);
case ResponseCode.UNINITIALIZED:
- return new KeyStoreException(errorCode, "Keystore not initialized");
+ return new KeyStoreException(errorCode, "Keystore not initialized",
+ serviceErrorMessage);
case ResponseCode.SYSTEM_ERROR:
- return new KeyStoreException(errorCode, "System error");
+ return new KeyStoreException(errorCode, "System error", serviceErrorMessage);
case ResponseCode.PERMISSION_DENIED:
- return new KeyStoreException(errorCode, "Permission denied");
+ return new KeyStoreException(errorCode, "Permission denied",
+ serviceErrorMessage);
case ResponseCode.KEY_NOT_FOUND:
- return new KeyStoreException(errorCode, "Key not found");
+ return new KeyStoreException(errorCode, "Key not found", serviceErrorMessage);
case ResponseCode.VALUE_CORRUPTED:
- return new KeyStoreException(errorCode, "Key blob corrupted");
+ return new KeyStoreException(errorCode, "Key blob corrupted",
+ serviceErrorMessage);
case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
- return new KeyStoreException(errorCode, "Key permanently invalidated");
+ return new KeyStoreException(errorCode, "Key permanently invalidated",
+ serviceErrorMessage);
default:
- return new KeyStoreException(errorCode, String.valueOf(errorCode));
+ return new KeyStoreException(errorCode, String.valueOf(errorCode),
+ serviceErrorMessage);
}
} else {
// Keymaster layer error
@@ -350,10 +356,12 @@ public class KeyStore2 {
// The name of this parameter significantly differs between Keymaster and
// framework APIs. Use the framework wording to make life easier for developers.
return new KeyStoreException(errorCode,
- "Invalid user authentication validity duration");
+ "Invalid user authentication validity duration",
+ serviceErrorMessage);
default:
return new KeyStoreException(errorCode,
- KeymasterDefs.getErrorMessage(errorCode));
+ KeymasterDefs.getErrorMessage(errorCode),
+ serviceErrorMessage);
}
}
}
diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java
index 6db2745840f4..54184dbf6e08 100644
--- a/keystore/java/android/security/KeyStoreException.java
+++ b/keystore/java/android/security/KeyStoreException.java
@@ -158,6 +158,16 @@ public class KeyStoreException extends Exception {
}
/**
+ * @hide
+ */
+ public KeyStoreException(int errorCode, @Nullable String message,
+ @Nullable String keystoreErrorMessage) {
+ super(message + " (internal Keystore code: " + errorCode + " message: "
+ + keystoreErrorMessage + ")");
+ mErrorCode = errorCode;
+ }
+
+ /**
* Returns the internal error code. Only for use by the platform.
*
* @hide
diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java
index e6c1ea827118..737ff2b4822f 100644
--- a/keystore/java/android/security/KeyStoreOperation.java
+++ b/keystore/java/android/security/KeyStoreOperation.java
@@ -75,7 +75,7 @@ public class KeyStoreOperation {
);
}
default:
- throw KeyStore2.getKeyStoreException(e.errorCode);
+ throw KeyStore2.getKeyStoreException(e.errorCode, e.getMessage());
}
} catch (RemoteException e) {
// Log exception and report invalid operation handle.
@@ -85,7 +85,8 @@ public class KeyStoreOperation {
"Remote exception while advancing a KeyStoreOperation.",
e
);
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, "");
+ throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, "",
+ e.getMessage());
}
}
diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java
index b85dd742cc49..9c0b46c8e87b 100644
--- a/keystore/java/android/security/KeyStoreSecurityLevel.java
+++ b/keystore/java/android/security/KeyStoreSecurityLevel.java
@@ -54,12 +54,12 @@ public class KeyStoreSecurityLevel {
try {
return request.execute();
} catch (ServiceSpecificException e) {
- throw KeyStore2.getKeyStoreException(e.errorCode);
+ throw KeyStore2.getKeyStoreException(e.errorCode, e.getMessage());
} catch (RemoteException e) {
// Log exception and report invalid operation handle.
// This should prompt the caller drop the reference to this operation and retry.
Log.e(TAG, "Could not connect to Keystore.", e);
- throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, "");
+ throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, "", e.getMessage());
}
}
@@ -117,7 +117,7 @@ public class KeyStoreSecurityLevel {
break;
}
default:
- throw KeyStore2.getKeyStoreException(e.errorCode);
+ throw KeyStore2.getKeyStoreException(e.errorCode, e.getMessage());
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/tests/src/android/security/keystore/KeyStoreExceptionTest.java b/keystore/tests/src/android/security/keystore/KeyStoreExceptionTest.java
new file mode 100644
index 000000000000..31c742289a61
--- /dev/null
+++ b/keystore/tests/src/android/security/keystore/KeyStoreExceptionTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import static org.junit.Assert.assertTrue;
+
+import android.security.KeyStoreException;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class KeyStoreExceptionTest {
+ @Test
+ public void testKeystoreMessageIsIncluded() {
+ final String primaryMessage = "some_message";
+ final String keystoreMessage = "ks_message";
+ KeyStoreException exception = new KeyStoreException(-1, primaryMessage, keystoreMessage);
+
+ String exceptionMessage = exception.getMessage();
+ assertTrue(exceptionMessage.contains(primaryMessage));
+ assertTrue(exceptionMessage.contains(keystoreMessage));
+
+ String exceptionString = exception.toString();
+ assertTrue(exceptionString.contains(primaryMessage));
+ assertTrue(exceptionString.contains(keystoreMessage));
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 27f22c4f2e88..c12522b43f2a 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -75,6 +75,8 @@ abstract class HdmiCecLocalDevice {
protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
protected int mLastKeyRepeatCount = 0;
+ HdmiCecStandbyModeHandler mStandbyHandler;
+
// Stores recent changes to the active source in the CEC network.
private final ArrayBlockingQueue<HdmiCecController.Dumpable> mActiveSourceHistory =
new ArrayBlockingQueue<>(MAX_HDMI_ACTIVE_SOURCE_HISTORY);
@@ -263,6 +265,11 @@ abstract class HdmiCecLocalDevice {
if (dest != mAddress && dest != Constants.ADDR_BROADCAST) {
return Constants.NOT_HANDLED;
}
+ if (mService.isPowerStandby()
+ && !mService.isWakeUpMessageReceived()
+ && mStandbyHandler.handleCommand(message)) {
+ return Constants.HANDLED;
+ }
// Cache incoming message if it is included in the list of cacheable opcodes.
mCecMessageCache.cacheMessage(message);
return onMessage(message);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 0bb128536b42..c549b5598b67 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -112,6 +112,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
mSystemAudioControlFeatureEnabled =
mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
+ mStandbyHandler = new HdmiCecStandbyModeHandler(service, this);
}
private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 37ee76b7c615..40718585c484 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -64,6 +64,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
HdmiCecLocalDevicePlayback(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ mStandbyHandler = new HdmiCecStandbyModeHandler(service, this);
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 6e7a2a0eb229..3d218cffc5df 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -91,8 +91,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@GuardedBy("mLock")
private boolean mSystemAudioMute = false;
- private final HdmiCecStandbyModeHandler mStandbyHandler;
-
// If true, do not do routing control/send active source for internal source.
// Set to true when the device was woken up by <Text/Image View On>.
private boolean mSkipRoutingControl;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
index 57fe9e6a4acc..1c296e5b5640 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
@@ -16,6 +16,7 @@
package com.android.server.hdmi;
+import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.SparseArray;
/**
@@ -56,7 +57,8 @@ public final class HdmiCecStandbyModeHandler {
private final class AutoOnHandler implements CecMessageHandler {
@Override
public boolean handle(HdmiCecMessage message) {
- if (!mTv.getAutoWakeup()) {
+ HdmiCecLocalDeviceTv tv = (HdmiCecLocalDeviceTv) mDevice;
+ if (!tv.getAutoWakeup()) {
mAborterRefused.handle(message);
return true;
}
@@ -78,7 +80,7 @@ public final class HdmiCecStandbyModeHandler {
}
private final HdmiControlService mService;
- private final HdmiCecLocalDeviceTv mTv;
+ private final HdmiCecLocalDevice mDevice;
private final SparseArray<CecMessageHandler> mCecMessageHandlers = new SparseArray<>();
private final CecMessageHandler mDefaultHandler = new Aborter(
@@ -92,13 +94,7 @@ public final class HdmiCecStandbyModeHandler {
private final UserControlProcessedHandler
mUserControlProcessedHandler = new UserControlProcessedHandler();
- public HdmiCecStandbyModeHandler(HdmiControlService service, HdmiCecLocalDeviceTv tv) {
- mService = service;
- mTv = tv;
-
- addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler);
- addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler);
-
+ private void addCommonHandlers() {
addHandler(Constants.MESSAGE_ACTIVE_SOURCE, mBystander);
addHandler(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, mBystander);
addHandler(Constants.MESSAGE_ROUTING_CHANGE, mBystander);
@@ -112,19 +108,6 @@ public final class HdmiCecStandbyModeHandler {
addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander);
addHandler(Constants.MESSAGE_REPORT_AUDIO_STATUS, mBystander);
- // If TV supports the following messages during power-on, ignore them and do nothing,
- // else reply with <Feature Abort>["Unrecognized Opcode"]
- // <Deck Status>, <Tuner Device Status>, <Tuner Cleared Status>, <Timer Status>
- addHandler(Constants.MESSAGE_RECORD_STATUS, mBystander);
-
- // If TV supports the following messages during power-on, reply with <Feature Abort>["Not
- // in correct mode to respond"], else reply with <Feature Abort>["Unrecognized Opcode"]
- // <Give Tuner Device Status>, <Select Digital Service>, <Tuner Step Decrement>,
- // <Tuner Stem Increment>, <Menu Status>.
- addHandler(Constants.MESSAGE_RECORD_TV_SCREEN, mAborterIncorrectMode);
- addHandler(Constants.MESSAGE_INITIATE_ARC, mAborterIncorrectMode);
- addHandler(Constants.MESSAGE_TERMINATE_ARC, mAborterIncorrectMode);
-
addHandler(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, mBypasser);
addHandler(Constants.MESSAGE_GET_MENU_LANGUAGE, mBypasser);
addHandler(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, mBypasser);
@@ -145,6 +128,34 @@ public final class HdmiCecStandbyModeHandler {
addHandler(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, mAborterIncorrectMode);
}
+ private void addTvHandlers() {
+ addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler);
+ addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler);
+
+ // If TV supports the following messages during power-on, ignore them and do nothing,
+ // else reply with <Feature Abort>["Unrecognized Opcode"]
+ // <Deck Status>, <Tuner Device Status>, <Tuner Cleared Status>, <Timer Status>
+ addHandler(Constants.MESSAGE_RECORD_STATUS, mBystander);
+
+ // If TV supports the following messages during power-on, reply with <Feature Abort>["Not
+ // in correct mode to respond"], else reply with <Feature Abort>["Unrecognized Opcode"]
+ // <Give Tuner Device Status>, <Select Digital Service>, <Tuner Step Decrement>,
+ // <Tuner Stem Increment>, <Menu Status>.
+ addHandler(Constants.MESSAGE_RECORD_TV_SCREEN, mAborterIncorrectMode);
+ addHandler(Constants.MESSAGE_INITIATE_ARC, mAborterIncorrectMode);
+ addHandler(Constants.MESSAGE_TERMINATE_ARC, mAborterIncorrectMode);
+ }
+
+ public HdmiCecStandbyModeHandler(HdmiControlService service, HdmiCecLocalDevice device) {
+ mService = service;
+ mDevice = device;
+
+ addCommonHandlers();
+ if (mDevice.getType() == HdmiDeviceInfo.DEVICE_TV) {
+ addTvHandlers();
+ }
+ }
+
private void addHandler(int opcode, CecMessageHandler handler) {
mCecMessageHandlers.put(opcode, handler);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 4c39768a8de7..77e49addf79f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -892,6 +892,7 @@ public class HdmiControlServiceTest {
int sourceAddress = Constants.ADDR_TV;
byte[] params = {0x00, 0x01, 0x02, 0x03};
int vendorId = 0x123456;
+ mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
VendorCommandListener vendorCmdListener =
new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
@@ -913,6 +914,7 @@ public class HdmiControlServiceTest {
int sourceAddress = Constants.ADDR_TV;
byte[] params = {0x00, 0x01, 0x02, 0x03};
int vendorId = 0x123456;
+ mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
VendorCommandListener vendorCmdListener =
new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
@@ -936,6 +938,7 @@ public class HdmiControlServiceTest {
byte[] params = {0x00, 0x01, 0x02, 0x03};
int vendorId = 0x123456;
int diffVendorId = 0x345678;
+ mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
VendorCommandListener vendorCmdListener =
new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 9ab5aeb9c34c..53dff545b0ce 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.LongDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -44,11 +45,18 @@ import android.util.SparseArray;
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
@@ -173,7 +181,21 @@ public class ImsService extends Service {
private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
private IImsServiceControllerListener mListener;
+ private Executor mExecutor;
+ /**
+ * Create a new ImsService.
+ * <p>
+ * Method stubs called from the framework will be called asynchronously. Vendor specifies the
+ * {@link Executor} that the methods stubs will be called. If mExecutor is set to null by
+ * vendor use Runnable::run.
+ */
+ public ImsService() {
+ mExecutor = ImsService.this.getExecutor();
+ if (mExecutor == null) {
+ mExecutor = Runnable::run;
+ }
+ }
/**
* Listener that notifies the framework of ImsService changes.
@@ -201,78 +223,132 @@ public class ImsService extends Service {
@Override
public IImsMmTelFeature createMmTelFeature(int slotId) {
- return createMmTelFeatureInternal(slotId);
+ return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId),
+ "createMmTelFeature");
}
@Override
public IImsRcsFeature createRcsFeature(int slotId) {
- return createRcsFeatureInternal(slotId);
+ return executeMethodAsyncForResult(() -> createRcsFeatureInternal(slotId),
+ "createRcsFeature");
}
@Override
public void addFeatureStatusCallback(int slotId, int featureType,
IImsFeatureStatusCallback c) {
- ImsService.this.addImsFeatureStatusCallback(slotId, featureType, c);
+ executeMethodAsync(() -> ImsService.this.addImsFeatureStatusCallback(
+ slotId, featureType, c), "addFeatureStatusCallback");
}
@Override
public void removeFeatureStatusCallback(int slotId, int featureType,
IImsFeatureStatusCallback c) {
- ImsService.this.removeImsFeatureStatusCallback(slotId, featureType, c);
+ executeMethodAsync(() -> ImsService.this.removeImsFeatureStatusCallback(
+ slotId, featureType, c), "removeFeatureStatusCallback");
}
@Override
public void removeImsFeature(int slotId, int featureType) {
- ImsService.this.removeImsFeature(slotId, featureType);
+ executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType),
+ "removeImsFeature");
}
@Override
public ImsFeatureConfiguration querySupportedImsFeatures() {
- return ImsService.this.querySupportedImsFeatures();
+ return executeMethodAsyncForResult(() -> ImsService.this.querySupportedImsFeatures(),
+ "ImsFeatureConfiguration");
}
@Override
public long getImsServiceCapabilities() {
- long caps = ImsService.this.getImsServiceCapabilities();
- long sanitizedCaps = sanitizeCapabilities(caps);
- if (caps != sanitizedCaps) {
- Log.w(LOG_TAG, "removing invalid bits from field: 0x"
- + Long.toHexString(caps ^ sanitizedCaps));
- }
- return sanitizedCaps;
+ return executeMethodAsyncForResult(() -> {
+ long caps = ImsService.this.getImsServiceCapabilities();
+ long sanitizedCaps = sanitizeCapabilities(caps);
+ if (caps != sanitizedCaps) {
+ Log.w(LOG_TAG, "removing invalid bits from field: 0x"
+ + Long.toHexString(caps ^ sanitizedCaps));
+ }
+ return sanitizedCaps;
+ }, "getImsServiceCapabilities");
}
@Override
public void notifyImsServiceReadyForFeatureCreation() {
- ImsService.this.readyForFeatureCreation();
+ executeMethodAsync(() -> ImsService.this.readyForFeatureCreation(),
+ "notifyImsServiceReadyForFeatureCreation");
}
@Override
public IImsConfig getConfig(int slotId) {
- ImsConfigImplBase c = ImsService.this.getConfig(slotId);
- return c != null ? c.getIImsConfig() : null;
+ return executeMethodAsyncForResult(() -> {
+ ImsConfigImplBase c = ImsService.this.getConfig(slotId);
+ if (c != null) {
+ c.setDefaultExecutor(mExecutor);
+ return c.getIImsConfig();
+ } else {
+ return null;
+ }
+ }, "getConfig");
}
@Override
public IImsRegistration getRegistration(int slotId) {
- ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
- return r != null ? r.getBinder() : null;
+ return executeMethodAsyncForResult(() -> {
+ ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
+ if (r != null) {
+ r.setDefaultExecutor(mExecutor);
+ return r.getBinder();
+ } else {
+ return null;
+ }
+ }, "getRegistration");
}
@Override
public ISipTransport getSipTransport(int slotId) {
- SipTransportImplBase s = ImsService.this.getSipTransport(slotId);
- return s != null ? s.getBinder() : null;
+ return executeMethodAsyncForResult(() -> {
+ SipTransportImplBase s = ImsService.this.getSipTransport(slotId);
+ if (s != null) {
+ s.setDefaultExecutor(mExecutor);
+ return s.getBinder();
+ } else {
+ return null;
+ }
+ }, "getSipTransport");
}
@Override
public void enableIms(int slotId) {
- ImsService.this.enableIms(slotId);
+ executeMethodAsync(() -> ImsService.this.enableIms(slotId), "enableIms");
}
@Override
public void disableIms(int slotId) {
- ImsService.this.disableIms(slotId);
+ executeMethodAsync(() -> ImsService.this.disableIms(slotId), "disableIms");
+ }
+
+ // 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) {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) {
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ return null;
+ }
}
};
@@ -300,6 +376,7 @@ public class ImsService extends Service {
MmTelFeature f = createMmTelFeature(slotId);
if (f != null) {
setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
+ f.setDefaultExecutor(mExecutor);
return f.getBinder();
} else {
Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
@@ -310,6 +387,7 @@ public class ImsService extends Service {
private IImsRcsFeature createRcsFeatureInternal(int slotId) {
RcsFeature f = createRcsFeature(slotId);
if (f != null) {
+ f.setDefaultExecutor(mExecutor);
setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
return f.getBinder();
} else {
@@ -562,4 +640,15 @@ public class ImsService extends Service {
result.append("}");
return result.toString();
}
+
+ /**
+ * The ImsService will now be able to define an Executor that the ImsService can be used to
+ * execute the methods. By default all ImsService level method calls will use this Executor.
+ * The ImsService has set the default executor as Runnable::run,
+ * Should be override or default executor will be used.
+ * @return an Executor used to execute methods called remotely by the framework.
+ */
+ public @NonNull Executor getExecutor() {
+ return Runnable::run;
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 9a3f592480d1..7fdf21b3e5ff 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -40,16 +40,25 @@ import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.ImsSmsImplBase;
import android.telephony.ims.stub.ImsUtImplBase;
import android.util.ArraySet;
+import android.util.Log;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsUt;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
/**
* Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support.
@@ -60,6 +69,7 @@ import java.util.Set;
public class MmTelFeature extends ImsFeature {
private static final String LOG_TAG = "MmTelFeature";
+ private Executor mExecutor;
/**
* @hide
@@ -68,160 +78,261 @@ public class MmTelFeature extends ImsFeature {
public MmTelFeature() {
}
+ /**
+ * Create a new MmTelFeature using the Executor specified for methods being called by the
+ * framework.
+ * @param executor The executor for the framework to use when executing the methods overridden
+ * by the implementation of MmTelFeature.
+ * @hide
+ */
+ @SystemApi
+ public MmTelFeature(@NonNull Executor executor) {
+ super();
+ mExecutor = executor;
+ }
+
private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
@Override
public void setListener(IImsMmTelListener l) {
- MmTelFeature.this.setListener(l);
+ executeMethodAsyncNoException(() -> MmTelFeature.this.setListener(l), "setListener");
}
@Override
public int getFeatureState() throws RemoteException {
- try {
- return MmTelFeature.this.getFeatureState();
- } catch (Exception e) {
- throw new RemoteException(e.getMessage());
- }
+ return executeMethodAsyncForResult(() -> MmTelFeature.this.getFeatureState(),
+ "getFeatureState");
}
-
@Override
public ImsCallProfile createCallProfile(int callSessionType, int callType)
throws RemoteException {
- synchronized (mLock) {
- try {
- return MmTelFeature.this.createCallProfile(callSessionType, callType);
- } catch (Exception e) {
- throw new RemoteException(e.getMessage());
- }
- }
+ return executeMethodAsyncForResult(() -> MmTelFeature.this.createCallProfile(
+ callSessionType, callType), "createCallProfile");
}
@Override
public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types)
throws RemoteException {
- synchronized (mLock) {
- try {
- MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(new ArraySet<>(types));
- } catch (Exception e) {
- throw new RemoteException(e.getMessage());
- }
- }
+ executeMethodAsync(() -> MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(
+ new ArraySet<>(types)), "changeOfferedRtpHeaderExtensionTypes");
}
@Override
public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
- synchronized (mLock) {
- return createCallSessionInterface(profile);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ IImsCallSession result = executeMethodAsyncForResult(() -> {
+ try {
+ return createCallSessionInterface(profile);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return null;
+ }
+ }, "createCallSession");
+
+ if (exceptionRef.get() != null) {
+ throw exceptionRef.get();
}
+
+ return result;
}
@Override
public int shouldProcessCall(String[] numbers) {
- synchronized (mLock) {
- return MmTelFeature.this.shouldProcessCall(numbers);
+ Integer result = executeMethodAsyncForResultNoException(() ->
+ MmTelFeature.this.shouldProcessCall(numbers), "shouldProcessCall");
+ if (result != null) {
+ return result.intValue();
+ } else {
+ return PROCESS_CALL_CSFB;
}
}
@Override
public IImsUt getUtInterface() throws RemoteException {
- synchronized (mLock) {
- return MmTelFeature.this.getUtInterface();
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ IImsUt result = executeMethodAsyncForResult(() -> {
+ try {
+ return MmTelFeature.this.getUtInterface();
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return null;
+ }
+ }, "getUtInterface");
+
+ if (exceptionRef.get() != null) {
+ throw exceptionRef.get();
}
+
+ return result;
}
@Override
public IImsEcbm getEcbmInterface() throws RemoteException {
- synchronized (mLock) {
- return MmTelFeature.this.getEcbmInterface();
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ IImsEcbm result = executeMethodAsyncForResult(() -> {
+ try {
+ return MmTelFeature.this.getEcbmInterface();
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return null;
+ }
+ }, "getEcbmInterface");
+
+ if (exceptionRef.get() != null) {
+ throw exceptionRef.get();
}
+
+ return result;
}
@Override
public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException {
- synchronized (mLock) {
- try {
- MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage);
- } catch (Exception e) {
- throw new RemoteException(e.getMessage());
- }
- }
+ executeMethodAsync(() -> MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage),
+ "setUiTtyMode");
}
@Override
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
- synchronized (mLock) {
- return MmTelFeature.this.getMultiEndpointInterface();
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ IImsMultiEndpoint result = executeMethodAsyncForResult(() -> {
+ try {
+ return MmTelFeature.this.getMultiEndpointInterface();
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return null;
+ }
+ }, "getMultiEndpointInterface");
+
+ if (exceptionRef.get() != null) {
+ throw exceptionRef.get();
}
+
+ return result;
}
@Override
public int queryCapabilityStatus() {
- return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
+ Integer result = executeMethodAsyncForResultNoException(() -> MmTelFeature.this
+ .queryCapabilityStatus().mCapabilities, "queryCapabilityStatus");
+
+ if (result != null) {
+ return result.intValue();
+ } else {
+ return 0;
+ }
}
@Override
public void addCapabilityCallback(IImsCapabilityCallback c) {
- // no need to lock, structure already handles multithreading.
- MmTelFeature.this.addCapabilityCallback(c);
+ executeMethodAsyncNoException(() -> MmTelFeature.this
+ .addCapabilityCallback(c), "addCapabilityCallback");
}
@Override
public void removeCapabilityCallback(IImsCapabilityCallback c) {
- // no need to lock, structure already handles multithreading.
- MmTelFeature.this.removeCapabilityCallback(c);
+ executeMethodAsyncNoException(() -> MmTelFeature.this
+ .removeCapabilityCallback(c), "removeCapabilityCallback");
}
@Override
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
IImsCapabilityCallback c) {
- MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
+ executeMethodAsyncNoException(() -> MmTelFeature.this
+ .requestChangeEnabledCapabilities(request, c),
+ "changeCapabilitiesConfiguration");
}
@Override
public void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c) {
- queryCapabilityConfigurationInternal(capability, radioTech, c);
+ executeMethodAsyncNoException(() -> queryCapabilityConfigurationInternal(
+ capability, radioTech, c), "queryCapabilityConfiguration");
}
@Override
public void setSmsListener(IImsSmsListener l) {
- MmTelFeature.this.setSmsListener(l);
+ executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l),
+ "setSmsListener");
}
@Override
public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
byte[] pdu) {
- synchronized (mLock) {
- MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu);
- }
+ executeMethodAsyncNoException(() -> MmTelFeature.this
+ .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms");
}
@Override
public void acknowledgeSms(int token, int messageRef, int result) {
- synchronized (mLock) {
- MmTelFeature.this.acknowledgeSms(token, messageRef, result);
- }
+ executeMethodAsyncNoException(() -> MmTelFeature.this
+ .acknowledgeSms(token, messageRef, result), "acknowledgeSms");
}
@Override
public void acknowledgeSmsReport(int token, int messageRef, int result) {
- synchronized (mLock) {
- MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result);
- }
+ executeMethodAsyncNoException(() -> MmTelFeature.this
+ .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport");
}
@Override
public String getSmsFormat() {
- synchronized (mLock) {
- return MmTelFeature.this.getSmsFormat();
- }
+ return executeMethodAsyncForResultNoException(() -> MmTelFeature.this
+ .getSmsFormat(), "getSmsFormat");
}
@Override
public void onSmsReady() {
- synchronized (mLock) {
- MmTelFeature.this.onSmsReady();
+ executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(),
+ "onSmsReady");
+ }
+
+ // 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 {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
+ }
+
+ private void executeMethodAsyncNoException(Runnable r, String errorLogName) {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).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(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResultNoException(Supplier<T> r,
+ String errorLogName) {
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ return null;
}
}
};
@@ -672,7 +783,12 @@ public class MmTelFeature extends ImsFeature {
public IImsCallSession createCallSessionInterface(ImsCallProfile profile)
throws RemoteException {
ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile);
- return s != null ? s.getServiceImpl() : null;
+ if (s != null) {
+ s.setDefaultExecutor(mExecutor);
+ return s.getServiceImpl();
+ } else {
+ return null;
+ }
}
/**
@@ -713,7 +829,12 @@ public class MmTelFeature extends ImsFeature {
*/
protected IImsUt getUtInterface() throws RemoteException {
ImsUtImplBase utImpl = getUt();
- return utImpl != null ? utImpl.getInterface() : null;
+ if (utImpl != null) {
+ utImpl.setDefaultExecutor(mExecutor);
+ return utImpl.getInterface();
+ } else {
+ return null;
+ }
}
/**
@@ -721,7 +842,12 @@ public class MmTelFeature extends ImsFeature {
*/
protected IImsEcbm getEcbmInterface() throws RemoteException {
ImsEcbmImplBase ecbmImpl = getEcbm();
- return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null;
+ if (ecbmImpl != null) {
+ ecbmImpl.setDefaultExecutor(mExecutor);
+ return ecbmImpl.getImsEcbm();
+ } else {
+ return null;
+ }
}
/**
@@ -729,7 +855,12 @@ public class MmTelFeature extends ImsFeature {
*/
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint();
- return multiendpointImpl != null ? multiendpointImpl.getIImsMultiEndpoint() : null;
+ if (multiendpointImpl != null) {
+ multiendpointImpl.setDefaultExecutor(mExecutor);
+ return multiendpointImpl.getIImsMultiEndpoint();
+ } else {
+ return null;
+ }
}
/**
@@ -859,4 +990,16 @@ public class MmTelFeature extends ImsFeature {
public final IImsMmTelFeature getBinder() {
return mImsMMTelBinder;
}
+
+ /**
+ * Set default Executor from ImsService.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of MmTelFeature.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ if (mExecutor == null) {
+ mExecutor = executor;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 18cc37d7fbda..11cf0e3f7855 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -70,7 +70,7 @@ public class RcsFeature extends ImsFeature {
// Reference the outer class in order to have better test coverage metrics instead of
// creating a inner class referencing the outer class directly.
private final RcsFeature mReference;
- private final Executor mExecutor;
+ private Executor mExecutor;
RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) {
mReference = classRef;
@@ -259,7 +259,7 @@ public class RcsFeature extends ImsFeature {
}
}
- private final Executor mExecutor;
+ private Executor mExecutor;
private final RcsFeatureBinder mImsRcsBinder;
private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl;
private CapabilityExchangeEventListener mCapExchangeEventListener;
@@ -270,13 +270,9 @@ public class RcsFeature extends ImsFeature {
* Method stubs called from the framework will be called asynchronously. To specify the
* {@link Executor} that the methods stubs will be called, use
* {@link RcsFeature#RcsFeature(Executor)} instead.
- *
- * @deprecated Use {@link #RcsFeature(Executor)} to create the RcsFeature.
*/
- @Deprecated
public RcsFeature() {
super();
- mExecutor = Runnable::run;
// Run on the Binder threads that call them.
mImsRcsBinder = new RcsFeatureBinder(this, mExecutor);
}
@@ -477,4 +473,17 @@ public class RcsFeature extends ImsFeature {
return mCapabilityExchangeImpl;
}
}
+
+ /**
+ * Set default Executor from ImsService.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of RcsFeature.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ if (mImsRcsBinder.mExecutor == null) {
+ mExecutor = executor;
+ mImsRcsBinder.mExecutor = executor;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index a3a6cb864fa5..e8100957517f 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -30,12 +30,20 @@ import android.telephony.ims.RtpHeaderExtension;
import android.telephony.ims.RtpHeaderExtensionType;
import android.telephony.ims.aidl.IImsCallSessionListener;
import android.util.ArraySet;
+import android.util.Log;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* Base implementation of IImsCallSession, which implements stub versions of the methods available.
@@ -48,6 +56,8 @@ import java.util.Set;
// DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
// will break other implementations of ImsCallSession maintained by other ImsServices.
public class ImsCallSessionImplBase implements AutoCloseable {
+
+ private static final String LOG_TAG = "ImsCallSessionImplBase";
/**
* Notify USSD Mode.
*/
@@ -110,185 +120,235 @@ public class ImsCallSessionImplBase implements AutoCloseable {
}
}
+ private Executor mExecutor = Runnable::run;
+
// Non-final for injection by tests
private IImsCallSession mServiceImpl = new IImsCallSession.Stub() {
@Override
public void close() {
- ImsCallSessionImplBase.this.close();
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.close(), "close");
}
@Override
public String getCallId() {
- return ImsCallSessionImplBase.this.getCallId();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallId(),
+ "getCallId");
}
@Override
public ImsCallProfile getCallProfile() {
- return ImsCallSessionImplBase.this.getCallProfile();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallProfile(),
+ "getCallProfile");
}
@Override
public ImsCallProfile getLocalCallProfile() {
- return ImsCallSessionImplBase.this.getLocalCallProfile();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
+ .getLocalCallProfile(), "getLocalCallProfile");
}
@Override
public ImsCallProfile getRemoteCallProfile() {
- return ImsCallSessionImplBase.this.getRemoteCallProfile();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
+ .getRemoteCallProfile(), "getRemoteCallProfile");
}
@Override
public String getProperty(String name) {
- return ImsCallSessionImplBase.this.getProperty(name);
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getProperty(name),
+ "getProperty");
}
@Override
public int getState() {
- return ImsCallSessionImplBase.this.getState();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getState(),
+ "getState");
}
@Override
public boolean isInCall() {
- return ImsCallSessionImplBase.this.isInCall();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isInCall(),
+ "isInCall");
}
@Override
public void setListener(IImsCallSessionListener listener) {
- ImsCallSessionImplBase.this.setListener(new ImsCallSessionListener(listener));
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.setListener(
+ new ImsCallSessionListener(listener)), "setListener");
}
@Override
public void setMute(boolean muted) {
- ImsCallSessionImplBase.this.setMute(muted);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.setMute(muted), "setMute");
}
@Override
public void start(String callee, ImsCallProfile profile) {
- ImsCallSessionImplBase.this.start(callee, profile);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.start(callee, profile), "start");
}
@Override
public void startConference(String[] participants, ImsCallProfile profile) throws
RemoteException {
- ImsCallSessionImplBase.this.startConference(participants, profile);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.startConference(participants,
+ profile), "startConference");
}
@Override
public void accept(int callType, ImsStreamMediaProfile profile) {
- ImsCallSessionImplBase.this.accept(callType, profile);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.accept(callType, profile),
+ "accept");
}
@Override
public void deflect(String deflectNumber) {
- ImsCallSessionImplBase.this.deflect(deflectNumber);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.deflect(deflectNumber),
+ "deflect");
}
@Override
public void reject(int reason) {
- ImsCallSessionImplBase.this.reject(reason);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.reject(reason), "reject");
}
@Override
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
- ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.transfer(number,
+ isConfirmationRequired), "transfer");
}
@Override
public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
- ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
- otherSession.setServiceImpl(transferToSession);
- ImsCallSessionImplBase.this.transfer(otherSession);
+ executeMethodAsync(() -> {
+ ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
+ otherSession.setServiceImpl(transferToSession);
+ ImsCallSessionImplBase.this.transfer(otherSession);
+ }, "consultativeTransfer");
}
@Override
public void terminate(int reason) {
- ImsCallSessionImplBase.this.terminate(reason);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.terminate(reason), "terminate");
}
@Override
public void hold(ImsStreamMediaProfile profile) {
- ImsCallSessionImplBase.this.hold(profile);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.hold(profile), "hold");
}
@Override
public void resume(ImsStreamMediaProfile profile) {
- ImsCallSessionImplBase.this.resume(profile);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.resume(profile), "resume");
}
@Override
public void merge() {
- ImsCallSessionImplBase.this.merge();
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.merge(), "merge");
}
@Override
public void update(int callType, ImsStreamMediaProfile profile) {
- ImsCallSessionImplBase.this.update(callType, profile);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.update(callType, profile),
+ "update");
}
@Override
public void extendToConference(String[] participants) {
- ImsCallSessionImplBase.this.extendToConference(participants);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.extendToConference(participants),
+ "extendToConference");
}
@Override
public void inviteParticipants(String[] participants) {
- ImsCallSessionImplBase.this.inviteParticipants(participants);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.inviteParticipants(participants),
+ "inviteParticipants");
}
@Override
public void removeParticipants(String[] participants) {
- ImsCallSessionImplBase.this.removeParticipants(participants);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.removeParticipants(participants),
+ "removeParticipants");
}
@Override
public void sendDtmf(char c, Message result) {
- ImsCallSessionImplBase.this.sendDtmf(c, result);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.sendDtmf(c, result), "sendDtmf");
}
@Override
public void startDtmf(char c) {
- ImsCallSessionImplBase.this.startDtmf(c);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.startDtmf(c), "startDtmf");
}
@Override
public void stopDtmf() {
- ImsCallSessionImplBase.this.stopDtmf();
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.stopDtmf(), "stopDtmf");
}
@Override
public void sendUssd(String ussdMessage) {
- ImsCallSessionImplBase.this.sendUssd(ussdMessage);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.sendUssd(ussdMessage), "sendUssd");
}
@Override
public IImsVideoCallProvider getVideoCallProvider() {
- return ImsCallSessionImplBase.this.getVideoCallProvider();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
+ .getVideoCallProvider(), "getVideoCallProvider");
}
@Override
public boolean isMultiparty() {
- return ImsCallSessionImplBase.this.isMultiparty();
+ return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isMultiparty(),
+ "isMultiparty");
}
@Override
public void sendRttModifyRequest(ImsCallProfile toProfile) {
- ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile),
+ "sendRttModifyRequest");
}
@Override
public void sendRttModifyResponse(boolean status) {
- ImsCallSessionImplBase.this.sendRttModifyResponse(status);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyResponse(status),
+ "sendRttModifyResponse");
}
@Override
public void sendRttMessage(String rttMessage) {
- ImsCallSessionImplBase.this.sendRttMessage(rttMessage);
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttMessage(rttMessage),
+ "sendRttMessage");
}
@Override
public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) {
- ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
- new ArraySet<RtpHeaderExtension>(extensions));
+ executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
+ new ArraySet<RtpHeaderExtension>(extensions)), "sendRtpHeaderExtensions");
+ }
+
+ // 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) {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResult(Supplier<T> r,
+ String errorLogName) {
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ return null;
+ }
}
};
@@ -674,4 +734,14 @@ public class ImsCallSessionImplBase implements AutoCloseable {
public void setServiceImpl(IImsCallSession serviceImpl) {
mServiceImpl = serviceImpl;
}
+
+ /**
+ * Set default Executor from MmTelFeature.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of ImsCallSession.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ mExecutor = executor;
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index d75da9035124..11fc328a42c7 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -33,12 +33,21 @@ import android.util.Log;
import com.android.ims.ImsConfig;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.util.RemoteCallbackListExt;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
/**
* Controls the modification of IMS specific configurations. For more information on the supported
@@ -81,21 +90,48 @@ public class ImsConfigImplBase {
WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
+ private final Object mLock = new Object();
+ private Executor mExecutor;
@VisibleForTesting
- public ImsConfigStub(ImsConfigImplBase imsConfigImplBase) {
+ public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Executor executor) {
+ mExecutor = executor;
mImsConfigImplBaseWeakReference =
new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
}
@Override
public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException {
- getImsConfigImpl().addImsConfigCallback(c);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().addImsConfigCallback(c);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "addImsConfigCallback");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception addImsConfigCallback");
+ throw exceptionRef.get();
+ }
}
@Override
public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException {
- getImsConfigImpl().removeImsConfigCallback(c);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().removeImsConfigCallback(c);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "removeImsConfigCallback");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception removeImsConfigCallback");
+ throw exceptionRef.get();
+ }
}
/**
@@ -108,16 +144,34 @@ public class ImsConfigImplBase {
* unavailable.
*/
@Override
- public synchronized int getConfigInt(int item) throws RemoteException {
- if (mProvisionedIntValue.containsKey(item)) {
- return mProvisionedIntValue.get(item);
- } else {
- int retVal = getImsConfigImpl().getConfigInt(item);
- if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
- updateCachedValue(item, retVal, false);
+ public int getConfigInt(int item) throws RemoteException {
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ int retVal = executeMethodAsyncForResult(()-> {
+ int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
+ synchronized (mLock) {
+ if (mProvisionedIntValue.containsKey(item)) {
+ return mProvisionedIntValue.get(item);
+ } else {
+ try {
+ returnVal = getImsConfigImpl().getConfigInt(item);
+ if (returnVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
+ mProvisionedIntValue.put(item, returnVal);
+ }
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return returnVal;
+ }
+ }
}
- return retVal;
+ return returnVal;
+ }, "getConfigInt");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
+ throw exceptionRef.get();
}
+
+ return retVal;
}
/**
@@ -129,16 +183,34 @@ public class ImsConfigImplBase {
* @return value in String format.
*/
@Override
- public synchronized String getConfigString(int item) throws RemoteException {
- if (mProvisionedStringValue.containsKey(item)) {
- return mProvisionedStringValue.get(item);
- } else {
- String retVal = getImsConfigImpl().getConfigString(item);
- if (retVal != null) {
- updateCachedValue(item, retVal, false);
+ public String getConfigString(int item) throws RemoteException {
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ String retVal = executeMethodAsyncForResult(()-> {
+ String returnVal = null;
+ synchronized (mLock) {
+ if (mProvisionedStringValue.containsKey(item)) {
+ returnVal = mProvisionedStringValue.get(item);
+ } else {
+ try {
+ returnVal = getImsConfigImpl().getConfigString(item);
+ if (returnVal != null) {
+ mProvisionedStringValue.put(item, returnVal);
+ }
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return returnVal;
+ }
+ }
}
- return retVal;
+ return returnVal;
+ }, "getConfigString");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
+ throw exceptionRef.get();
}
+
+ return retVal;
}
/**
@@ -153,14 +225,32 @@ public class ImsConfigImplBase {
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
*/
@Override
- public synchronized int setConfigInt(int item, int value) throws RemoteException {
- mProvisionedIntValue.remove(item);
- int retVal = getImsConfigImpl().setConfig(item, value);
- if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
- updateCachedValue(item, value, true);
- } else {
- Log.d(TAG, "Set provision value of " + item +
- " to " + value + " failed with error code " + retVal);
+ public int setConfigInt(int item, int value) throws RemoteException {
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ int retVal = executeMethodAsyncForResult(()-> {
+ int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
+ try {
+ synchronized (mLock) {
+ mProvisionedIntValue.remove(item);
+ returnVal = getImsConfigImpl().setConfig(item, value);
+ if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+ mProvisionedIntValue.put(item, value);
+ } else {
+ Log.d(TAG, "Set provision value of " + item
+ + " to " + value + " failed with error code " + returnVal);
+ }
+ }
+ notifyImsConfigChanged(item, value);
+ return returnVal;
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return returnVal;
+ }
+ }, "setConfigInt");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception setConfigInt");
+ throw exceptionRef.get();
}
return retVal;
@@ -178,12 +268,30 @@ public class ImsConfigImplBase {
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
*/
@Override
- public synchronized int setConfigString(int item, String value)
+ public int setConfigString(int item, String value)
throws RemoteException {
- mProvisionedStringValue.remove(item);
- int retVal = getImsConfigImpl().setConfig(item, value);
- if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
- updateCachedValue(item, value, true);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ int retVal = executeMethodAsyncForResult(()-> {
+ int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
+ try {
+ synchronized (mLock) {
+ mProvisionedStringValue.remove(item);
+ returnVal = getImsConfigImpl().setConfig(item, value);
+ if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+ mProvisionedStringValue.put(item, value);
+ }
+ }
+ notifyImsConfigChanged(item, value);
+ return returnVal;
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ return returnVal;
+ }
+ }, "setConfigString");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception setConfigInt");
+ throw exceptionRef.get();
}
return retVal;
@@ -191,7 +299,19 @@ public class ImsConfigImplBase {
@Override
public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
- getImsConfigImpl().updateImsCarrierConfigs(bundle);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().updateImsCarrierConfigs(bundle);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "updateImsCarrierConfigs");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception updateImsCarrierConfigs");
+ throw exceptionRef.get();
+ }
}
private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
@@ -206,13 +326,37 @@ public class ImsConfigImplBase {
@Override
public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed)
throws RemoteException {
- getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "notifyRcsAutoConfigurationReceived");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationReceived");
+ throw exceptionRef.get();
+ }
}
@Override
public void notifyRcsAutoConfigurationRemoved()
throws RemoteException {
- getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved();
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved();
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "notifyRcsAutoConfigurationRemoved");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationRemoved");
+ throw exceptionRef.get();
+ }
}
private void notifyImsConfigChanged(int item, int value) throws RemoteException {
@@ -223,50 +367,144 @@ public class ImsConfigImplBase {
getImsConfigImpl().notifyConfigChanged(item, value);
}
- protected synchronized void updateCachedValue(int item, int value, boolean notifyChange)
- throws RemoteException {
- mProvisionedIntValue.put(item, value);
- if (notifyChange) {
- notifyImsConfigChanged(item, value);
+ protected void updateCachedValue(int item, int value) {
+ synchronized (mLock) {
+ mProvisionedIntValue.put(item, value);
}
}
- protected synchronized void updateCachedValue(int item, String value,
- boolean notifyChange) throws RemoteException {
- mProvisionedStringValue.put(item, value);
- if (notifyChange) {
- notifyImsConfigChanged(item, value);
+ protected void updateCachedValue(int item, String value) {
+ synchronized (mLock) {
+ mProvisionedStringValue.put(item, value);
}
}
@Override
public void addRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
- getImsConfigImpl().addRcsConfigCallback(c);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().addRcsConfigCallback(c);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "addRcsConfigCallback");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception addRcsConfigCallback");
+ throw exceptionRef.get();
+ }
}
@Override
public void removeRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
- getImsConfigImpl().removeRcsConfigCallback(c);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().removeRcsConfigCallback(c);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "removeRcsConfigCallback");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception removeRcsConfigCallback");
+ throw exceptionRef.get();
+ }
}
@Override
public void triggerRcsReconfiguration() throws RemoteException {
- getImsConfigImpl().triggerAutoConfiguration();
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().triggerAutoConfiguration();
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "triggerRcsReconfiguration");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception triggerRcsReconfiguration");
+ throw exceptionRef.get();
+ }
}
@Override
public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException {
- getImsConfigImpl().setRcsClientConfiguration(rcc);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ getImsConfigImpl().setRcsClientConfiguration(rcc);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "setRcsClientConfiguration");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception setRcsClientConfiguration");
+ throw exceptionRef.get();
+ }
}
@Override
public void notifyIntImsConfigChanged(int item, int value) throws RemoteException {
- notifyImsConfigChanged(item, value);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ notifyImsConfigChanged(item, value);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "notifyIntImsConfigChanged");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception notifyIntImsConfigChanged");
+ throw exceptionRef.get();
+ }
}
@Override
public void notifyStringImsConfigChanged(int item, String value) throws RemoteException {
- notifyImsConfigChanged(item, value);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(()-> {
+ try {
+ notifyImsConfigChanged(item, value);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "notifyStringImsConfigChanged");
+
+ if (exceptionRef.get() != null) {
+ Log.d(TAG, "ImsConfigImplBase Exception notifyStringImsConfigChanged");
+ throw exceptionRef.get();
+ }
+ }
+
+ // 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 {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResult(Supplier<T> r,
+ String errorLogName) throws RemoteException {
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
}
}
@@ -303,15 +541,24 @@ public class ImsConfigImplBase {
ImsConfigStub mImsConfigStub;
/**
- * Used for compatibility between older versions of the ImsService.
+ * Create a ImsConfig using the Executor specified for methods being called by the
+ * framework.
+ * @param executor The executor for the framework to use when executing the methods overridden
+ * by the implementation of ImsConfig.
+ */
+ public ImsConfigImplBase(@NonNull Executor executor) {
+ mImsConfigStub = new ImsConfigStub(this, executor);
+ }
+
+ /**
* @hide
*/
- public ImsConfigImplBase(Context context) {
- mImsConfigStub = new ImsConfigStub(this);
+ public ImsConfigImplBase(@NonNull Context context) {
+ mImsConfigStub = new ImsConfigStub(this, null);
}
public ImsConfigImplBase() {
- mImsConfigStub = new ImsConfigStub(this);
+ mImsConfigStub = new ImsConfigStub(this, null);
}
/**
@@ -427,8 +674,10 @@ public class ImsConfigImplBase {
* @param value in Integer format.
*/
public final void notifyProvisionedValueChanged(int item, int value) {
+ mImsConfigStub.updateCachedValue(item, value);
+
try {
- mImsConfigStub.updateCachedValue(item, value, true);
+ mImsConfigStub.notifyImsConfigChanged(item, value);
} catch (RemoteException e) {
Log.w(TAG, "notifyProvisionedValueChanged(int): Framework connection is dead.");
}
@@ -443,8 +692,10 @@ public class ImsConfigImplBase {
* @param value in String format.
*/
public final void notifyProvisionedValueChanged(int item, String value) {
+ mImsConfigStub.updateCachedValue(item, value);
+
try {
- mImsConfigStub.updateCachedValue(item, value, true);
+ mImsConfigStub.notifyImsConfigChanged(item, value);
} catch (RemoteException e) {
Log.w(TAG, "notifyProvisionedValueChanged(string): Framework connection is dead.");
}
@@ -582,4 +833,16 @@ public class ImsConfigImplBase {
}
});
}
+
+ /**
+ * Set default Executor from ImsService.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of ImsConfig.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ if (mImsConfigStub.mExecutor == null) {
+ mImsConfigStub.mExecutor = executor;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 8ad40ed1032c..84b2253e1b27 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -16,14 +16,21 @@
package android.telephony.ims.stub;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.RemoteException;
import android.util.Log;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsEcbmListener;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.Executor;
+
/**
* Base implementation of ImsEcbm, which implements stub versions of the methods
@@ -40,10 +47,12 @@ public class ImsEcbmImplBase {
private final Object mLock = new Object();
private IImsEcbmListener mListener;
+ private Executor mExecutor = Runnable::run;
+
private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
@Override
public void setListener(IImsEcbmListener listener) {
- synchronized (mLock) {
+ executeMethodAsync(() -> {
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
Log.w(TAG, "setListener: discarding dead Binder");
mListener = null;
@@ -62,12 +71,25 @@ public class ImsEcbmImplBase {
+ "listener");
mListener = listener;
}
- }
+ }, "setListener");
}
@Override
public void exitEmergencyCallbackMode() {
- ImsEcbmImplBase.this.exitEmergencyCallbackMode();
+ executeMethodAsync(() -> ImsEcbmImplBase.this.exitEmergencyCallbackMode(),
+ "exitEmergencyCallbackMode");
+ }
+
+ // 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) {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(TAG, "ImsEcbmImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ }
}
};
@@ -123,4 +145,14 @@ public class ImsEcbmImplBase {
}
}
}
+
+ /**
+ * Set default Executor from MmTelFeature.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of ImsEcbm.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ mExecutor = executor;
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index ec1c7b3a92a8..a723cd8b118c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -16,6 +16,7 @@
package android.telephony.ims.stub;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.RemoteException;
import android.telephony.ims.ImsExternalCallState;
@@ -23,9 +24,14 @@ import android.util.Log;
import com.android.ims.internal.IImsExternalCallStateListener;
import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.Executor;
/**
* Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
@@ -43,11 +49,13 @@ public class ImsMultiEndpointImplBase {
private IImsExternalCallStateListener mListener;
private final Object mLock = new Object();
+ private Executor mExecutor = Runnable::run;
+
private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
@Override
public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
- synchronized (mLock) {
+ executeMethodAsync(() -> {
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
Log.w(TAG, "setListener: discarding dead Binder");
mListener = null;
@@ -67,12 +75,25 @@ public class ImsMultiEndpointImplBase {
+ "listener");
mListener = listener;
}
- }
+ }, "setListener");
}
@Override
public void requestImsExternalCallStateInfo() throws RemoteException {
- ImsMultiEndpointImplBase.this.requestImsExternalCallStateInfo();
+ executeMethodAsync(() -> ImsMultiEndpointImplBase.this
+ .requestImsExternalCallStateInfo(), "requestImsExternalCallStateInfo");
+ }
+
+ // 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) {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(TAG, "ImsMultiEndpointImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ }
}
};
@@ -108,4 +129,14 @@ public class ImsMultiEndpointImplBase {
public void requestImsExternalCallStateInfo() {
Log.d(TAG, "requestImsExternalCallStateInfo() not implemented");
}
+
+ /**
+ * Set default Executor from MmTelFeature.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of ImsMultiEndpoint.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ mExecutor = executor;
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 02bcdec621c1..3b151a422b57 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -31,10 +31,19 @@ import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.util.Log;
import com.android.internal.telephony.util.RemoteCallbackListExt;
+import com.android.internal.telephony.util.TelephonyUtils;
import com.android.internal.util.ArrayUtils;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
/**
* Controls IMS registration for this ImsService and notifies the framework when the IMS
@@ -92,39 +101,114 @@ public class ImsRegistrationImplBase {
// yet.
private static final int REGISTRATION_STATE_UNKNOWN = -1;
+ private Executor mExecutor;
+
+ /**
+ * Create a new ImsRegistration.
+ * <p>
+ * Method stubs called from the framework will be called asynchronously. To specify the
+ * {@link Executor} that the methods stubs will be called, use
+ * {@link ImsRegistrationImplBase#ImsRegistrationImplBase(Executor)} instead.
+ */
+ public ImsRegistrationImplBase() {
+ super();
+ }
+
+ /**
+ * Create a ImsRegistration using the Executor specified for methods being called by the
+ * framework.
+ * @param executor The executor for the framework to use when executing the methods overridden
+ * by the implementation of ImsRegistration.
+ */
+ public ImsRegistrationImplBase(@NonNull Executor executor) {
+ super();
+ mExecutor = executor;
+ }
+
private final IImsRegistration mBinder = new IImsRegistration.Stub() {
@Override
public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
- synchronized (mLock) {
- return (mRegistrationAttributes == null) ? REGISTRATION_TECH_NONE
- : mRegistrationAttributes.getRegistrationTechnology();
- }
+ return executeMethodAsyncForResult(() -> (mRegistrationAttributes == null)
+ ? REGISTRATION_TECH_NONE : mRegistrationAttributes.getRegistrationTechnology(),
+ "getRegistrationTechnology");
}
@Override
public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
- ImsRegistrationImplBase.this.addRegistrationCallback(c);
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(() -> {
+ try {
+ ImsRegistrationImplBase.this.addRegistrationCallback(c);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "addRegistrationCallback");
+
+ if (exceptionRef.get() != null) {
+ throw exceptionRef.get();
+ }
}
@Override
public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
- ImsRegistrationImplBase.this.removeRegistrationCallback(c);
+ executeMethodAsync(() -> ImsRegistrationImplBase.this.removeRegistrationCallback(c),
+ "removeRegistrationCallback");
}
@Override
public void triggerFullNetworkRegistration(int sipCode, String sipReason) {
- ImsRegistrationImplBase.this.triggerFullNetworkRegistration(sipCode, sipReason);
+ executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
+ .triggerFullNetworkRegistration(sipCode, sipReason),
+ "triggerFullNetworkRegistration");
}
@Override
public void triggerUpdateSipDelegateRegistration() {
- ImsRegistrationImplBase.this.updateSipDelegateRegistration();
+ executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
+ .updateSipDelegateRegistration(), "triggerUpdateSipDelegateRegistration");
}
@Override
public void triggerSipDelegateDeregistration() {
- ImsRegistrationImplBase.this.triggerSipDelegateDeregistration();
+ executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
+ .triggerSipDelegateDeregistration(), "triggerSipDelegateDeregistration");
+ }
+
+ // 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 {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
+ }
+
+ private void executeMethodAsyncNoException(Runnable r, String errorLogName) {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResult(Supplier<T> r,
+ String errorLogName) throws RemoteException {
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
}
};
@@ -394,4 +478,16 @@ public class ImsRegistrationImplBase {
onSubscriberAssociatedUriChanged(c, uris);
}
}
+
+ /**
+ * Set default Executor from ImsService.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of Registration.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ if (mExecutor == null) {
+ mExecutor = executor;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index eb3e8ed5a8e4..11cdeed10c5a 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -27,10 +27,17 @@ import android.util.Log;
import com.android.ims.internal.IImsUt;
import com.android.ims.internal.IImsUtListener;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* Base implementation of IMS UT interface, which implements stubs. Override these methods to
@@ -119,96 +126,108 @@ public class ImsUtImplBase {
*/
public static final int INVALID_RESULT = -1;
+ private Executor mExecutor = Runnable::run;
+
private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
private final Object mLock = new Object();
private ImsUtListener mUtListener;
@Override
public void close() throws RemoteException {
- ImsUtImplBase.this.close();
+ executeMethodAsync(() ->ImsUtImplBase.this.close(), "close");
}
@Override
public int queryCallBarring(int cbType) throws RemoteException {
- return ImsUtImplBase.this.queryCallBarring(cbType);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallBarring(cbType),
+ "queryCallBarring");
}
@Override
public int queryCallForward(int condition, String number) throws RemoteException {
- return ImsUtImplBase.this.queryCallForward(condition, number);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallForward(
+ condition, number), "queryCallForward");
}
@Override
public int queryCallWaiting() throws RemoteException {
- return ImsUtImplBase.this.queryCallWaiting();
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallWaiting(),
+ "queryCallWaiting");
}
@Override
public int queryCLIR() throws RemoteException {
- return ImsUtImplBase.this.queryCLIR();
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIR(), "queryCLIR");
}
@Override
public int queryCLIP() throws RemoteException {
- return ImsUtImplBase.this.queryCLIP();
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIP(), "queryCLIP");
}
@Override
public int queryCOLR() throws RemoteException {
- return ImsUtImplBase.this.queryCOLR();
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLR(), "queryCOLR");
}
@Override
public int queryCOLP() throws RemoteException {
- return ImsUtImplBase.this.queryCOLP();
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLP(), "queryCOLP");
}
@Override
public int transact(Bundle ssInfo) throws RemoteException {
- return ImsUtImplBase.this.transact(ssInfo);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.transact(ssInfo),
+ "transact");
}
@Override
public int updateCallBarring(int cbType, int action, String[] barrList) throws
RemoteException {
- return ImsUtImplBase.this.updateCallBarring(cbType, action, barrList);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallBarring(
+ cbType, action, barrList), "updateCallBarring");
}
@Override
public int updateCallForward(int action, int condition, String number, int serviceClass,
int timeSeconds) throws RemoteException {
- return ImsUtImplBase.this.updateCallForward(action, condition, number, serviceClass,
- timeSeconds);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallForward(
+ action, condition, number, serviceClass, timeSeconds), "updateCallForward");
}
@Override
public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
- return ImsUtImplBase.this.updateCallWaiting(enable, serviceClass);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallWaiting(
+ enable, serviceClass), "updateCallWaiting");
}
@Override
public int updateCLIR(int clirMode) throws RemoteException {
- return ImsUtImplBase.this.updateCLIR(clirMode);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIR(clirMode),
+ "updateCLIR");
}
@Override
public int updateCLIP(boolean enable) throws RemoteException {
- return ImsUtImplBase.this.updateCLIP(enable);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIP(enable),
+ "updateCLIP");
}
@Override
public int updateCOLR(int presentation) throws RemoteException {
- return ImsUtImplBase.this.updateCOLR(presentation);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLR(presentation),
+ "updateCOLR");
}
@Override
public int updateCOLP(boolean enable) throws RemoteException {
- return ImsUtImplBase.this.updateCOLP(enable);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLP(enable),
+ "updateCOLP");
}
@Override
public void setListener(IImsUtListener listener) throws RemoteException {
- synchronized (mLock) {
+ executeMethodAsync(() -> {
if (mUtListener != null
&& !mUtListener.getListenerInterface().asBinder().isBinderAlive()) {
Log.w(TAG, "setListener: discarding dead Binder");
@@ -229,29 +248,59 @@ public class ImsUtImplBase {
+ "listener");
mUtListener = new ImsUtListener(listener);
}
- }
- ImsUtImplBase.this.setListener(mUtListener);
+ ImsUtImplBase.this.setListener(mUtListener);
+ }, "setListener");
}
@Override
public int queryCallBarringForServiceClass(int cbType, int serviceClass)
throws RemoteException {
- return ImsUtImplBase.this.queryCallBarringForServiceClass(cbType, serviceClass);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this
+ .queryCallBarringForServiceClass(cbType, serviceClass),
+ "queryCallBarringForServiceClass");
}
@Override
public int updateCallBarringForServiceClass(int cbType, int action,
String[] barrList, int serviceClass) throws RemoteException {
- return ImsUtImplBase.this.updateCallBarringForServiceClass(
- cbType, action, barrList, serviceClass);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this
+ .updateCallBarringForServiceClass(cbType, action, barrList, serviceClass),
+ "updateCallBarringForServiceClass");
}
@Override
public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
int serviceClass, String password) throws RemoteException {
- return ImsUtImplBase.this.updateCallBarringWithPassword(
- cbType, action, barrList, serviceClass, password);
+ return executeMethodAsyncForResult(() -> ImsUtImplBase.this
+ .updateCallBarringWithPassword(cbType, action, barrList, serviceClass,
+ password), "updateCallBarringWithPassword");
+ }
+
+ // 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 {
+ try {
+ CompletableFuture.runAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+ } catch (CancellationException | CompletionException e) {
+ Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
+ }
+
+ private <T> T executeMethodAsyncForResult(Supplier<T> r,
+ String errorLogName) throws RemoteException {
+ CompletableFuture<T> future = CompletableFuture.supplyAsync(
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+ try {
+ return future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: "
+ + e.getMessage());
+ throw new RemoteException(e.getMessage());
+ }
}
};
@@ -470,4 +519,14 @@ public class ImsUtImplBase {
public IImsUt getInterface() {
return mServiceImpl;
}
+
+ /**
+ * Set default Executor from MmTelFeature.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of ImsUT.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ mExecutor = executor;
+ }
}
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index 13ea99735ab4..52538cb4e2df 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -86,10 +86,21 @@ public class SipTransportImplBase {
}
};
- private final Executor mBinderExecutor;
+ private Executor mBinderExecutor;
private final ArrayList<SipDelegateAidlWrapper> mDelegates = new ArrayList<>();
/**
+ * Create a new SipTransport.
+ * <p>
+ * Method stubs called from the framework will be called asynchronously. To specify the
+ * {@link Executor} that the methods stubs will be called, use
+ * {@link SipTransportImplBase#SipTransportImplBase(Executor)} instead.
+ */
+ public SipTransportImplBase() {
+ super();
+ }
+
+ /**
* Create an implementation of SipTransportImplBase.
*
* @param executor The executor that remote calls from the framework will be called on. This
@@ -212,4 +223,16 @@ public class SipTransportImplBase {
public ISipTransport getBinder() {
return mSipTransportImpl;
}
+
+ /**
+ * Set default Executor from ImsService.
+ * @param executor The default executor for the framework to use when executing the methods
+ * overridden by the implementation of SipTransport.
+ * @hide
+ */
+ public final void setDefaultExecutor(@NonNull Executor executor) {
+ if (mBinderExecutor == null) {
+ mBinderExecutor = executor;
+ }
+ }
}