Merge "Allow com.android.* classes in system_service stubs"
diff --git a/Android.bp b/Android.bp
index 888c576..ff3ad31 100644
--- a/Android.bp
+++ b/Android.bp
@@ -911,22 +911,6 @@
output_extension: "proto.h",
}
-
-subdirs = [
- "cmds/*",
- "core/*",
- "libs/*",
- "media/*",
- "proto",
- "tools/*",
- "native/android",
- "native/graphics/jni",
-]
-
-optional_subdirs = [
- "core/tests/utiltests/jni",
-]
-
// TODO(b/77285514): remove this once the last few hidl interfaces have been
// updated to use hwbinder.stubs.
java_library {
@@ -986,13 +970,6 @@
}
filegroup {
- name: "framework-annotation-nonnull-srcs",
- srcs: [
- "core/java/android/annotation/NonNull.java",
- ],
-}
-
-filegroup {
name: "framework-media-annotation-srcs",
srcs: [
"core/java/android/annotation/CallbackExecutor.java",
diff --git a/api/current.txt b/api/current.txt
index 37b7ebc..20c2ca2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -43835,7 +43835,7 @@
method public final android.telecom.CallAudioState getCallAudioState();
method public final String getCallerDisplayName();
method public final int getCallerDisplayNamePresentation();
- method public int getCallerNumberVerificationStatus();
+ method public final int getCallerNumberVerificationStatus();
method public final android.telecom.Conference getConference();
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
@@ -43888,7 +43888,7 @@
method public final void setAudioModeIsVoip(boolean);
method public final void setAudioRoute(int);
method public final void setCallerDisplayName(String, int);
- method public void setCallerNumberVerificationStatus(int);
+ method public final void setCallerNumberVerificationStatus(int);
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
method public final void setConnectionCapabilities(int);
@@ -44703,8 +44703,8 @@
field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
- field public static final String KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL = "allow_holding_video_call";
field public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL = "allow_hold_call_during_emergency_bool";
+ field public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL = "allow_hold_video_call_bool";
field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index 265674a..c6f42f7 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
index 229bee5..5bc9992 100644
--- a/core/java/android/app/DexLoadReporter.java
+++ b/core/java/android/app/DexLoadReporter.java
@@ -28,9 +28,8 @@
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.HashSet;
-import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -87,50 +86,32 @@
}
@Override
- public void report(List<ClassLoader> classLoadersChain, List<String> classPaths) {
- if (classLoadersChain.size() != classPaths.size()) {
- Slog.wtf(TAG, "Bad call to DexLoadReporter: argument size mismatch");
- return;
- }
- if (classPaths.isEmpty()) {
- Slog.wtf(TAG, "Bad call to DexLoadReporter: empty dex paths");
- return;
- }
-
- // The first element of classPaths is the list of dex files that should be registered.
- // The classpath is represented as a list of dex files separated by File.pathSeparator.
- String[] dexPathsForRegistration = classPaths.get(0).split(File.pathSeparator);
- if (dexPathsForRegistration.length == 0) {
- // No dex files to register.
+ public void report(Map<String, String> classLoaderContextMap) {
+ if (classLoaderContextMap.isEmpty()) {
+ Slog.wtf(TAG, "Bad call to DexLoadReporter: empty classLoaderContextMap");
return;
}
// Notify the package manager about the dex loads unconditionally.
// The load might be for either a primary or secondary dex file.
- notifyPackageManager(classLoadersChain, classPaths);
+ notifyPackageManager(classLoaderContextMap);
// Check for secondary dex files and register them for profiling if possible.
// Note that we only register the dex paths belonging to the first class loader.
- registerSecondaryDexForProfiling(dexPathsForRegistration);
+ registerSecondaryDexForProfiling(classLoaderContextMap.keySet());
}
- private void notifyPackageManager(List<ClassLoader> classLoadersChain,
- List<String> classPaths) {
+ private void notifyPackageManager(Map<String, String> classLoaderContextMap) {
// Get the class loader names for the binder call.
- List<String> classLoadersNames = new ArrayList<>(classPaths.size());
- for (ClassLoader classLoader : classLoadersChain) {
- classLoadersNames.add(classLoader.getClass().getName());
- }
String packageName = ActivityThread.currentPackageName();
try {
- ActivityThread.getPackageManager().notifyDexLoad(
- packageName, classLoadersNames, classPaths,
- VMRuntime.getRuntime().vmInstructionSet());
+ ActivityThread.getPackageManager().notifyDexLoad(packageName,
+ classLoaderContextMap, VMRuntime.getRuntime().vmInstructionSet());
} catch (RemoteException re) {
Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
}
}
- private void registerSecondaryDexForProfiling(String[] dexPaths) {
+ private void registerSecondaryDexForProfiling(Set<String> dexPaths) {
if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
return;
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 429a6e5..6d051e4 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -529,19 +529,12 @@
* Notify the package manager that a list of dex files have been loaded.
*
* @param loadingPackageName the name of the package who performs the load
- * @param classLoadersNames the names of the class loaders present in the loading chain. The
- * list encodes the class loader chain in the natural order. The first class loader has
- * the second one as its parent and so on. The dex files present in the class path of the
- * first class loader will be recorded in the usage file.
- * @param classPaths the class paths corresponding to the class loaders names from
- * {@param classLoadersNames}. The the first element corresponds to the first class loader
- * and so on. A classpath is represented as a list of dex files separated by
- * {@code File.pathSeparator}, or null if the class loader's classpath is not known.
- * The dex files found in the first class path will be recorded in the usage file.
+ * @param classLoaderContextMap a map from file paths to dex files that have been loaded to
+ * the class loader context that was used to load them.
* @param loaderIsa the ISA of the loader process
*/
- oneway void notifyDexLoad(String loadingPackageName, in List<String> classLoadersNames,
- in List<String> classPaths, String loaderIsa);
+ oneway void notifyDexLoad(String loadingPackageName,
+ in Map<String, String> classLoaderContextMap, String loaderIsa);
/**
* Register an application dex module with the package manager.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9cf751d..589b1aa 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1279,7 +1279,8 @@
@UnsupportedAppUsage
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
try {
- return mService.getDefaultNetworkCapabilitiesForUser(userId);
+ return mService.getDefaultNetworkCapabilitiesForUser(
+ userId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1361,7 +1362,7 @@
@Nullable
public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
try {
- return mService.getNetworkCapabilities(network);
+ return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4035,10 +4036,9 @@
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
- final String callingPackageName = mContext.getOpPackageName();
try {
mService.pendingRequestForNetwork(
- request.networkCapabilities, operation, callingPackageName);
+ request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
@@ -4150,10 +4150,9 @@
@NonNull PendingIntent operation) {
printStackTrace();
checkPendingIntentNotNull(operation);
- final String callingPackageName = mContext.getOpPackageName();
try {
mService.pendingListenForNetwork(
- request.networkCapabilities, operation, callingPackageName);
+ request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 3a55461..1434560 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -59,7 +59,8 @@
NetworkInfo[] getAllNetworkInfo();
Network getNetworkForType(int networkType);
Network[] getAllNetworks();
- NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId);
+ NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+ int userId, String callingPackageName);
boolean isNetworkSupported(int networkType);
@@ -68,7 +69,7 @@
LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network);
- NetworkCapabilities getNetworkCapabilities(in Network network);
+ NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
@UnsupportedAppUsage
NetworkState[] getAllNetworkState();
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ef4a9e5..873d6e914 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -830,6 +830,23 @@
* <p>This field keeps track of the UID of the app that created this network and is in charge of
* its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
* VPN, or Carrier Service app managing a cellular data connection.
+ *
+ * <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
+ * reset to Process.INVALID_UID unless all the following conditions are met:
+ *
+ * <ol>
+ * <li>The destination app is the network owner
+ * <li>The destination app has the ACCESS_FINE_LOCATION permission granted
+ * <li>The user's location toggle is on
+ * </ol>
+ *
+ * This is because the owner UID is location-sensitive. The apps that request a network could
+ * know where the device is if they can tell for sure the system has connected to the network
+ * they requested.
+ *
+ * <p>This is populated by the network agents and for the NetworkCapabilities instance sent by
+ * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system
+ * server.
*/
private int mOwnerUid = Process.INVALID_UID;
@@ -842,7 +859,16 @@
}
/**
- * Retrieves the UID of the owner app.
+ * Retrieves the UID of the app that owns this network.
+ *
+ * <p>For user privacy reasons, this field will only be populated if:
+ *
+ * <ol>
+ * <li>The calling app is the network owner
+ * <li>The calling app has the ACCESS_FINE_LOCATION permission granted
+ * <li>The user's location toggle is on
+ * </ol>
+ *
*/
public int getOwnerUid() {
return mOwnerUid;
@@ -880,8 +906,9 @@
* @param administratorUids the UIDs to be set as administrators of this Network.
* @hide
*/
+ @NonNull
@SystemApi
- public @NonNull NetworkCapabilities setAdministratorUids(
+ public NetworkCapabilities setAdministratorUids(
@NonNull final List<Integer> administratorUids) {
mAdministratorUids.clear();
mAdministratorUids.addAll(administratorUids);
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 265674a..c6f42f7 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index d3fe582..9d0cb01 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -393,6 +393,9 @@
}
public int getNumCoresInCpuCluster(int cluster) {
+ if (cluster < 0 || cluster >= mCpuClusters.length) {
+ return 0; // index out of bound
+ }
return mCpuClusters[cluster].numCpus;
}
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 899d630..d8ec72f 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -51,6 +51,12 @@
<value>0.1</value> <!-- ~1mA -->
</array>
+ <!-- Additional power consumption by CPU excluding cluster and core when
+ running -->
+ <array name="cpu.active">
+ <value>0.1</value>
+ </array>
+
<!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
number of CPU cores for that cluster.
diff --git a/libs/usb/Android.bp b/libs/usb/Android.bp
index 027a748..e752b55 100644
--- a/libs/usb/Android.bp
+++ b/libs/usb/Android.bp
@@ -19,5 +19,3 @@
srcs: ["src/**/*.java"],
api_packages: ["com.android.future.usb"],
}
-
-subdirs = ["tests/*"]
diff --git a/libs/usb/tests/AccessoryChat/Android.bp b/libs/usb/tests/AccessoryChat/Android.bp
index 63a670c..19ed3d3 100644
--- a/libs/usb/tests/AccessoryChat/Android.bp
+++ b/libs/usb/tests/AccessoryChat/Android.bp
@@ -1,4 +1,3 @@
-subdirs = ["accessorychat"]
//
// Copyright (C) 2011 The Android Open Source Project
//
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index f873eeb..27660db 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -124,8 +124,3 @@
"-Wunreachable-code",
],
}
-
-subdirs = [
- "audioeffect",
- "soundpool",
-]
diff --git a/media/native/Android.bp b/media/native/Android.bp
deleted file mode 100644
index b44c296..0000000
--- a/media/native/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = ["*"]
diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml
index 25b7fc1..e124be6 100644
--- a/packages/DynamicSystemInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -27,10 +27,11 @@
<string name="notification_action_cancel">Cancel</string>
<!-- Action on notification: Discard installation [CHAR LIMIT=16] -->
<string name="notification_action_discard">Discard</string>
- <!-- Action on notification: Uninstall Dynamic System [CHAR LIMIT=16] -->
- <string name="notification_action_uninstall">Uninstall</string>
<!-- Action on notification: Restart to Dynamic System [CHAR LIMIT=16] -->
<string name="notification_action_reboot_to_dynsystem">Restart</string>
+ <!-- Action on notification: Restart to original Android version [CHAR LIMIT=16] -->
+ <string name="notification_action_reboot_to_origin">Restart</string>
+
<!-- Toast when installed Dynamic System is discarded [CHAR LIMIT=64] -->
<string name="toast_dynsystem_discarded">Discarded dynamic system</string>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 7affe88..37a77be 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -462,7 +462,7 @@
.setStyle(new Notification.BigTextStyle().bigText(msgInUse));
builder.addAction(new Notification.Action.Builder(
- null, getString(R.string.notification_action_uninstall),
+ null, getString(R.string.notification_action_reboot_to_origin),
createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build());
break;
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index cb0de7a..1a3d5b65 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -83,7 +83,6 @@
name: "framework-tethering-stubs",
srcs: [":framework-tethering-stubs-sources"],
libs: ["framework-all"],
- static_libs: ["tethering-aidl-interfaces-java"],
sdk_version: "core_platform",
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index e462d36..33335633 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -314,9 +314,13 @@
startStateMachineUpdaters(mHandler);
startTrackDefaultNetwork();
- getWifiManager().registerSoftApCallback(
- mHandler::post /* executor */,
- new TetheringSoftApCallback());
+
+ final WifiManager wifiManager = getWifiManager();
+ if (wifiManager != null) {
+ wifiManager.registerSoftApCallback(
+ mHandler::post /* executor */,
+ new TetheringSoftApCallback());
+ }
}
private void startStateMachineUpdaters(Handler handler) {
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index 265674a..c6f42f7 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,3 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
+qasid@google.com
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 52a2ca97..1eb77a4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1536,7 +1536,8 @@
}
@Override
- public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
+ public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
+ int userId, String callingPackageName) {
// The basic principle is: if an app's traffic could possibly go over a
// network, without the app doing anything multinetwork-specific,
// (hence, by "default"), then include that network's capabilities in
@@ -1558,7 +1559,10 @@
NetworkAgentInfo nai = getDefaultNetwork();
NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) {
- result.put(nai.network, nc);
+ result.put(
+ nai.network,
+ maybeSanitizeLocationInfoForCaller(
+ nc, Binder.getCallingUid(), callingPackageName));
}
synchronized (mVpns) {
@@ -1568,10 +1572,12 @@
Network[] networks = vpn.getUnderlyingNetworks();
if (networks != null) {
for (Network network : networks) {
- nai = getNetworkAgentInfoForNetwork(network);
- nc = getNetworkCapabilitiesInternal(nai);
+ nc = getNetworkCapabilitiesInternal(network);
if (nc != null) {
- result.put(network, nc);
+ result.put(
+ network,
+ maybeSanitizeLocationInfoForCaller(
+ nc, Binder.getCallingUid(), callingPackageName));
}
}
}
@@ -1638,20 +1644,26 @@
}
}
+ private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) {
+ return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+ }
+
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
if (nai == null) return null;
synchronized (nai) {
if (nai.networkCapabilities == null) return null;
return networkCapabilitiesRestrictedForCallerPermissions(
- nai.networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
+ nai.networkCapabilities, Binder.getCallingPid(), Binder.getCallingUid());
}
}
@Override
- public NetworkCapabilities getNetworkCapabilities(Network network) {
+ public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
enforceAccessPermission();
- return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+ return maybeSanitizeLocationInfoForCaller(
+ getNetworkCapabilitiesInternal(network),
+ Binder.getCallingUid(), callingPackageName);
}
@VisibleForTesting
@@ -1667,20 +1679,34 @@
}
newNc.setAdministratorUids(Collections.EMPTY_LIST);
- maybeSanitizeLocationInfoForCaller(newNc, callerUid);
-
return newNc;
}
- private void maybeSanitizeLocationInfoForCaller(
- NetworkCapabilities nc, int callerUid) {
- // TODO(b/142072839): Conditionally reset the owner UID if the following
- // conditions are not met:
- // 1. The destination app is the network owner
- // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted
- // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted
- // 3. The user's location toggle is on
- nc.setOwnerUid(INVALID_UID);
+ @VisibleForTesting
+ @Nullable
+ NetworkCapabilities maybeSanitizeLocationInfoForCaller(
+ @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
+ if (nc == null) {
+ return null;
+ }
+ final NetworkCapabilities newNc = new NetworkCapabilities(nc);
+ if (callerUid != newNc.getOwnerUid()) {
+ newNc.setOwnerUid(INVALID_UID);
+ return newNc;
+ }
+
+ Binder.withCleanCallingIdentity(
+ () -> {
+ if (!mLocationPermissionChecker.checkLocationPermission(
+ callerPkgName, null /* featureId */, callerUid, null /* message */)) {
+ // Caller does not have the requisite location permissions. Reset the
+ // owner's UID in the NetworkCapabilities.
+ newNc.setOwnerUid(INVALID_UID);
+ }
+ }
+ );
+
+ return newNc;
}
private LinkProperties linkPropertiesRestrictedForCallerPermissions(
@@ -1755,7 +1781,7 @@
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
- final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+ final NetworkCapabilities caps = getNetworkCapabilitiesInternal(getActiveNetwork());
if (caps != null) {
return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
} else {
@@ -5322,8 +5348,8 @@
}
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " " + request +
- (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+ return "uid/pid:" + mUid + "/" + mPid + " " + request
+ + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
}
}
@@ -6416,8 +6442,13 @@
}
switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: {
- putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid));
+ final NetworkCapabilities nc =
+ networkCapabilitiesRestrictedForCallerPermissions(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+ putParcelable(
+ bundle,
+ maybeSanitizeLocationInfoForCaller(
+ nc, nri.mUid, nri.request.getRequestorPackageName()));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
@@ -6430,9 +6461,13 @@
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
// networkAgent can't be null as it has been accessed a few lines above.
- final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid);
- putParcelable(bundle, nc);
+ final NetworkCapabilities netCap =
+ networkCapabilitiesRestrictedForCallerPermissions(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid);
+ putParcelable(
+ bundle,
+ maybeSanitizeLocationInfoForCaller(
+ netCap, nri.mUid, nri.request.getRequestorPackageName()));
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d8f5dfb..709811e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9764,8 +9764,8 @@
}
@Override
- public void notifyDexLoad(String loadingPackageName, List<String> classLoaderNames,
- List<String> classPaths, String loaderIsa) {
+ public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
+ String loaderIsa) {
int userId = UserHandle.getCallingUserId();
ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
if (ai == null) {
@@ -9773,7 +9773,7 @@
+ loadingPackageName + ", user=" + userId);
return;
}
- mDexManager.notifyDexLoad(ai, classLoaderNames, classPaths, loaderIsa, userId);
+ mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 9e86a4b..441fa75 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -44,6 +44,8 @@
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageManagerServiceUtils;
+import dalvik.system.VMRuntime;
+
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
@@ -143,22 +145,15 @@
* return as fast as possible.
*
* @param loadingAppInfo the package performing the load
- * @param classLoadersNames the names of the class loaders present in the loading chain. The
- * list encodes the class loader chain in the natural order. The first class loader has
- * the second one as its parent and so on. The dex files present in the class path of the
- * first class loader will be recorded in the usage file.
- * @param classPaths the class paths corresponding to the class loaders names from
- * {@param classLoadersNames}. The the first element corresponds to the first class loader
- * and so on. A classpath is represented as a list of dex files separated by
- * {@code File.pathSeparator}, or null if the class loader's classpath is not known.
- * The dex files found in the first class path will be recorded in the usage file.
+ * @param classLoaderContextMap a map from file paths to dex files that have been loaded to
+ * the class loader context that was used to load them.
* @param loaderIsa the ISA of the app loading the dex files
* @param loaderUserId the user id which runs the code loading the dex files
*/
- public void notifyDexLoad(ApplicationInfo loadingAppInfo, List<String> classLoadersNames,
- List<String> classPaths, String loaderIsa, int loaderUserId) {
+ public void notifyDexLoad(ApplicationInfo loadingAppInfo,
+ Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId) {
try {
- notifyDexLoadInternal(loadingAppInfo, classLoadersNames, classPaths, loaderIsa,
+ notifyDexLoadInternal(loadingAppInfo, classLoaderContextMap, loaderIsa,
loaderUserId);
} catch (Exception e) {
Slog.w(TAG, "Exception while notifying dex load for package " +
@@ -168,46 +163,23 @@
@VisibleForTesting
/*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
- List<String> classLoaderNames, List<String> classPaths, String loaderIsa,
+ Map<String, String> classLoaderContextMap, String loaderIsa,
int loaderUserId) {
- if (classLoaderNames.size() != classPaths.size()) {
- Slog.wtf(TAG, "Bad call to noitfyDexLoad: args have different size");
+ if (classLoaderContextMap == null) {
return;
}
- if (classLoaderNames.isEmpty()) {
+ if (classLoaderContextMap.isEmpty()) {
Slog.wtf(TAG, "Bad call to notifyDexLoad: class loaders list is empty");
return;
}
if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
- Slog.w(TAG, "Loading dex files " + classPaths + " in unsupported ISA: " +
- loaderIsa + "?");
+ Slog.w(TAG, "Loading dex files " + classLoaderContextMap.keySet()
+ + " in unsupported ISA: " + loaderIsa + "?");
return;
}
- // The first classpath should never be null because the first classloader
- // should always be an instance of BaseDexClassLoader.
- String firstClassPath = classPaths.get(0);
- if (firstClassPath == null) {
- return;
- }
- // The classpath is represented as a list of dex files separated by File.pathSeparator.
- String[] dexPathsToRegister = firstClassPath.split(File.pathSeparator);
-
- // Encode the class loader contexts for the dexPathsToRegister.
- String[] classLoaderContexts = DexoptUtils.processContextForDexLoad(
- classLoaderNames, classPaths);
-
- // A null classLoaderContexts means that there are unsupported class loaders in the
- // chain.
- if (classLoaderContexts == null) {
- if (DEBUG) {
- Slog.i(TAG, loadingAppInfo.packageName +
- " uses unsupported class loader in " + classLoaderNames);
- }
- }
-
- int dexPathIndex = 0;
- for (String dexPath : dexPathsToRegister) {
+ for (Map.Entry<String, String> mapping : classLoaderContextMap.entrySet()) {
+ String dexPath = mapping.getKey();
// Find the owning package name.
DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId);
@@ -229,7 +201,6 @@
// If the dex file is the primary apk (or a split) and not isUsedByOtherApps
// do not record it. This case does not bring any new usable information
// and can be safely skipped.
- dexPathIndex++;
continue;
}
@@ -239,13 +210,13 @@
searchResult.mOwningPackageName, loadingAppInfo.packageName);
}
- if (classLoaderContexts != null) {
-
+ String classLoaderContext = mapping.getValue();
+ if (classLoaderContext != null
+ && VMRuntime.isValidClassLoaderContext(classLoaderContext)) {
// Record dex file usage. If the current usage is a new pattern (e.g. new
// secondary, or UsedByOtherApps), record will return true and we trigger an
// async write to disk to make sure we don't loose the data in case of a reboot.
- String classLoaderContext = classLoaderContexts[dexPathIndex];
if (mPackageDexUsage.record(searchResult.mOwningPackageName,
dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit,
loadingAppInfo.packageName, classLoaderContext)) {
@@ -259,7 +230,6 @@
Slog.i(TAG, "Could not find owning package for dex file: " + dexPath);
}
}
- dexPathIndex++;
}
}
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index e68c238..08763e7 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -83,8 +83,9 @@
"=UnknownClassLoaderContext=";
// The marker used for unsupported class loader contexts (no longer written, may occur in old
- // files so discarded on read).
- private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
+ // files so discarded on read). Note: this matches
+ // ClassLoaderContext::kUnsupportedClassLoaderContextEncoding in the runtime.
+ /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
"=UnsupportedClassLoaderContext=";
/**
@@ -133,6 +134,9 @@
if (classLoaderContext == null) {
throw new IllegalArgumentException("Null classLoaderContext");
}
+ if (classLoaderContext.equals(UNSUPPORTED_CLASS_LOADER_CONTEXT)) {
+ return false;
+ }
synchronized (mPackageUseInfoMap) {
PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName);
@@ -843,10 +847,11 @@
boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages);
String oldClassLoaderContext = mClassLoaderContext;
- if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) {
+ if (isUnknownOrUnsupportedContext(mClassLoaderContext)) {
// Can happen if we read a previous version.
mClassLoaderContext = dexUseInfo.mClassLoaderContext;
- } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
+ } else if (!isUnknownOrUnsupportedContext(dexUseInfo.mClassLoaderContext)
+ && !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
// We detected a context change.
mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
}
@@ -857,6 +862,13 @@
|| !Objects.equals(oldClassLoaderContext, mClassLoaderContext);
}
+ private static boolean isUnknownOrUnsupportedContext(String context) {
+ // TODO: Merge UNKNOWN_CLASS_LOADER_CONTEXT & UNSUPPORTED_CLASS_LOADER_CONTEXT cases
+ // into UNSUPPORTED_CLASS_LOADER_CONTEXT.
+ return UNKNOWN_CLASS_LOADER_CONTEXT.equals(context)
+ || UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context);
+ }
+
public boolean isUsedByOtherApps() {
return mIsUsedByOtherApps;
}
@@ -878,7 +890,7 @@
public boolean isUnknownClassLoaderContext() {
// The class loader context may be unknown if we loaded the data from a previous version
// which didn't save the context.
- return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
+ return isUnknownOrUnsupportedContext(mClassLoaderContext);
}
public boolean isVariableClassLoaderContext() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b93365a..de7ae55 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -41,7 +41,6 @@
import android.database.sqlite.SQLiteGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityModuleConnector;
-import android.net.ITetheringConnector;
import android.net.NetworkStackClient;
import android.os.BaseBundle;
import android.os.Binder;
@@ -286,6 +285,8 @@
private static final String CONTENT_SUGGESTIONS_SERVICE_CLASS =
"com.android.server.contentsuggestions.ContentSuggestionsManagerService";
+ private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
+
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
@@ -2226,7 +2227,7 @@
try {
// TODO: hide implementation details, b/146312721.
ConnectivityModuleConnector.getInstance().startModuleService(
- ITetheringConnector.class.getName(),
+ TETHERING_CONNECTOR_CLASS,
PERMISSION_MAINLINE_NETWORK_STACK, service -> {
ServiceManager.addService(Context.TETHERING_SERVICE, service,
false /* allowIsolated */,
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index a4ba056..cb20b65 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -532,6 +532,61 @@
assertHasDclInfo(mBarUser0, mBarUser0, secondaries);
}
+ @Test
+ public void testPrimaryAndSecondaryDexLoad() {
+ // Foo loads both primary and secondary dexes
+ List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+ List<String> fooDexes = new ArrayList<>(mFooUser0.getBaseAndSplitDexPaths());
+ int primaryCount = fooDexes.size();
+ fooDexes.addAll(fooSecondaries);
+
+ notifyDexLoad(mFooUser0, fooDexes, mUser0);
+
+ PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+ assertIsUsedByOtherApps(mFooUser0, pui, false);
+ assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
+
+ // Below we want to verify that the secondary dex files within fooDexes have been correctly
+ // reported and their class loader contexts were correctly recorded.
+ //
+ // In order to achieve this we first use DexoptUtils.processContextForDexLoad to compute the
+ // class loader contexts for all the dex files.
+ String[] allClassLoaderContexts = DexoptUtils.processContextForDexLoad(
+ Arrays.asList(mFooUser0.mClassLoader),
+ Arrays.asList(String.join(File.pathSeparator, fooDexes)));
+ // Next we filter out the class loader contexts corresponding to non-secondary dex files.
+ String[] secondaryClassLoaderContexts = Arrays.copyOfRange(allClassLoaderContexts,
+ primaryCount, allClassLoaderContexts.length);
+ assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0,
+ secondaryClassLoaderContexts);
+
+ assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
+ }
+
+ @Test
+ public void testNotifySecondary_withSharedLibrary() {
+ // Foo loads its own secondary files.
+ List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+
+ String contextSuffix = "{PCL[/system/framework/org.apache.http.legacy.jar]}";
+ String[] expectedContexts = DexoptUtils.processContextForDexLoad(
+ Arrays.asList(mFooUser0.mClassLoader),
+ Arrays.asList(String.join(File.pathSeparator, fooSecondaries)));
+ for (int i = 0; i < expectedContexts.length; i++) {
+ expectedContexts[i] += contextSuffix;
+ }
+
+ notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0);
+
+ PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+ assertIsUsedByOtherApps(mFooUser0, pui, false);
+ assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
+ assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0,
+ expectedContexts);
+
+ assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
+ }
+
private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId,
String[] expectedContexts) {
@@ -572,17 +627,43 @@
// By default, assume a single class loader in the chain.
// This makes writing tests much easier.
List<String> classLoaders = Arrays.asList(testData.mClassLoader);
- List<String> classPaths = (dexPaths == null)
- ? Arrays.asList((String) null)
- : Arrays.asList(String.join(File.pathSeparator, dexPaths));
+ List<String> classPaths = dexPaths != null
+ ? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null;
notifyDexLoad(testData, classLoaders, classPaths, loaderUserId);
}
private void notifyDexLoad(TestData testData, List<String> classLoaders,
List<String> classPaths, int loaderUserId) {
+ String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths);
// We call the internal function so any exceptions thrown cause test failures.
- mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, classLoaders,
- classPaths, testData.mLoaderIsa, loaderUserId);
+ List<String> dexPaths = classPaths != null
+ ? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList();
+ notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId);
+ }
+
+ private void notifyDexLoad(TestData testData, List<String> dexPaths,
+ String[] classLoaderContexts, int loaderUserId) {
+ assertTrue(dexPaths.size() == classLoaderContexts.length);
+ HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size());
+ for (int i = 0; i < dexPaths.size(); i++) {
+ dexPathMapping.put(dexPaths.get(i), classLoaderContexts != null
+ ? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
+ }
+ mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping,
+ testData.mLoaderIsa, loaderUserId);
+ }
+
+ private String[] computeClassLoaderContexts(List<String> classLoaders,
+ List<String> classPaths) {
+ if (classPaths == null) {
+ return new String[0];
+ }
+ String[] results = DexoptUtils.processContextForDexLoad(classLoaders, classPaths);
+ if (results == null) {
+ results = new String[classPaths.get(0).split(File.pathSeparator).length];
+ Arrays.fill(results, PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
+ }
+ return results;
}
private PackageUseInfo getPackageUseInfo(TestData testData) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
old mode 100644
new mode 100755
index 52213d8..c5fcf67
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -465,8 +465,27 @@
* @hide
*/
public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
+
+ /**
+ * When set for a call, indicates that this {@code Call} can be transferred to another
+ * number.
+ * Call supports the blind and assured call transfer feature.
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_TRANSFER = 0x04000000;
+
+ /**
+ * When set for a call, indicates that this {@code Call} can be transferred to another
+ * ongoing call.
+ * Call supports the consultative call transfer feature.
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x08000000;
+
//******************************************************************************************
- // Next CAPABILITY value: 0x04000000
+ // Next CAPABILITY value: 0x10000000
//******************************************************************************************
/**
@@ -699,6 +718,12 @@
if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) {
builder.append(" CAPABILITY_ADD_PARTICIPANT");
}
+ if (can(capabilities, CAPABILITY_TRANSFER)) {
+ builder.append(" CAPABILITY_TRANSFER");
+ }
+ if (can(capabilities, CAPABILITY_TRANSFER_CONSULTATIVE)) {
+ builder.append(" CAPABILITY_TRANSFER_CONSULTATIVE");
+ }
builder.append("]");
return builder.toString();
}
@@ -1564,6 +1589,30 @@
}
/**
+ * Instructs this {@code Call} to be transferred to another number.
+ *
+ * @param targetNumber The address to which the call will be transferred.
+ * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
+ * if {@code false}, it will initiate BLIND transfer.
+ *
+ * @hide
+ */
+ public void transfer(@NonNull Uri targetNumber, boolean isConfirmationRequired) {
+ mInCallAdapter.transferCall(mTelecomCallId, targetNumber, isConfirmationRequired);
+ }
+
+ /**
+ * Instructs this {@code Call} to be transferred to another ongoing call.
+ * This will initiate CONSULTATIVE transfer.
+ * @param toCall The other ongoing {@code Call} to which this call will be transferred.
+ *
+ * @hide
+ */
+ public void transfer(@NonNull android.telecom.Call toCall) {
+ mInCallAdapter.transferCall(mTelecomCallId, toCall.mTelecomCallId);
+ }
+
+ /**
* Instructs this {@code Call} to disconnect.
*/
public void disconnect() {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
old mode 100644
new mode 100755
index 3b0ba254..4604cd2
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -387,8 +387,25 @@
* @hide
*/
public static final int CAPABILITY_ADD_PARTICIPANT = 0x04000000;
+
+ /**
+ * Indicates that this {@code Connection} can be transferred to another
+ * number.
+ * Connection supports the blind and assured call transfer feature.
+ * @hide
+ */
+ public static final int CAPABILITY_TRANSFER = 0x08000000;
+
+ /**
+ * Indicates that this {@code Connection} can be transferred to another
+ * ongoing {@code Connection}.
+ * Connection supports the consultative call transfer feature.
+ * @hide
+ */
+ public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x10000000;
+
//**********************************************************************************************
- // Next CAPABILITY value: 0x08000000
+ // Next CAPABILITY value: 0x20000000
//**********************************************************************************************
/**
@@ -967,6 +984,13 @@
if ((capabilities & CAPABILITY_ADD_PARTICIPANT) == CAPABILITY_ADD_PARTICIPANT) {
builder.append(isLong ? " CAPABILITY_ADD_PARTICIPANT" : " add_participant");
}
+ if ((capabilities & CAPABILITY_TRANSFER) == CAPABILITY_TRANSFER) {
+ builder.append(isLong ? " CAPABILITY_TRANSFER" : " sup_trans");
+ }
+ if ((capabilities & CAPABILITY_TRANSFER_CONSULTATIVE)
+ == CAPABILITY_TRANSFER_CONSULTATIVE) {
+ builder.append(isLong ? " CAPABILITY_TRANSFER_CONSULTATIVE" : " sup_cTrans");
+ }
builder.append("]");
return builder.toString();
}
@@ -3092,6 +3116,26 @@
public void onReject(String replyMessage) {}
/**
+ * Notifies this Connection, a request to transfer to a target number.
+ * @param number the number to transfer this {@link Connection} to.
+ * @param isConfirmationRequired when {@code true}, the {@link ConnectionService}
+ * should wait until the transfer has successfully completed before disconnecting
+ * the current {@link Connection}.
+ * When {@code false}, the {@link ConnectionService} should signal the network to
+ * perform the transfer, but should immediately disconnect the call regardless of
+ * the outcome of the transfer.
+ * @hide
+ */
+ public void onTransfer(@NonNull Uri number, boolean isConfirmationRequired) {}
+
+ /**
+ * Notifies this Connection, a request to transfer to another Connection.
+ * @param otherConnection the {@link Connection} to transfer this call to.
+ * @hide
+ */
+ public void onTransfer(@NonNull Connection otherConnection) {}
+
+ /**
* Notifies this Connection of a request to silence the ringer.
* <p>
* The ringer may be silenced by any of the following methods:
@@ -3532,7 +3576,7 @@
* ATIS-1000082.
* @return the verification status.
*/
- public @VerificationStatus int getCallerNumberVerificationStatus() {
+ public final @VerificationStatus int getCallerNumberVerificationStatus() {
return mCallerNumberVerificationStatus;
}
@@ -3544,7 +3588,7 @@
* by
* {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}.
*/
- public void setCallerNumberVerificationStatus(
+ public final void setCallerNumberVerificationStatus(
@VerificationStatus int callerNumberVerificationStatus) {
mCallerNumberVerificationStatus = callerNumberVerificationStatus;
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
old mode 100644
new mode 100755
index 2aea723..0dca006
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -128,6 +128,8 @@
private static final String SESSION_ANSWER = "CS.an";
private static final String SESSION_ANSWER_VIDEO = "CS.anV";
private static final String SESSION_DEFLECT = "CS.def";
+ private static final String SESSION_TRANSFER = "CS.trans";
+ private static final String SESSION_CONSULTATIVE_TRANSFER = "CS.cTrans";
private static final String SESSION_REJECT = "CS.r";
private static final String SESSION_REJECT_MESSAGE = "CS.rWM";
private static final String SESSION_SILENCE = "CS.s";
@@ -196,6 +198,8 @@
private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
private static final int MSG_REJECT_WITH_REASON = 38;
private static final int MSG_ADD_PARTICIPANT = 39;
+ private static final int MSG_EXPLICIT_CALL_TRANSFER = 40;
+ private static final int MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE = 41;
private static Connection sNullConnection;
@@ -481,6 +485,38 @@
}
@Override
+ public void transfer(@NonNull String callId, @NonNull Uri number,
+ boolean isConfirmationRequired, Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_TRANSFER);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = number;
+ args.argi1 = isConfirmationRequired ? 1 : 0;
+ args.arg3 = Log.createSubsession();
+ mHandler.obtainMessage(MSG_EXPLICIT_CALL_TRANSFER, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void consultativeTransfer(@NonNull String callId, @NonNull String otherCallId,
+ Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_CONSULTATIVE_TRANSFER);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = otherCallId;
+ args.arg3 = Log.createSubsession();
+ mHandler.obtainMessage(
+ MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void silence(String callId, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_SILENCE);
try {
@@ -1108,6 +1144,30 @@
}
break;
}
+ case MSG_EXPLICIT_CALL_TRANSFER: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg3, SESSION_HANDLER + SESSION_TRANSFER);
+ try {
+ final boolean isConfirmationRequired = args.argi1 == 1;
+ transfer((String) args.arg1, (Uri) args.arg2, isConfirmationRequired);
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
+ case MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession(
+ (Session) args.arg3, SESSION_HANDLER + SESSION_CONSULTATIVE_TRANSFER);
+ try {
+ consultativeTransfer((String) args.arg1, (String) args.arg2);
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
case MSG_DISCONNECT: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_DISCONNECT);
@@ -2042,6 +2102,18 @@
findConnectionForAction(callId, "reject").onReject(rejectReason);
}
+ private void transfer(String callId, Uri number, boolean isConfirmationRequired) {
+ Log.d(this, "transfer %s", callId);
+ findConnectionForAction(callId, "transfer").onTransfer(number, isConfirmationRequired);
+ }
+
+ private void consultativeTransfer(String callId, String otherCallId) {
+ Log.d(this, "consultativeTransfer %s", callId);
+ Connection connection1 = findConnectionForAction(callId, "consultativeTransfer");
+ Connection connection2 = findConnectionForAction(otherCallId, " consultativeTransfer");
+ connection1.onTransfer(connection2);
+ }
+
private void silence(String callId) {
Log.d(this, "silence %s", callId);
findConnectionForAction(callId, "silence").onSilence();
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
old mode 100644
new mode 100755
index 9d291740..dd6c153
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.NonNull;
import android.bluetooth.BluetoothDevice;
import android.net.Uri;
import android.os.Bundle;
@@ -102,6 +103,35 @@
}
/**
+ * Instructs Telecom to transfer the specified call.
+ *
+ * @param callId The identifier of the call to transfer.
+ * @param targetNumber The address to transfer to.
+ * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
+ * if {@code false}, it will initiate BLIND transfer.
+ */
+ public void transferCall(@NonNull String callId, @NonNull Uri targetNumber,
+ boolean isConfirmationRequired) {
+ try {
+ mAdapter.transferCall(callId, targetNumber, isConfirmationRequired);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecom to transfer the specified call to another ongoing call.
+ *
+ * @param callId The identifier of the call to transfer.
+ * @param otherCallId The identifier of the other call to which this will be transferred.
+ */
+ public void transferCall(@NonNull String callId, @NonNull String otherCallId) {
+ try {
+ mAdapter.consultativeTransfer(callId, otherCallId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Instructs Telecom to disconnect the specified call.
*
* @param callId The identifier of the call to disconnect.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index a397d77..fb54179 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -81,6 +81,11 @@
void rejectWithMessage(String callId, String message, in Session.Info sessionInfo);
+ void transfer(String callId, in Uri number, boolean isConfirmationRequired,
+ in Session.Info sessionInfo);
+
+ void consultativeTransfer(String callId, String otherCallId, in Session.Info sessionInfo);
+
void disconnect(String callId, in Session.Info sessionInfo);
void silence(String callId, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
old mode 100644
new mode 100755
index 9beff22..edf1cf4
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -36,6 +36,10 @@
void rejectCallWithReason(String callId, int rejectReason);
+ void transferCall(String callId, in Uri targetNumber, boolean isConfirmationRequired);
+
+ void consultativeTransfer(String callId, String otherCallId);
+
void disconnectCall(String callId);
void holdCall(String callId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 233eced..bca09e5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -839,7 +839,8 @@
/**
* The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in
* Settings->More->Emergency broadcasts menu even though developer options is turned on.
- * @deprecated moved to cellbroadcastreceiver resource show_test_settings
+ * @deprecated Use {@code com.android.cellbroadcastreceiver.CellBroadcastReceiver} resource
+ * {@code show_test_settings} to control whether to show test alert settings or not.
*/
@Deprecated
public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL =
@@ -1936,6 +1937,13 @@
"carrier_allow_deflect_ims_call_bool";
/**
+ * Flag indicating whether the carrier supports explicit call transfer for an IMS call.
+ * @hide
+ */
+ public static final String KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL =
+ "carrier_allow_transfer_ims_call_bool";
+
+ /**
* Flag indicating whether the carrier always wants to play an "on-hold" tone when a call has
* been remotely held.
* <p>
@@ -1965,10 +1973,15 @@
"allow_add_call_during_video_call";
/**
- * When false, indicates that holding a video call is disabled
+ * When {@code true}, indicates that video calls can be put on hold in order to swap to another
+ * call (e.g. a new outgoing call).
+ * When {@code false}, indicates that video calls will be disconnected when swapping to another
+ * call.
+ * <p>
+ * This is {@code true} by default.
*/
- public static final String KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL =
- "allow_holding_video_call";
+ public static final String KEY_ALLOW_HOLD_VIDEO_CALL_BOOL =
+ "allow_hold_video_call_bool";
/**
* When true, indicates that the HD audio icon in the in-call screen should not be shown for
@@ -3336,6 +3349,25 @@
"subscription_group_uuid_string";
/**
+ * Data switch validation minimal gap time, in milliseconds.
+ *
+ * Which means, if the same subscription on the same network (based on MCC+MNC+TAC+subId)
+ * was recently validated (within this time gap), and Telephony receives a request to switch to
+ * it again, Telephony will skip the validation part and switch to it as soon as connection
+ * is setup, as if it's already validated.
+ *
+ * If the network was validated within the gap but the latest validation result is false, the
+ * validation will not be skipped.
+ *
+ * If not set or set to 0, validation will never be skipped.
+ * The max acceptable value of this config is 24 hours.
+ *
+ * @hide
+ */
+ public static final String KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG =
+ "data_switch_validation_min_gap_LONG";
+
+ /**
* A boolean property indicating whether this subscription should be managed as an opportunistic
* subscription.
*
@@ -3420,6 +3452,7 @@
sDefaults.putString(KEY_CARRIER_CONFIG_VERSION_STRING, "");
sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false);
sDefaults.putBoolean(KEY_AUTO_RETRY_FAILED_WIFI_EMERGENCY_CALL, false);
sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
@@ -3713,7 +3746,7 @@
sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL, true);
sDefaults.putBoolean(KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL, true);
- sDefaults.putBoolean(KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL, true);
+ sDefaults.putBoolean(KEY_ALLOW_HOLD_VIDEO_CALL_BOOL, true);
sDefaults.putBoolean(KEY_WIFI_CALLS_CAN_BE_HD_AUDIO, true);
sDefaults.putBoolean(KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO, true);
sDefaults.putBoolean(KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO, false);
@@ -3902,6 +3935,7 @@
sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
CellSignalStrengthLte.USE_RSRP);
+ sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0);
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 4978dc1..2529387 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -244,19 +244,30 @@
} else {
mParametersUseForLevel = cc.getInt(
CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT);
- Rlog.i(LOG_TAG, "Using signal strength level: " + mParametersUseForLevel);
+ if (DBG) {
+ Rlog.i(LOG_TAG, "Using signal strength level: " + mParametersUseForLevel);
+ }
rsrpThresholds = cc.getIntArray(
CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY);
if (rsrpThresholds == null) rsrpThresholds = sRsrpThresholds;
- Rlog.i(LOG_TAG, "Applying LTE RSRP Thresholds: " + Arrays.toString(rsrpThresholds));
+ if (DBG) {
+ Rlog.i(LOG_TAG, "Applying LTE RSRP Thresholds: "
+ + Arrays.toString(rsrpThresholds));
+ }
rsrqThresholds = cc.getIntArray(
CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY);
if (rsrqThresholds == null) rsrqThresholds = sRsrqThresholds;
- Rlog.i(LOG_TAG, "Applying LTE RSRQ Thresholds: " + Arrays.toString(rsrqThresholds));
+ if (DBG) {
+ Rlog.i(LOG_TAG, "Applying LTE RSRQ Thresholds: "
+ + Arrays.toString(rsrqThresholds));
+ }
rssnrThresholds = cc.getIntArray(
CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY);
if (rssnrThresholds == null) rssnrThresholds = sRssnrThresholds;
- Rlog.i(LOG_TAG, "Applying LTE RSSNR Thresholds: " + Arrays.toString(rssnrThresholds));
+ if (DBG) {
+ Rlog.i(LOG_TAG, "Applying LTE RSSNR Thresholds: "
+ + Arrays.toString(rssnrThresholds));
+ }
rsrpOnly = cc.getBoolean(
CarrierConfigManager.KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL, false);
}
@@ -283,15 +294,21 @@
if (isLevelForParameter(USE_RSRP)) {
rsrpLevel = updateLevelWithMeasure(rsrp, rsrpThresholds);
- Rlog.i(LOG_TAG, "Updated 4G LTE RSRP Level: " + rsrpLevel);
+ if (DBG) {
+ Rlog.i(LOG_TAG, "Updated 4G LTE RSRP Level: " + rsrpLevel);
+ }
}
if (isLevelForParameter(USE_RSRQ)) {
rsrqLevel = updateLevelWithMeasure(mRsrq, rsrqThresholds);
- Rlog.i(LOG_TAG, "Updated 4G LTE RSRQ Level: " + rsrqLevel);
+ if (DBG) {
+ Rlog.i(LOG_TAG, "Updated 4G LTE RSRQ Level: " + rsrqLevel);
+ }
}
if (isLevelForParameter(USE_RSSNR)) {
rssnrLevel = updateLevelWithMeasure(mRssnr, rssnrThresholds);
- Rlog.i(LOG_TAG, "Updated 4G LTE RSSNR Level: " + rssnrLevel);
+ if (DBG) {
+ Rlog.i(LOG_TAG, "Updated 4G LTE RSSNR Level: " + rssnrLevel);
+ }
}
// Apply the smaller value among three levels of three measures.
mLevel = Math.min(Math.min(rsrpLevel, rsrqLevel), rssnrLevel);
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index e3d03a3..8562df1 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -40,6 +40,8 @@
*/
public static final int UNKNOWN_ASU_LEVEL = 99;
+ private static final boolean VDBG = false;
+
private static final String TAG = "CellSignalStrengthNr";
// Lifted from Default carrier configs and max range of SSRSRP
@@ -301,31 +303,45 @@
} else {
mParametersUseForLevel = cc.getInt(
CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, USE_SSRSRP);
- Rlog.i(TAG, "Using SSRSRP for Level.");
mSsRsrpThresholds = cc.getIntArray(
CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY);
- Rlog.i(TAG, "Applying 5G NR SSRSRP Thresholds: " + Arrays.toString(mSsRsrpThresholds));
+ if (VDBG) {
+ Rlog.i(TAG, "Applying 5G NR SSRSRP Thresholds: "
+ + Arrays.toString(mSsRsrpThresholds));
+ }
mSsRsrqThresholds = cc.getIntArray(
CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY);
- Rlog.i(TAG, "Applying 5G NR SSRSRQ Thresholds: " + Arrays.toString(mSsRsrqThresholds));
+ if (VDBG) {
+ Rlog.i(TAG, "Applying 5G NR SSRSRQ Thresholds: "
+ + Arrays.toString(mSsRsrqThresholds));
+ }
mSsSinrThresholds = cc.getIntArray(
CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY);
- Rlog.i(TAG, "Applying 5G NR SSSINR Thresholds: " + Arrays.toString(mSsSinrThresholds));
+ if (VDBG) {
+ Rlog.i(TAG, "Applying 5G NR SSSINR Thresholds: "
+ + Arrays.toString(mSsSinrThresholds));
+ }
}
int ssRsrpLevel = SignalStrength.INVALID;
int ssRsrqLevel = SignalStrength.INVALID;
int ssSinrLevel = SignalStrength.INVALID;
if (isLevelForParameter(USE_SSRSRP)) {
ssRsrpLevel = updateLevelWithMeasure(mSsRsrp, mSsRsrpThresholds);
- Rlog.i(TAG, "Updated 5G NR SSRSRP Level: " + ssRsrpLevel);
+ if (VDBG) {
+ Rlog.i(TAG, "Updated 5G NR SSRSRP Level: " + ssRsrpLevel);
+ }
}
if (isLevelForParameter(USE_SSRSRQ)) {
ssRsrqLevel = updateLevelWithMeasure(mSsRsrq, mSsRsrqThresholds);
- Rlog.i(TAG, "Updated 5G NR SSRSRQ Level: " + ssRsrqLevel);
+ if (VDBG) {
+ Rlog.i(TAG, "Updated 5G NR SSRSRQ Level: " + ssRsrqLevel);
+ }
}
if (isLevelForParameter(USE_SSSINR)) {
ssSinrLevel = updateLevelWithMeasure(mSsSinr, mSsSinrThresholds);
- Rlog.i(TAG, "Updated 5G NR SSSINR Level: " + ssSinrLevel);
+ if (VDBG) {
+ Rlog.i(TAG, "Updated 5G NR SSSINR Level: " + ssSinrLevel);
+ }
}
// Apply the smaller value among three levels of three measures.
mLevel = Math.min(Math.min(ssRsrpLevel, ssRsrqLevel), ssSinrLevel);
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index e7b2613..f86eeb2 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2015,8 +2015,12 @@
/**
* Gets the total capacity of SMS storage on RUIM and SIM cards
+ * <p>
+ * This is the number of 176 byte EF-SMS records which can be stored on the RUIM or SIM card.
+ * <p>
+ * See 3GPP TS 31.102 - 4.2.25 - EF-SMS for more information
*
- * @return the total capacity count of SMS on RUIM and SIM cards
+ * @return the total number of SMS records which can be stored on the RUIM or SIM cards.
* @hide
*/
@SystemApi
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
old mode 100644
new mode 100755
index 1b583fd..80c38cb
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -16,6 +16,8 @@
package android.telephony.ims;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.CallQuality;
@@ -451,6 +453,21 @@
}
/**
+ * Received success response for call transfer request.
+ */
+ public void callSessionTransferred(@NonNull ImsCallSession session) {
+ // no-op
+ }
+
+ /**
+ * Received failure response for call transfer request.
+ */
+ public void callSessionTransferFailed(@NonNull ImsCallSession session,
+ @Nullable ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
* Called when the IMS service reports a change to the call quality.
*/
public void callQualityChanged(CallQuality callQuality) {
@@ -795,6 +812,41 @@
}
/**
+ * Transfers an ongoing call.
+ *
+ * @param number number to be transferred to.
+ * @param isConfirmationRequired indicates blind or assured transfer.
+ */
+ public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.transfer(number, isConfirmationRequired);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Transfers a call to another ongoing call.
+ *
+ * @param transferToSession the other ImsCallSession to which this session will be transferred.
+ */
+ public void transfer(@NonNull ImsCallSession transferToSession) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ if (transferToSession != null) {
+ miSession.consultativeTransfer(transferToSession.getSession());
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Terminates a call.
*
* @see Listener#callSessionTerminated
@@ -1410,6 +1462,20 @@
}
}
+ @Override
+ public void callSessionTransferred() {
+ if (mListener != null) {
+ mListener.callSessionTransferred(ImsCallSession.this);
+ }
+ }
+
+ @Override
+ public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionTransferFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
/**
* Call quality updated
*/
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index cc2ebb9..36d2067 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -148,6 +148,12 @@
void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
/**
+ * Notifies the result of transfer request.
+ */
+ void callSessionTransferred();
+ void callSessionTransferFailed(in ImsReasonInfo reasonInfo);
+
+ /**
* Notifies of a change to the call quality.
* @param callQuality then updated call quality
*/
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
old mode 100644
new mode 100755
index 75bd6a7..06aa642
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -16,6 +16,8 @@
package android.telephony.ims.compat.stub;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Message;
import android.os.RemoteException;
@@ -197,6 +199,29 @@
}
/**
+ * Transfer an established call to given number, disconnecting the ongoing call
+ * when the transfer is complete.
+ *
+ * @param number number to transfer the call
+ * @param isConfirmationRequired when {@code true}, then the {@link ImsCallSessionImplBase}
+ * should wait until the transfer has successfully completed before disconnecting the current
+ * {@link ImsCallSessionImplBase}. When {@code false}, the {@link ImsCallSessionImplBase}
+ * should signal the network to perform the transfer, but should immediately disconnect the
+ * call regardless of the outcome of the transfer.
+ */
+ @Override
+ public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+ }
+
+ /**
+ * Transfer an established call to an existing ongoing session.
+ * When the transfer is complete, the current call gets disconnected locally.
+ */
+ @Override
+ public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
+ }
+
+ /**
* Rejects an incoming call or session update.
*
* @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
@@ -610,6 +635,17 @@
}
@Override
+ public void callSessionTransferred() throws RemoteException {
+ mNewListener.callSessionTransferred();
+ }
+
+ @Override
+ public void callSessionTransferFailed(@Nullable ImsReasonInfo reasonInfo)
+ throws RemoteException {
+ mNewListener.callSessionTransferFailed(reasonInfo);
+ }
+
+ @Override
public void callQualityChanged(CallQuality callQuality) throws RemoteException {
mNewListener.callQualityChanged(callQuality);
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index e8f69ea..73ba0e3 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -16,6 +16,7 @@
package android.telephony.ims.stub;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Message;
@@ -183,6 +184,18 @@
}
@Override
+ public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+ ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired);
+ }
+
+ @Override
+ public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
+ ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
+ otherSession.setServiceImpl(transferToSession);
+ ImsCallSessionImplBase.this.transfer(otherSession);
+ }
+
+ @Override
public void terminate(int reason) {
ImsCallSessionImplBase.this.terminate(reason);
}
@@ -423,6 +436,26 @@
}
/**
+ * Transfer an established call to given number
+ *
+ * @param number number to transfer the call
+ * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
+ * if {@code False} it indicates Blind transfer.
+ * @hide
+ */
+ public void transfer(@NonNull String number, boolean isConfirmationRequired) {
+ }
+
+ /**
+ * Transfer an established call to another call session
+ *
+ * @param otherSession The other ImsCallSession to transfer the ongoing session to.
+ * @hide
+ */
+ public void transfer(@NonNull ImsCallSessionImplBase otherSession) {
+ }
+
+ /**
* Terminates a call.
*
* @param reason reason code to terminate a call, defined in {@link ImsReasonInfo}.
diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
index 15234e5..0466efc 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -18,7 +18,6 @@
import android.os.Message;
import android.telephony.ims.aidl.IImsCallSessionListener;
-
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsStreamMediaProfile;
import com.android.ims.internal.IImsVideoCallProvider;
@@ -151,6 +150,22 @@
void reject(int reason);
/**
+ * Transfer an established call to given number
+ *
+ * @param number number to transfer the call
+ * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
+ * if {@code False} it indicates Blind transfer.
+ */
+ void transfer(String number, boolean isConfirmationRequired);
+
+ /**
+ * Transfer an established call to another call session
+ *
+ * @param transferToSession The other ImsCallSession to transfer the ongoing session to.
+ */
+ void consultativeTransfer(in IImsCallSession transferToSession);
+
+ /**
* Terminates a call.
*
* @see Listener#callSessionTerminated
diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
index b33a9f1..1c62cc4 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
@@ -184,6 +184,12 @@
void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
/**
+ * Notifies about the response for call transfer request.
+ */
+ void callSessionTransferred();
+
+ void callSessionTransferFailed(in ImsReasonInfo reasonInfo);
+ /**
* Notifies of a change to the call quality.
* @param callQuality then updated call quality
*/
diff --git a/tests/BootImageProfileTest/TEST_MAPPING b/tests/BootImageProfileTest/DISABLED_TEST_MAPPING
similarity index 100%
rename from tests/BootImageProfileTest/TEST_MAPPING
rename to tests/BootImageProfileTest/DISABLED_TEST_MAPPING
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index 490c467..23caf49 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -26,6 +26,7 @@
import android.os.IBinder
import com.android.networkstack.metrics.DataStallStatsUtils
import com.android.networkstack.netlink.TcpSocketTracker
+import com.android.server.NetworkStackService
import com.android.server.NetworkStackService.NetworkMonitorConnector
import com.android.server.NetworkStackService.NetworkStackConnector
import com.android.server.connectivity.NetworkMonitor
@@ -88,6 +89,7 @@
val nm = NetworkMonitor(this@TestNetworkStackService, cb,
this.network,
mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
+ mock(NetworkStackService.NetworkStackServiceManager::class.java),
NetworkMonitorDeps(privateDnsBypassNetwork),
mock(DataStallStatsUtils::class.java),
mock(TcpSocketTracker::class.java))
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 77147c8..86ba8af 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1180,6 +1180,10 @@
Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0),
}));
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
+ when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+ .thenReturn(applicationInfo);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
@@ -3041,7 +3045,7 @@
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, null, 0, null,
- ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME);
+ ConnectivityManager.TYPE_WIFI, mContext.getPackageName());
});
class NonParcelableSpecifier extends NetworkSpecifier {
@@ -6438,17 +6442,89 @@
assertEquals(wifiLp, mService.getActiveLinkProperties());
}
+ private void setupLocationPermissions(
+ int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = targetSdk;
+ when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
+ .thenReturn(applicationInfo);
+
+ when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
+
+ if (op != null) {
+ when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+ }
+
+ if (perm != null) {
+ mServiceContext.setPermission(perm, PERMISSION_GRANTED);
+ }
+ }
+
+ private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+ final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
+
+ return mService
+ .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
+ .getOwnerUid();
+ }
+
@Test
- public void testNetworkCapabilitiesRestrictedForCallerPermissions() {
- int callerUid = Process.myUid();
- final NetworkCapabilities originalNc = new NetworkCapabilities();
- originalNc.setOwnerUid(callerUid);
+ public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
- final NetworkCapabilities newNc =
- mService.networkCapabilitiesRestrictedForCallerPermissions(
- originalNc, Process.myPid(), callerUid);
+ final int myUid = Process.myUid();
+ assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
- assertEquals(Process.INVALID_UID, newNc.getOwnerUid());
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
+ // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
+ setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
+ // Test that even with fine location permission, not being the owner leads to sanitization.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
+ // Test that not having fine location permission leads to sanitization.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+
+ // Test that without the location permission, the owner field is sanitized.
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+ }
+
+ @Test
+ public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
+
+ // Test that without the location permission, the owner field is sanitized.
+ final int myUid = Process.myUid();
+ assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -6734,21 +6810,6 @@
mContext.getOpPackageName()));
}
- private void setupLocationPermissions(
- int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = targetSdk;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
-
- when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
-
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
-
- mServiceContext.setPermission(perm, PERMISSION_GRANTED);
- }
-
private void setUpConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);