Merge "Bluetooth ScanFilter: Allow null in setDeviceAddress"
diff --git a/Android.bp b/Android.bp
index c916f5d..c5d557c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -435,6 +435,19 @@
"--api-lint-ignore-prefix junit. " +
"--api-lint-ignore-prefix org. "
+packages_to_document = [
+ "android",
+ "dalvik",
+ "java",
+ "javax",
+ "junit",
+ "org.apache.http",
+ "org.json",
+ "org.w3c.dom",
+ "org.xml.sax",
+ "org.xmlpull",
+]
+
filegroup {
name: "android-non-updatable-stub-sources",
srcs: [
@@ -484,7 +497,7 @@
"android.hardware.usb.gadget-V1.0-java",
"android.hardware.vibrator-V1.3-java",
"framework-protos",
- "stable.core.platform.api.stubs",
+ "art.module.public.api",
// There are a few classes from modules used by the core that
// need to be resolved by metalava. We use a prebuilt stub of the
// full sdk to ensure we can resolve them. If a new class gets added,
@@ -493,6 +506,7 @@
// NOTE: The below can be removed once the prebuilt stub contains IKE.
"sdk_system_current_android.net.ipsec.ike",
],
+ filter_packages: packages_to_document,
high_mem: true, // Lots of sources => high memory use, see b/170701554
installable: false,
annotations_enabled: true,
diff --git a/ApiDocs.bp b/ApiDocs.bp
index c6a70d9..83ace02 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -89,13 +89,14 @@
":updatable-media-srcs",
// No longer part of the stubs, but are included in the docs.
- "test-base/src/**/*.java",
- "test-mock/src/**/*.java",
- "test-runner/src/**/*.java",
+ ":android-test-base-sources",
+ ":android-test-mock-sources",
+ ":android-test-runner-sources",
],
libs: framework_docs_only_libs,
create_doc_stubs: true,
annotations_enabled: true,
+ filter_packages: packages_to_document,
api_levels_annotations_enabled: true,
api_levels_annotations_dirs: [
"sdk-dir",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 96aac1a..626f977 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -27,24 +27,10 @@
// Common metalava configs
/////////////////////////////////////////////////////////////////////
-packages_to_document = [
- "android",
- "dalvik",
- "java",
- "javax",
- "junit",
- "org.apache.http",
- "org.json",
- "org.w3c.dom",
- "org.xml.sax",
- "org.xmlpull",
-]
-
stubs_defaults {
name: "metalava-non-updatable-api-stubs-default",
defaults: ["android-non-updatable-stubs-defaults"],
api_levels_annotations_enabled: false,
- filter_packages: packages_to_document,
defaults_visibility: ["//visibility:private"],
}
diff --git a/build/boot/boot-image-profile.txt b/boot/boot-image-profile.txt
similarity index 100%
rename from build/boot/boot-image-profile.txt
rename to boot/boot-image-profile.txt
diff --git a/build/boot/preloaded-classes b/boot/preloaded-classes
similarity index 100%
rename from build/boot/preloaded-classes
rename to boot/preloaded-classes
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ea626b3..bb42ddc 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12331,6 +12331,7 @@
field public static final int REGISTRATION_TECH_IWLAN = 1; // 0x1
field public static final int REGISTRATION_TECH_LTE = 0; // 0x0
field public static final int REGISTRATION_TECH_NONE = -1; // 0xffffffff
+ field public static final int REGISTRATION_TECH_NR = 3; // 0x3
}
public class ImsSmsImplBase {
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 98acd98..01d1aa5 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -79,6 +79,16 @@
public static final int DIRECTION_OUT = 1;
/**
+ * Used when applying a transform to direct traffic through an {@link IpSecTransform} for
+ * forwarding between interfaces.
+ *
+ * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
+ *
+ * @hide
+ */
+ public static final int DIRECTION_FWD = 2;
+
+ /**
* The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
*
* <p>No IPsec packet may contain an SPI of 0.
diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
index 5e93820..14e70cf 100644
--- a/core/java/android/net/vcn/VcnNetworkPolicyResult.java
+++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
@@ -87,6 +87,16 @@
&& mNetworkCapabilities.equals(that.mNetworkCapabilities);
}
+ @Override
+ public String toString() {
+ return "VcnNetworkPolicyResult { "
+ + "mIsTeardownRequested = "
+ + mIsTearDownRequested
+ + ", mNetworkCapabilities"
+ + mNetworkCapabilities
+ + " }";
+ }
+
/** {@inheritDoc} */
@Override
public int describeContents() {
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
index b47d564..b0d4f3b 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -85,6 +85,11 @@
return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult);
}
+ @Override
+ public String toString() {
+ return mVcnNetworkPolicyResult.toString();
+ }
+
/** {@inheritDoc} */
@Override
public int describeContents() {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index e47ffcc..5017d9e 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -424,7 +424,8 @@
* Magic version number for a current development build, which has
* not yet turned into an official release.
*/
- public static final int CUR_DEVELOPMENT = VMRuntime.SDK_VERSION_CUR_DEVELOPMENT;
+ // This must match VMRuntime.SDK_VERSION_CUR_DEVELOPMENT.
+ public static final int CUR_DEVELOPMENT = 10000;
/**
* October 2008: The original, first, version of Android. Yay!
@@ -1311,6 +1312,7 @@
* selinux into "permissive" mode in particular.
* @hide
*/
+ @UnsupportedAppUsage
public static final boolean IS_DEBUGGABLE =
SystemProperties.getInt("ro.debuggable", 0) == 1;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 1e60f74..a7516a4 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -74,8 +74,9 @@
*
* @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ // This must match VMDebug.TRACE_COUNT_ALLOCS.
@Deprecated
- public static final int TRACE_COUNT_ALLOCS = VMDebug.TRACE_COUNT_ALLOCS;
+ public static final int TRACE_COUNT_ALLOCS = 1;
/**
* Flags for printLoadedClasses(). Default behavior is to only show
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 6220abe..e74d3966a 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -528,6 +528,7 @@
"libhwui_defaults",
"android_graphics_apex",
"android_graphics_jni",
+ "linker_hugepage_aligned",
],
export_header_lib_headers: ["android_graphics_apex_headers"],
}
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 139474c..67a040d 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -160,7 +161,7 @@
be set to true when the phone is having emergency call, and then will
be set to false by mPhoneStateListener when the emergency call ends.
*/
- mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(phoneNumber);
+ mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber);
if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
} else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
updateLocationMode();
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 2d9bdaf..3131965 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -127,6 +127,9 @@
public static final int SAMPLE_RATE_HZ_MIN = native_getMinSampleRate();
private static native int native_getMinSampleRate();
+ /** @hide */
+ public static final int FCC_24 = 24; // fixed channel count 24; do not change.
+
// Expose only the getter method publicly so we can change it in the future
private static final int NUM_STREAM_TYPES = 12;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 7c91f52..68ce5e7 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1712,9 +1712,10 @@
mChannelCount = 0;
break; // channel index configuration only
}
- if (!isMultichannelConfigSupported(channelConfig)) {
- // input channel configuration features unsupported channels
- throw new IllegalArgumentException("Unsupported channel configuration.");
+ if (!isMultichannelConfigSupported(channelConfig, audioFormat)) {
+ throw new IllegalArgumentException(
+ "Unsupported channel mask configuration " + channelConfig
+ + " for encoding " + audioFormat);
}
mChannelMask = channelConfig;
mChannelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
@@ -1722,13 +1723,17 @@
// check the channel index configuration (if present)
mChannelIndexMask = channelIndexMask;
if (mChannelIndexMask != 0) {
- // restrictive: indexMask could allow up to AUDIO_CHANNEL_BITS_LOG2
- final int indexMask = (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1;
- if ((channelIndexMask & ~indexMask) != 0) {
- throw new IllegalArgumentException("Unsupported channel index configuration "
- + channelIndexMask);
+ // As of S, we accept up to 24 channel index mask.
+ final int fullIndexMask = (1 << AudioSystem.FCC_24) - 1;
+ final int channelIndexCount = Integer.bitCount(channelIndexMask);
+ final boolean accepted = (channelIndexMask & ~fullIndexMask) == 0
+ && (!AudioFormat.isEncodingLinearFrames(audioFormat) // compressed OK
+ || channelIndexCount <= AudioSystem.OUT_CHANNEL_COUNT_MAX); // PCM
+ if (!accepted) {
+ throw new IllegalArgumentException(
+ "Unsupported channel index mask configuration " + channelIndexMask
+ + " for encoding " + audioFormat);
}
- int channelIndexCount = Integer.bitCount(channelIndexMask);
if (mChannelCount == 0) {
mChannelCount = channelIndexCount;
} else if (mChannelCount != channelIndexCount) {
@@ -1781,16 +1786,19 @@
* @param channelConfig the mask to validate
* @return false if the AudioTrack can't be used with such a mask
*/
- private static boolean isMultichannelConfigSupported(int channelConfig) {
+ private static boolean isMultichannelConfigSupported(int channelConfig, int encoding) {
// check for unsupported channels
if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) {
loge("Channel configuration features unsupported channels");
return false;
}
final int channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
- if (channelCount > AudioSystem.OUT_CHANNEL_COUNT_MAX) {
- loge("Channel configuration contains too many channels " +
- channelCount + ">" + AudioSystem.OUT_CHANNEL_COUNT_MAX);
+ final int channelCountLimit = AudioFormat.isEncodingLinearFrames(encoding)
+ ? AudioSystem.OUT_CHANNEL_COUNT_MAX // PCM limited to OUT_CHANNEL_COUNT_MAX
+ : AudioSystem.FCC_24; // Compressed limited to 24 channels
+ if (channelCount > channelCountLimit) {
+ loge("Channel configuration contains too many channels for encoding "
+ + encoding + "(" + channelCount + " > " + channelCountLimit + ")");
return false;
}
// check for unsupported multichannel combinations:
@@ -2301,7 +2309,7 @@
channelCount = 2;
break;
default:
- if (!isMultichannelConfigSupported(channelConfig)) {
+ if (!isMultichannelConfigSupported(channelConfig, audioFormat)) {
loge("getMinBufferSize(): Invalid channel configuration.");
return ERROR_BAD_VALUE;
} else {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 937a9d2..950b1c7 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -2444,7 +2444,8 @@
* For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
* {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
* to be selected. This is logically different than
- * {@code NetworkCapabilities.NET_CAPABILITY_*}.
+ * {@code NetworkCapabilities.NET_CAPABILITY_*}. Also note that multiple networks with the
+ * same transport type may be active concurrently.
*
* @param transportType the transport type to be added or removed.
* @return this builder
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index bcabec8..2c1d3e2 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -683,6 +683,16 @@
assertThat(ap.getTitle()).isEqualTo(providerFriendlyName);
}
+ // This method doesn't copy mIsFailover, mIsAvailable and mIsRoaming because NetworkInfo
+ // doesn't expose those three set methods. But that's fine since the tests don't use those three
+ // variables.
+ private NetworkInfo copyNetworkInfo(NetworkInfo ni) {
+ final NetworkInfo copy = new NetworkInfo(ni.getType(), ni.getSubtype(), ni.getTypeName(),
+ ni.getSubtypeName());
+ copy.setDetailedState(ni.getDetailedState(), ni.getReason(), ni.getExtraInfo());
+ return copy;
+ }
+
@Test
public void testUpdateNetworkInfo_returnsTrue() {
int networkId = 123;
@@ -704,7 +714,7 @@
.setWifiInfo(wifiInfo)
.build();
- NetworkInfo newInfo = new NetworkInfo(networkInfo);
+ NetworkInfo newInfo = copyNetworkInfo(networkInfo);
newInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
}
@@ -730,7 +740,7 @@
.setWifiInfo(wifiInfo)
.build();
- NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+ NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
}
@@ -755,7 +765,7 @@
.setWifiInfo(wifiInfo)
.build();
- NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+ NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
wifiInfo.setRssi(rssi + 1);
assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
}
@@ -781,7 +791,7 @@
.setWifiInfo(wifiInfo)
.build();
- NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
+ NetworkInfo newInfo = copyNetworkInfo(networkInfo); // same values
wifiInfo.setRssi(WifiInfo.INVALID_RSSI);
assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 5a52597..9e60356 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -114,7 +114,7 @@
private val onSeedingComplete = Consumer<Boolean> {
accepted ->
if (accepted) {
- selectedStructure = controlsController.get().getFavorites().maxBy {
+ selectedStructure = controlsController.get().getFavorites().maxByOrNull {
it.controls.size
} ?: EMPTY_STRUCTURE
updatePreferences(selectedStructure)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
index 1d2e747..eec69f98 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
@@ -28,7 +28,7 @@
appsAndTypes = itemsList.groupBy({ it.application }, { it.privacyType })
.toList()
.sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps
- { it.second.min() })) // Sort by "smallest" AppOpp (Location is largest)
+ { it.second.minOrNull() })) // Sort by "smallest" AppOpp (Location is largest)
types = itemsList.map { it.privacyType }.distinct().sorted()
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 794cb93..d6ee951 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -49,6 +49,7 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.system.ErrnoException;
@@ -65,6 +66,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.net.module.util.NetdUtils;
+import com.android.net.module.util.PermissionUtils;
import libcore.io.IoUtils;
@@ -466,8 +468,7 @@
/** Safety method; guards against access of other user's UserRecords */
private void checkCallerUid(int uid) {
- if (uid != Binder.getCallingUid()
- && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
+ if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) {
throw new SecurityException("Attempted access of unowned resources");
}
}
@@ -1105,11 +1106,15 @@
* Checks the user-provided direction field and throws an IllegalArgumentException if it is not
* DIRECTION_IN or DIRECTION_OUT
*/
- private static void checkDirection(int direction) {
+ private void checkDirection(int direction) {
switch (direction) {
case IpSecManager.DIRECTION_OUT:
case IpSecManager.DIRECTION_IN:
return;
+ case IpSecManager.DIRECTION_FWD:
+ // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ return;
}
throw new IllegalArgumentException("Invalid Direction: " + direction);
}
@@ -1353,6 +1358,26 @@
ikey,
0xffffffff,
resourceId);
+
+ // Add a forwarding policy on the tunnel interface. In order to support forwarding
+ // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA.
+ //
+ // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD,
+ // forwarding will be blocked by default (as would be the case if this policy was
+ // absent).
+ //
+ // This is necessary only on the tunnel interface, and not any the interface to
+ // which traffic will be forwarded to.
+ netd.ipSecAddSecurityPolicy(
+ callerUid,
+ selAddrFamily,
+ IpSecManager.DIRECTION_FWD,
+ remoteAddr,
+ localAddr,
+ 0,
+ ikey,
+ 0xffffffff,
+ resourceId);
}
userRecord.mTunnelInterfaceRecords.put(
@@ -1820,7 +1845,7 @@
int mark =
(direction == IpSecManager.DIRECTION_OUT)
? tunnelInterfaceInfo.getOkey()
- : tunnelInterfaceInfo.getIkey();
+ : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies
try {
// Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 471d2af..1fd637a 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -434,6 +434,7 @@
synchronized (mLock) {
final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot;
mLastSnapshot = snapshot;
+ Slog.d(TAG, "new snapshot: " + mLastSnapshot);
// Start any VCN instances as necessary
for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
@@ -536,7 +537,7 @@
@GuardedBy("mLock")
private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
- Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
+ Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
// TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
// VCN.
@@ -558,7 +559,7 @@
@GuardedBy("mLock")
private void startOrUpdateVcnLocked(
@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
- Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup);
+ Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup);
if (mVcns.containsKey(subscriptionGroup)) {
final Vcn vcn = mVcns.get(subscriptionGroup);
@@ -584,7 +585,7 @@
if (!config.getProvisioningPackageName().equals(opPkgName)) {
throw new IllegalArgumentException("Mismatched caller and VcnConfig creator");
}
- Slog.v(TAG, "VCN config updated for subGrp: " + subscriptionGroup);
+ Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup);
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName());
@@ -609,7 +610,7 @@
public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
requireNonNull(opPkgName, "opPkgName was null");
- Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
+ Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), opPkgName);
@@ -845,8 +846,14 @@
}
final NetworkCapabilities result = ncBuilder.build();
- return new VcnUnderlyingNetworkPolicy(
+ final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
+
+ if (VDBG) {
+ Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
+ + "; and lp: " + linkProperties + "; result = " + policy);
+ }
+ return policy;
});
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index a37115d..2e38278 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -96,6 +96,7 @@
"/system/bin/audioserver",
"/system/bin/cameraserver",
"/system/bin/drmserver",
+ "/system/bin/keystore2",
"/system/bin/mediadrmserver",
"/system/bin/mediaserver",
"/system/bin/netd",
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index f41c364..1ecb9eb 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -31,6 +31,8 @@
import libcore.io.IoUtils;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
@@ -43,8 +45,12 @@
public class LmkdConnection {
private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM;
- // lmkd reply max size in bytes
- private static final int LMKD_REPLY_MAX_SIZE = 12;
+ /**
+ * Max LMKD reply packet length in bytes
+ * Used to hold the data for the statsd atoms logging
+ * Must be in sync with statslog.h
+ */
+ private static final int LMKD_REPLY_MAX_SIZE = 214;
// connection listener interface
interface LmkdConnectionListener {
@@ -70,7 +76,7 @@
* @param receivedLen Size of the data received
* @return True if the message has been handled correctly, false otherwise.
*/
- boolean handleUnsolicitedMessage(ByteBuffer dataReceived, int receivedLen);
+ boolean handleUnsolicitedMessage(DataInputStream inputData, int receivedLen);
}
private final MessageQueue mMsgQueue;
@@ -95,6 +101,10 @@
private final ByteBuffer mInputBuf =
ByteBuffer.allocate(LMKD_REPLY_MAX_SIZE);
+ // Input stream to parse the incoming data
+ private final DataInputStream mInputData = new DataInputStream(
+ new ByteArrayInputStream(mInputBuf.array()));
+
// object to protect mReplyBuf and to wait/notify when reply is received
private final Object mReplyBufLock = new Object();
@@ -186,26 +196,32 @@
private void processIncomingData() {
int len = read(mInputBuf);
if (len > 0) {
- synchronized (mReplyBufLock) {
- if (mReplyBuf != null) {
- if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) {
- // copy into reply buffer
- mReplyBuf.put(mInputBuf.array(), 0, len);
- mReplyBuf.rewind();
- // wakeup the waiting thread
- mReplyBufLock.notifyAll();
- } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
- // received unexpected packet
- // treat this as an error
- mReplyBuf = null;
- mReplyBufLock.notifyAll();
- Slog.e(TAG, "Received an unexpected packet from lmkd");
+ try {
+ // reset InputStream to point into mInputBuf.array() begin
+ mInputData.reset();
+ synchronized (mReplyBufLock) {
+ if (mReplyBuf != null) {
+ if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) {
+ // copy into reply buffer
+ mReplyBuf.put(mInputBuf.array(), 0, len);
+ mReplyBuf.rewind();
+ // wakeup the waiting thread
+ mReplyBufLock.notifyAll();
+ } else if (!mListener.handleUnsolicitedMessage(mInputData, len)) {
+ // received unexpected packet
+ // treat this as an error
+ mReplyBuf = null;
+ mReplyBufLock.notifyAll();
+ Slog.e(TAG, "Received an unexpected packet from lmkd");
+ }
+ } else if (!mListener.handleUnsolicitedMessage(mInputData, len)) {
+ // received asynchronous communication from lmkd
+ // but we don't recognize it.
+ Slog.w(TAG, "Received an unexpected packet from lmkd");
}
- } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
- // received asynchronous communication from lmkd
- // but we don't recognize it.
- Slog.w(TAG, "Received an unexpected packet from lmkd");
}
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to parse lmkd data buffer. Size = " + len);
}
}
}
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
new file mode 100644
index 0000000..c702d78
--- /dev/null
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 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 com.android.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.util.Slog;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Activity manager communication with lmkd data handling and statsd atom logging
+ */
+public final class LmkdStatsReporter {
+
+ static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdStatsReporter" : TAG_AM;
+
+ public static final int KILL_OCCURRED_MSG_SIZE = 80;
+ public static final int STATE_CHANGED_MSG_SIZE = 8;
+
+ private static final int PRESSURE_AFTER_KILL = 0;
+ private static final int NOT_RESPONDING = 1;
+ private static final int LOW_SWAP_AND_THRASHING = 2;
+ private static final int LOW_MEM_AND_SWAP = 3;
+ private static final int LOW_MEM_AND_THRASHING = 4;
+ private static final int DIRECT_RECL_AND_THRASHING = 5;
+ private static final int LOW_MEM_AND_SWAP_UTIL = 6;
+
+ /**
+ * Processes the LMK_KILL_OCCURRED packet data
+ * Logs the event when LMKD kills a process to reduce memory pressure.
+ * Code: LMK_KILL_OCCURRED = 51
+ */
+ public static void logKillOccurred(DataInputStream inputData) {
+ try {
+ final long pgFault = inputData.readLong();
+ final long pgMajFault = inputData.readLong();
+ final long rssInBytes = inputData.readLong();
+ final long cacheInBytes = inputData.readLong();
+ final long swapInBytes = inputData.readLong();
+ final long processStartTimeNS = inputData.readLong();
+ final int uid = inputData.readInt();
+ final int oomScore = inputData.readInt();
+ final int minOomScore = inputData.readInt();
+ final int freeMemKb = inputData.readInt();
+ final int freeSwapKb = inputData.readInt();
+ final int killReason = inputData.readInt();
+ final String procName = inputData.readUTF();
+
+ FrameworkStatsLog.write(FrameworkStatsLog.LMK_KILL_OCCURRED, uid, procName, oomScore,
+ pgFault, pgMajFault, rssInBytes, cacheInBytes, swapInBytes, processStartTimeNS,
+ minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason));
+ } catch (IOException e) {
+ Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
+ return;
+ }
+ }
+
+ /**
+ * Processes the LMK_STATE_CHANGED packet
+ * Logs the change in LMKD state which is used as start/stop boundaries for logging
+ * LMK_KILL_OCCURRED event.
+ * Code: LMK_STATE_CHANGED = 54
+ */
+ public static void logStateChanged(int state) {
+ FrameworkStatsLog.write(FrameworkStatsLog.LMK_STATE_CHANGED, state);
+ }
+
+ private static int mapKillReason(int reason) {
+ switch (reason) {
+ case PRESSURE_AFTER_KILL:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__PRESSURE_AFTER_KILL;
+ case NOT_RESPONDING:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__NOT_RESPONDING;
+ case LOW_SWAP_AND_THRASHING:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_SWAP_AND_THRASHING;
+ case LOW_MEM_AND_SWAP:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP;
+ case LOW_MEM_AND_THRASHING:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_THRASHING;
+ case DIRECT_RECL_AND_THRASHING:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_AND_THRASHING;
+ case LOW_MEM_AND_SWAP_UTIL:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP_UTIL;
+ default:
+ return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 444418c..e9b0146 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -125,6 +125,7 @@
import dalvik.system.VMRuntime;
+import java.io.DataInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -316,18 +317,25 @@
// LMK_GETKILLCNT
// LMK_SUBSCRIBE
// LMK_PROCKILL
+ // LMK_UPDATE_PROPS
+ // LMK_KILL_OCCURRED
+ // LMK_STATE_CHANGED
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
static final byte LMK_PROCPURGE = 3;
static final byte LMK_GETKILLCNT = 4;
static final byte LMK_SUBSCRIBE = 5;
- static final byte LMK_PROCKILL = 6; // Note: this is an unsolicated command
+ static final byte LMK_PROCKILL = 6; // Note: this is an unsolicited command
+ static final byte LMK_UPDATE_PROPS = 7;
+ static final byte LMK_KILL_OCCURRED = 8; // Msg to subscribed clients on kill occurred event
+ static final byte LMK_STATE_CHANGED = 9; // Msg to subscribed clients on state changed
// Low Memory Killer Daemon command codes.
// These must be kept in sync with async_event_type definitions in lmkd.h
//
static final int LMK_ASYNC_EVENT_KILL = 0;
+ static final int LMK_ASYNC_EVENT_STAT = 1;
// lmkd reconnect delay in msecs
private static final long LMKD_RECONNECT_DELAY_MS = 1000;
@@ -776,22 +784,44 @@
}
@Override
- public boolean handleUnsolicitedMessage(ByteBuffer dataReceived,
+ public boolean handleUnsolicitedMessage(DataInputStream inputData,
int receivedLen) {
if (receivedLen < 4) {
return false;
}
- switch (dataReceived.getInt(0)) {
- case LMK_PROCKILL:
- if (receivedLen != 12) {
+
+ try {
+ switch (inputData.readInt()) {
+ case LMK_PROCKILL:
+ if (receivedLen != 12) {
+ return false;
+ }
+ final int pid = inputData.readInt();
+ final int uid = inputData.readInt();
+ mAppExitInfoTracker.scheduleNoteLmkdProcKilled(pid, uid);
+ return true;
+ case LMK_KILL_OCCURRED:
+ if (receivedLen
+ < LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) {
+ return false;
+ }
+ LmkdStatsReporter.logKillOccurred(inputData);
+ return true;
+ case LMK_STATE_CHANGED:
+ if (receivedLen
+ != LmkdStatsReporter.STATE_CHANGED_MSG_SIZE) {
+ return false;
+ }
+ final int state = inputData.readInt();
+ LmkdStatsReporter.logStateChanged(state);
+ return true;
+ default:
return false;
- }
- mAppExitInfoTracker.scheduleNoteLmkdProcKilled(
- dataReceived.getInt(4), dataReceived.getInt(8));
- return true;
- default:
- return false;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
}
+ return false;
}
}
);
@@ -1433,6 +1463,12 @@
buf.putInt(LMK_SUBSCRIBE);
buf.putInt(LMK_ASYNC_EVENT_KILL);
ostream.write(buf.array(), 0, buf.position());
+
+ // Subscribe for stats event notifications
+ buf = ByteBuffer.allocate(4 * 2);
+ buf.putInt(LMK_SUBSCRIBE);
+ buf.putInt(LMK_ASYNC_EVENT_STAT);
+ ostream.write(buf.array(), 0, buf.position());
} catch (IOException ex) {
return false;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
index 740407c..e233084 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
@@ -86,6 +86,8 @@
pw.println(" Send a Vendor Command to the given target device");
pw.println(" setsystemaudiomode, setsam [on|off]");
pw.println(" Sets the System Audio Mode feature on or off on TV devices");
+ pw.println(" setarc [on|off]");
+ pw.println(" Sets the ARC feature on or off on TV devices");
}
private int handleShellCommand(String cmd) throws RemoteException {
@@ -100,6 +102,8 @@
case "setsystemaudiomode":
case "setsam":
return setSystemAudioMode(pw);
+ case "setarc":
+ return setArcMode(pw);
}
getErrPrintWriter().println("Unhandled command: " + cmd);
@@ -188,6 +192,27 @@
return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
}
+ private int setArcMode(PrintWriter pw) throws RemoteException {
+ if (1 > getRemainingArgsCount()) {
+ throw new IllegalArgumentException(
+ "Please indicate if ARC mode should be turned \"on\" or \"off\".");
+ }
+
+ String arg = getNextArg();
+ if (arg.equals("on")) {
+ pw.println("Setting ARC mode on");
+ mBinderService.setArcMode(true);
+ } else if (arg.equals("off")) {
+ pw.println("Setting ARC mode off");
+ mBinderService.setArcMode(false);
+ } else {
+ throw new IllegalArgumentException(
+ "Please indicate if ARC mode should be turned \"on\" or \"off\".");
+ }
+
+ return 0;
+ }
+
private boolean receiveCallback(String command) {
try {
if (!mLatch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index acec93c..77c1c1d 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -16,7 +16,6 @@
package com.android.server.pm;
-import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.Nullable;
@@ -24,12 +23,13 @@
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
-import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
import android.os.Environment;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -37,6 +37,7 @@
import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -65,9 +66,7 @@
private static final int JOB_IDLE_OPTIMIZE = 800;
private static final int JOB_POST_BOOT_UPDATE = 801;
- private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
- ? TimeUnit.MINUTES.toMillis(1)
- : TimeUnit.DAYS.toMillis(1);
+ private static final long IDLE_OPTIMIZATION_PERIOD = TimeUnit.DAYS.toMillis(1);
private static ComponentName sDexoptServiceName = new ComponentName(
"android",
@@ -115,14 +114,24 @@
return;
}
- JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ final JobScheduler js = context.getSystemService(JobScheduler.class);
// Schedule a one-off job which scans installed packages and updates
- // out-of-date oat files.
- js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
- .setMinimumLatency(TimeUnit.MINUTES.toMillis(1))
- .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1))
- .build());
+ // out-of-date oat files. Schedule it 10 minutes after the boot complete event,
+ // so that we don't overload the boot with additional dex2oat compilations.
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
+ .setMinimumLatency(TimeUnit.MINUTES.toMillis(10))
+ .setOverrideDeadline(TimeUnit.MINUTES.toMillis(60))
+ .build());
+ context.unregisterReceiver(this);
+ if (DEBUG) {
+ Slog.i(TAG, "BootBgDexopt scheduled");
+ }
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
// Schedule a daily job which scans installed packages and compiles
// those with fresh profiling data.
@@ -132,8 +141,8 @@
.setPeriodic(IDLE_OPTIMIZATION_PERIOD)
.build());
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Jobs scheduled");
+ if (DEBUG) {
+ Slog.d(TAG, "BgDexopt scheduled");
}
}
@@ -149,32 +158,11 @@
}
}
- // Returns the current battery level as a 0-100 integer.
- private int getBatteryLevel() {
- IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- Intent intent = registerReceiver(null, filter);
- int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
- boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
-
- if (!present) {
- // No battery, treat as if 100%, no possibility of draining battery.
- return 100;
- }
-
- if (level < 0 || scale <= 0) {
- // Battery data unavailable. This should never happen, so assume the worst.
- return 0;
- }
-
- return (100 * level / scale);
- }
-
private long getLowStorageThreshold(Context context) {
@SuppressWarnings("deprecation")
final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir);
if (lowThreshold == 0) {
- Log.e(TAG, "Invalid low storage threshold");
+ Slog.e(TAG, "Invalid low storage threshold");
}
return lowThreshold;
@@ -198,9 +186,8 @@
private void postBootUpdate(JobParameters jobParams, PackageManagerService pm,
ArraySet<String> pkgs) {
- // Load low battery threshold from the system config. This is a 0-100 integer.
- final int lowBatteryThreshold = getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryWarningLevel);
+ final BatteryManagerInternal batteryManagerInternal =
+ LocalServices.getService(BatteryManagerInternal.class);
final long lowThreshold = getLowStorageThreshold(this);
mAbortPostBootUpdate.set(false);
@@ -215,20 +202,19 @@
// Different job, which supersedes this one, is running.
break;
}
- if (getBatteryLevel() < lowBatteryThreshold) {
+ if (batteryManagerInternal.getBatteryLevelLow()) {
// Rather bail than completely drain the battery.
break;
}
long usableSpace = mDataDir.getUsableSpace();
if (usableSpace < lowThreshold) {
// Rather bail than completely fill up the disk.
- Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+ Slog.w(TAG, "Aborting background dex opt job due to low storage: " +
usableSpace);
break;
}
-
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Updating package " + pkg);
+ if (DEBUG) {
+ Slog.i(TAG, "Updating package " + pkg);
}
// Update package if needed. Note that there can be no race between concurrent
@@ -260,13 +246,13 @@
public void run() {
int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
if (result == OPTIMIZE_PROCESSED) {
- Log.i(TAG, "Idle optimizations completed.");
+ Slog.i(TAG, "Idle optimizations completed.");
} else if (result == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
- Log.w(TAG, "Idle optimizations aborted because of space constraints.");
+ Slog.w(TAG, "Idle optimizations aborted because of space constraints.");
} else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
- Log.w(TAG, "Idle optimizations aborted by job scheduler.");
+ Slog.w(TAG, "Idle optimizations aborted by job scheduler.");
} else {
- Log.w(TAG, "Idle optimizations ended with unexpected code: " + result);
+ Slog.w(TAG, "Idle optimizations ended with unexpected code: " + result);
}
if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
// Abandon our timeslice and do not reschedule.
@@ -280,7 +266,7 @@
// Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
Context context) {
- Log.i(TAG, "Performing idle optimizations");
+ Slog.i(TAG, "Performing idle optimizations");
// If post-boot update is still running, request that it exits early.
mExitPostBootUpdate.set(true);
mAbortIdleOptimization.set(false);
@@ -355,11 +341,15 @@
final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
* lowStorageThreshold;
boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
- Log.d(TAG, "Should Downgrade " + shouldDowngrade);
+ if (DEBUG) {
+ Slog.d(TAG, "Should Downgrade " + shouldDowngrade);
+ }
if (shouldDowngrade) {
Set<String> unusedPackages =
pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
- Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
+ if (DEBUG) {
+ Slog.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
+ }
if (!unusedPackages.isEmpty()) {
for (String pkg : unusedPackages) {
@@ -431,7 +421,9 @@
*/
private boolean downgradePackage(PackageManagerService pm, String pkg,
boolean isForPrimaryDex) {
- Log.d(TAG, "Downgrading " + pkg);
+ if (DEBUG) {
+ Slog.d(TAG, "Downgrading " + pkg);
+ }
boolean dex_opt_performed = false;
int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
@@ -553,7 +545,7 @@
long usableSpace = mDataDir.getUsableSpace();
if (usableSpace < lowStorageThreshold) {
// Rather bail than completely fill up the disk.
- Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
+ Slog.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
return OPTIMIZE_ABORT_NO_SPACE_LEFT;
}
@@ -592,8 +584,8 @@
@Override
public boolean onStartJob(JobParameters params) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "onStartJob");
+ if (DEBUG) {
+ Slog.i(TAG, "onStartJob");
}
// NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
@@ -601,17 +593,13 @@
// restart with a period of ~1 minute.
PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
if (pm.isStorageLow()) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Low storage, skipping this run");
- }
+ Slog.i(TAG, "Low storage, skipping this run");
return false;
}
final ArraySet<String> pkgs = pm.getOptimizablePackages();
if (pkgs.isEmpty()) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "No packages to optimize");
- }
+ Slog.i(TAG, "No packages to optimize");
return false;
}
@@ -627,8 +615,8 @@
@Override
public boolean onStopJob(JobParameters params) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "onStopJob");
+ if (DEBUG) {
+ Slog.d(TAG, "onStopJob");
}
if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
@@ -649,7 +637,7 @@
private void notifyPinService(ArraySet<String> updatedPackages) {
PinnerService pinnerService = LocalServices.getService(PinnerService.class);
if (pinnerService != null) {
- Log.i(TAG, "Pinning optimized code " + updatedPackages);
+ Slog.i(TAG, "Pinning optimized code " + updatedPackages);
pinnerService.update(updatedPackages, false /* force */);
}
}
@@ -684,7 +672,7 @@
final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
String sysPropValue = SystemProperties.get(sysPropKey);
if (sysPropValue == null || sysPropValue.isEmpty()) {
- Log.w(TAG, "SysProp " + sysPropKey + " not set");
+ Slog.w(TAG, "SysProp " + sysPropKey + " not set");
return Long.MAX_VALUE;
}
return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 12e55e5..ed4a7bf 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -27,6 +27,7 @@
import static android.ota.nano.OtaPackageMetadata.ApexMetadata;
import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
import android.annotation.IntDef;
import android.apex.CompressedApexInfo;
@@ -398,7 +399,13 @@
@VisibleForTesting
void onSystemServicesReady() {
- mInjector.getLockSettingsService().setRebootEscrowListener(this);
+ LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+ if (lockSettings == null) {
+ Slog.e(TAG, "Failed to get lock settings service, skipping set"
+ + " RebootEscrowListener");
+ return;
+ }
+ lockSettings.setRebootEscrowListener(this);
}
@Override // Binder call
@@ -564,12 +571,18 @@
case ROR_NEED_PREPARATION:
final long origId = Binder.clearCallingIdentity();
try {
- boolean result = mInjector.getLockSettingsService().prepareRebootEscrow();
- // Clear the RoR preparation state if lock settings reports an failure.
- if (!result) {
- clearRoRPreparationState();
+ LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+ if (lockSettings == null) {
+ Slog.e(TAG, "Failed to get lock settings service, skipping"
+ + " prepareRebootEscrow");
+ return false;
}
- return result;
+ // Clear the RoR preparation state if lock settings reports an failure.
+ if (!lockSettings.prepareRebootEscrow()) {
+ clearRoRPreparationState();
+ return false;
+ }
+ return true;
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -684,7 +697,14 @@
case ROR_REQUESTED_NEED_CLEAR:
final long origId = Binder.clearCallingIdentity();
try {
- return mInjector.getLockSettingsService().clearRebootEscrow();
+ LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+ if (lockSettings == null) {
+ Slog.e(TAG, "Failed to get lock settings service, skipping"
+ + " clearRebootEscrow");
+ return false;
+ }
+
+ return lockSettings.clearRebootEscrow();
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -778,7 +798,15 @@
final long origId = Binder.clearCallingIdentity();
int providerErrorCode;
try {
- providerErrorCode = mInjector.getLockSettingsService().armRebootEscrow();
+ LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+ if (lockSettings == null) {
+ Slog.e(TAG, "Failed to get lock settings service, skipping"
+ + " armRebootEscrow");
+ return new RebootPreparationError(
+ RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE,
+ ARM_REBOOT_ERROR_NO_PROVIDER);
+ }
+ providerErrorCode = lockSettings.armRebootEscrow();
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index e1747f7..f918827 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -50,6 +50,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.util.LogUtils;
import java.util.Arrays;
import java.util.Collections;
@@ -305,13 +306,13 @@
handleTeardown();
break;
default:
- Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
+ logWtf("Unknown msg.what: " + msg.what);
}
}
private void handleConfigUpdated(@NonNull VcnConfig config) {
// TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode()
- Slog.v(getLogTag(), "Config updated: config = " + config.hashCode());
+ logDbg("Config updated: old = " + mConfig.hashCode() + "; new = " + config.hashCode());
mConfig = config;
@@ -326,8 +327,7 @@
// connection details may have changed).
if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
if (gatewayConnection == null) {
- Slog.wtf(
- getLogTag(), "Found gatewayConnectionConfig without GatewayConnection");
+ logWtf("Found gatewayConnectionConfig without GatewayConnection");
} else {
gatewayConnection.teardownAsynchronously();
}
@@ -340,6 +340,7 @@
}
private void handleTeardown() {
+ logDbg("Tearing down");
mVcnContext.getVcnNetworkProvider().unregisterListener(mRequestListener);
for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
@@ -350,6 +351,7 @@
}
private void handleSafeModeStatusChanged() {
+ logDbg("VcnGatewayConnection safe mode status changed");
boolean hasSafeModeGatewayConnection = false;
// If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
@@ -365,21 +367,19 @@
hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
if (oldStatus != mCurrentStatus) {
mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
+ logDbg(
+ "Safe mode "
+ + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited"));
}
}
private void handleNetworkRequested(@NonNull NetworkRequest request) {
- Slog.v(getLogTag(), "Received request " + request);
+ logVdbg("Received request " + request);
// If preexisting VcnGatewayConnection(s) satisfy request, return
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
- if (VDBG) {
- Slog.v(
- getLogTag(),
- "Request already satisfied by existing VcnGatewayConnection: "
- + request);
- }
+ logDbg("Request already satisfied by existing VcnGatewayConnection: " + request);
return;
}
}
@@ -389,7 +389,7 @@
for (VcnGatewayConnectionConfig gatewayConnectionConfig :
mConfig.getGatewayConnectionConfigs()) {
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
- Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request);
+ logDbg("Bringing up new VcnGatewayConnection for request " + request);
if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) {
// Skip; this network does not provide any services if mobile data is disabled.
@@ -400,8 +400,9 @@
// pre-existing VcnGatewayConnections that satisfy a given request, but if state
// that affects the satsifying of requests changes, this is theoretically possible.
if (mVcnGatewayConnections.containsKey(gatewayConnectionConfig)) {
- Slog.wtf(getLogTag(), "Attempted to bring up VcnGatewayConnection for config "
- + "with existing VcnGatewayConnection");
+ logWtf(
+ "Attempted to bring up VcnGatewayConnection for config "
+ + "with existing VcnGatewayConnection");
return;
}
@@ -414,8 +415,12 @@
new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig),
mIsMobileDataEnabled);
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
+
+ return;
}
}
+
+ logVdbg("Request could not be fulfilled by VCN: " + request);
}
private Set<Integer> getExposedCapabilitiesForMobileDataState(
@@ -432,7 +437,7 @@
}
private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
- Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
+ logDbg("VcnGatewayConnection quit: " + config);
mVcnGatewayConnections.remove(config);
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
@@ -467,9 +472,7 @@
if (exposedCaps.contains(NET_CAPABILITY_INTERNET)
|| exposedCaps.contains(NET_CAPABILITY_DUN)) {
if (gatewayConnection == null) {
- Slog.wtf(
- getLogTag(),
- "Found gatewayConnectionConfig without GatewayConnection");
+ logWtf("Found gatewayConnectionConfig without" + " GatewayConnection");
} else {
// TODO(b/184868850): Optimize by restarting NetworkAgents without teardown.
gatewayConnection.teardownAsynchronously();
@@ -479,6 +482,8 @@
// Trigger re-evaluation of all requests; mobile data state impacts supported caps.
mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+
+ logDbg("Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled"));
}
}
@@ -507,8 +512,38 @@
return request.canBeSatisfiedBy(builder.build());
}
- private String getLogTag() {
- return TAG + " [" + mSubscriptionGroup.hashCode() + "]";
+ private String getLogPrefix() {
+ return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: ";
+ }
+
+ private void logVdbg(String msg) {
+ if (VDBG) {
+ Slog.v(TAG, getLogPrefix() + msg);
+ }
+ }
+
+ private void logDbg(String msg) {
+ Slog.d(TAG, getLogPrefix() + msg);
+ }
+
+ private void logDbg(String msg, Throwable tr) {
+ Slog.d(TAG, getLogPrefix() + msg, tr);
+ }
+
+ private void logErr(String msg) {
+ Slog.e(TAG, getLogPrefix() + msg);
+ }
+
+ private void logErr(String msg, Throwable tr) {
+ Slog.e(TAG, getLogPrefix() + msg, tr);
+ }
+
+ private void logWtf(String msg) {
+ Slog.wtf(TAG, getLogPrefix() + msg);
+ }
+
+ private void logWtf(String msg, Throwable tr) {
+ Slog.wtf(TAG, getLogPrefix() + msg, tr);
}
/**
@@ -521,6 +556,7 @@
pw.increaseIndent();
pw.println("mCurrentStatus: " + mCurrentStatus);
+ pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled);
pw.println("mVcnGatewayConnections:");
for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 65b947c..5cecff6 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -88,6 +88,7 @@
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.util.LogUtils;
import com.android.server.vcn.util.MtuUtils;
import java.io.IOException;
@@ -701,6 +702,7 @@
* <p>Once torn down, this VcnTunnel CANNOT be started again.
*/
public void teardownAsynchronously() {
+ logDbg("Triggering async teardown");
sendDisconnectRequestedAndAcquireWakelock(
DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */);
@@ -710,6 +712,8 @@
@Override
protected void onQuitting() {
+ logDbg("Quitting VcnGatewayConnection");
+
// No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
if (mTunnelIface != null) {
mTunnelIface.close();
@@ -750,6 +754,10 @@
// TODO(b/180132994): explore safely removing this Thread check
mVcnContext.ensureRunningOnLooperThread();
+ logDbg(
+ "Selected underlying network changed: "
+ + (underlying == null ? null : underlying.network));
+
// TODO(b/179091925): Move the delayed-message handling to BaseState
// If underlying is null, all underlying networks have been lost. Disconnect VCN after a
@@ -774,6 +782,8 @@
if (!mIsQuitting) {
mWakeLock.acquire();
+
+ logVdbg("Wakelock acquired: " + mWakeLock);
}
}
@@ -781,6 +791,8 @@
mVcnContext.ensureRunningOnLooperThread();
mWakeLock.release();
+
+ logVdbg("Wakelock released: " + mWakeLock);
}
/**
@@ -798,8 +810,7 @@
@Override
public void sendMessage(int what) {
- Slog.wtf(
- TAG,
+ logWtf(
"sendMessage should not be used in VcnGatewayConnection. See"
+ " sendMessageAndAcquireWakeLock()");
super.sendMessage(what);
@@ -807,8 +818,7 @@
@Override
public void sendMessage(int what, Object obj) {
- Slog.wtf(
- TAG,
+ logWtf(
"sendMessage should not be used in VcnGatewayConnection. See"
+ " sendMessageAndAcquireWakeLock()");
super.sendMessage(what, obj);
@@ -816,8 +826,7 @@
@Override
public void sendMessage(int what, int arg1) {
- Slog.wtf(
- TAG,
+ logWtf(
"sendMessage should not be used in VcnGatewayConnection. See"
+ " sendMessageAndAcquireWakeLock()");
super.sendMessage(what, arg1);
@@ -825,8 +834,7 @@
@Override
public void sendMessage(int what, int arg1, int arg2) {
- Slog.wtf(
- TAG,
+ logWtf(
"sendMessage should not be used in VcnGatewayConnection. See"
+ " sendMessageAndAcquireWakeLock()");
super.sendMessage(what, arg1, arg2);
@@ -834,8 +842,7 @@
@Override
public void sendMessage(int what, int arg1, int arg2, Object obj) {
- Slog.wtf(
- TAG,
+ logWtf(
"sendMessage should not be used in VcnGatewayConnection. See"
+ " sendMessageAndAcquireWakeLock()");
super.sendMessage(what, arg1, arg2, obj);
@@ -843,8 +850,7 @@
@Override
public void sendMessage(Message msg) {
- Slog.wtf(
- TAG,
+ logWtf(
"sendMessage should not be used in VcnGatewayConnection. See"
+ " sendMessageAndAcquireWakeLock()");
super.sendMessage(msg);
@@ -935,10 +941,14 @@
}
private void setTeardownTimeoutAlarm() {
+ logVdbg("Setting teardown timeout alarm; mCurrentToken: " + mCurrentToken);
+
// Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
// either case, there is nothing to cancel.
if (mTeardownTimeoutAlarm != null) {
- Slog.wtf(TAG, "mTeardownTimeoutAlarm should be null before being set");
+ logWtf(
+ "mTeardownTimeoutAlarm should be null before being set; mCurrentToken: "
+ + mCurrentToken);
}
final Message delayedMessage = obtainMessage(EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken);
@@ -950,6 +960,8 @@
}
private void cancelTeardownTimeoutAlarm() {
+ logVdbg("Cancelling teardown timeout alarm; mCurrentToken: " + mCurrentToken);
+
if (mTeardownTimeoutAlarm != null) {
mTeardownTimeoutAlarm.cancel();
mTeardownTimeoutAlarm = null;
@@ -960,6 +972,11 @@
}
private void setDisconnectRequestAlarm() {
+ logVdbg(
+ "Setting alarm to disconnect due to underlying network loss;"
+ + " mCurrentToken: "
+ + mCurrentToken);
+
// Only schedule a NEW alarm if none is already set.
if (mDisconnectRequestAlarm != null) {
return;
@@ -980,6 +997,11 @@
}
private void cancelDisconnectRequestAlarm() {
+ logVdbg(
+ "Cancelling alarm to disconnect due to underlying network loss;"
+ + " mCurrentToken: "
+ + mCurrentToken);
+
if (mDisconnectRequestAlarm != null) {
mDisconnectRequestAlarm.cancel();
mDisconnectRequestAlarm = null;
@@ -993,10 +1015,14 @@
}
private void setRetryTimeoutAlarm(long delay) {
+ logVdbg("Setting retry alarm; mCurrentToken: " + mCurrentToken);
+
// Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
// either case, there is nothing to cancel.
if (mRetryTimeoutAlarm != null) {
- Slog.wtf(TAG, "mRetryTimeoutAlarm should be null before being set");
+ logWtf(
+ "mRetryTimeoutAlarm should be null before being set; mCurrentToken: "
+ + mCurrentToken);
}
final Message delayedMessage = obtainMessage(EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken);
@@ -1004,6 +1030,8 @@
}
private void cancelRetryTimeoutAlarm() {
+ logVdbg("Cancel retry alarm; mCurrentToken: " + mCurrentToken);
+
if (mRetryTimeoutAlarm != null) {
mRetryTimeoutAlarm.cancel();
mRetryTimeoutAlarm = null;
@@ -1014,6 +1042,8 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
void setSafeModeAlarm() {
+ logVdbg("Setting safe mode alarm; mCurrentToken: " + mCurrentToken);
+
// Only schedule a NEW alarm if none is already set.
if (mSafeModeTimeoutAlarm != null) {
return;
@@ -1028,6 +1058,8 @@
}
private void cancelSafeModeAlarm() {
+ logVdbg("Cancel safe mode alarm; mCurrentToken: " + mCurrentToken);
+
if (mSafeModeTimeoutAlarm != null) {
mSafeModeTimeoutAlarm.cancel();
mSafeModeTimeoutAlarm = null;
@@ -1092,6 +1124,14 @@
+ exception.getMessage();
}
+ logDbg(
+ "Encountered error; code="
+ + errorCode
+ + ", exceptionClass="
+ + exceptionClass
+ + ", exceptionMessage="
+ + exceptionMessage);
+
mGatewayStatusCallback.onGatewayConnectionError(
mConnectionConfig.getGatewayConnectionName(),
errorCode,
@@ -1137,7 +1177,7 @@
try {
enterState();
} catch (Exception e) {
- Slog.wtf(TAG, "Uncaught exception", e);
+ logWtf("Uncaught exception", e);
sendDisconnectRequestedAndAcquireWakelock(
DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
}
@@ -1169,14 +1209,14 @@
public final boolean processMessage(Message msg) {
final int token = msg.arg1;
if (!isValidToken(token)) {
- Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what);
+ logDbg("Message called with obsolete token: " + token + "; what: " + msg.what);
return HANDLED;
}
try {
processStateMsg(msg);
} catch (Exception e) {
- Slog.wtf(TAG, "Uncaught exception", e);
+ logWtf("Uncaught exception", e);
sendDisconnectRequestedAndAcquireWakelock(
DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
}
@@ -1194,7 +1234,7 @@
try {
exitState();
} catch (Exception e) {
- Slog.wtf(TAG, "Uncaught exception", e);
+ logWtf("Uncaught exception", e);
sendDisconnectRequestedAndAcquireWakelock(
DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
}
@@ -1234,7 +1274,7 @@
protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) {
// TODO(b/180526152): notify VcnStatusCallback for Network loss
- Slog.v(TAG, "Tearing down. Cause: " + info.reason);
+ logDbg("Tearing down. Cause: " + info.reason);
mIsQuitting = info.shouldQuit;
teardownNetwork();
@@ -1250,6 +1290,7 @@
protected void handleSafeModeTimeoutExceeded() {
mSafeModeTimeoutAlarm = null;
+ logDbg("Entering safe mode after timeout exceeded");
// Connectivity for this GatewayConnection is broken; tear down the Network.
teardownNetwork();
@@ -1258,13 +1299,15 @@
}
protected void logUnexpectedEvent(int what) {
- Slog.d(TAG, String.format(
- "Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
+ logDbg(
+ "Unexpected event code "
+ + what
+ + " in state "
+ + this.getClass().getSimpleName());
}
protected void logWtfUnknownEvent(int what) {
- Slog.wtf(TAG, String.format(
- "Unknown event code %d in state %s", what, this.getClass().getSimpleName()));
+ logWtf("Unknown event code " + what + " in state " + this.getClass().getSimpleName());
}
}
@@ -1281,7 +1324,7 @@
}
if (mIkeSession != null || mNetworkAgent != null) {
- Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
+ logWtf("Active IKE Session or NetworkAgent in DisconnectedState");
}
cancelSafeModeAlarm();
@@ -1349,7 +1392,7 @@
@Override
protected void enterState() throws Exception {
if (mIkeSession == null) {
- Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state.");
+ logWtf("IKE session was already closed when entering Disconnecting state.");
sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, mCurrentToken);
return;
}
@@ -1436,7 +1479,7 @@
@Override
protected void enterState() {
if (mIkeSession != null) {
- Slog.wtf(TAG, "ConnectingState entered with active session");
+ logWtf("ConnectingState entered with active session");
// Attempt to recover.
mIkeSession.kill();
@@ -1455,7 +1498,7 @@
if (oldUnderlying == null) {
// This should never happen, but if it does, there's likely a nasty bug.
- Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?");
+ logWtf("Old underlying network was null in connected state. Bug?");
}
// If new underlying is null, all underlying networks have been lost; disconnect
@@ -1550,11 +1593,11 @@
// new NetworkAgent replaces an old one before the unwanted() call
// is processed.
if (mNetworkAgent != agentRef) {
- Slog.d(TAG, "unwanted() called on stale NetworkAgent");
+ logDbg("unwanted() called on stale NetworkAgent");
return;
}
- Slog.d(TAG, "NetworkAgent was unwanted");
+ logDbg("NetworkAgent was unwanted");
teardownAsynchronously();
} /* networkUnwantedCallback */,
(status) -> {
@@ -1568,8 +1611,7 @@
setSafeModeAlarm();
break;
default:
- Slog.wtf(
- TAG,
+ logWtf(
"Unknown validation status "
+ status
+ "; ignoring");
@@ -1602,13 +1644,26 @@
@NonNull Network underlyingNetwork,
@NonNull IpSecTransform transform,
int direction) {
+ if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) {
+ Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction);
+ }
+
try {
tunnelIface.setUnderlyingNetwork(underlyingNetwork);
// Transforms do not need to be persisted; the IkeSession will keep them alive
mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
+
+ // For inbound transforms, additionally allow forwarded traffic to bridge to DUN (as
+ // needed)
+ final Set<Integer> exposedCaps = mConnectionConfig.getAllExposedCapabilities();
+ if (direction == IpSecManager.DIRECTION_IN
+ && exposedCaps.contains(NET_CAPABILITY_DUN)) {
+ mIpSecManager.applyTunnelModeTransform(
+ tunnelIface, IpSecManager.DIRECTION_FWD, transform);
+ }
} catch (IOException e) {
- Slog.d(TAG, "Transform application failed for network " + token, e);
+ logDbg("Transform application failed for network " + token, e);
sessionLost(token, e);
}
}
@@ -1642,7 +1697,7 @@
tunnelIface.removeAddress(address.getAddress(), address.getPrefixLength());
}
} catch (IOException e) {
- Slog.d(TAG, "Adding address to tunnel failed for token " + token, e);
+ logDbg("Adding address to tunnel failed for token " + token, e);
sessionLost(token, e);
}
}
@@ -1722,6 +1777,8 @@
}
private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) {
+ logDbg("Migration completed: " + mUnderlying.network);
+
applyTransform(
mCurrentToken,
mTunnelIface,
@@ -1744,6 +1801,8 @@
mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
if (mUnderlying == null) {
+ logDbg("Underlying network lost");
+
// Ignored for now; a new network may be coming up. If none does, the delayed
// NETWORK_LOST disconnect will be fired, and tear down the session + network.
return;
@@ -1752,7 +1811,7 @@
// mUnderlying assumed non-null, given check above.
// If network changed, migrate. Otherwise, update any existing networkAgent.
if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) {
- Slog.v(TAG, "Migrating to new network: " + mUnderlying.network);
+ logDbg("Migrating to new network: " + mUnderlying.network);
mIkeSession.setNetwork(mUnderlying.network);
} else {
// oldUnderlying is non-null & underlying network itself has not changed
@@ -1803,7 +1862,7 @@
mFailedAttempts++;
if (mUnderlying == null) {
- Slog.wtf(TAG, "Underlying network was null in retry state");
+ logWtf("Underlying network was null in retry state");
transitionTo(mDisconnectedState);
} else {
// Safe to blindly set up, as it is cancelled and cleared on exiting this state
@@ -1973,25 +2032,25 @@
@Override
public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
- Slog.v(TAG, "IkeOpened for token " + mToken);
+ logDbg("IkeOpened for token " + mToken);
// Nothing to do here.
}
@Override
public void onClosed() {
- Slog.v(TAG, "IkeClosed for token " + mToken);
+ logDbg("IkeClosed for token " + mToken);
sessionClosed(mToken, null);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
- Slog.v(TAG, "IkeClosedExceptionally for token " + mToken, exception);
+ logDbg("IkeClosedExceptionally for token " + mToken, exception);
sessionClosed(mToken, exception);
}
@Override
public void onError(@NonNull IkeProtocolException exception) {
- Slog.v(TAG, "IkeError for token " + mToken, exception);
+ logDbg("IkeError for token " + mToken, exception);
// Non-fatal, log and continue.
}
}
@@ -2008,7 +2067,7 @@
/** Internal proxy method for injecting of mocked ChildSessionConfiguration */
@VisibleForTesting(visibility = Visibility.PRIVATE)
void onOpened(@NonNull VcnChildSessionConfiguration childConfig) {
- Slog.v(TAG, "ChildOpened for token " + mToken);
+ logDbg("ChildOpened for token " + mToken);
childOpened(mToken, childConfig);
}
@@ -2019,19 +2078,19 @@
@Override
public void onClosed() {
- Slog.v(TAG, "ChildClosed for token " + mToken);
+ logDbg("ChildClosed for token " + mToken);
sessionLost(mToken, null);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
- Slog.v(TAG, "ChildClosedExceptionally for token " + mToken, exception);
+ logDbg("ChildClosedExceptionally for token " + mToken, exception);
sessionLost(mToken, exception);
}
@Override
public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) {
- Slog.v(TAG, "ChildTransformCreated; Direction: " + direction + "; token " + mToken);
+ logDbg("ChildTransformCreated; Direction: " + direction + "; token " + mToken);
childTransformCreated(mToken, transform, direction);
}
@@ -2039,7 +2098,7 @@
public void onIpSecTransformsMigrated(
@NonNull IpSecTransform inIpSecTransform,
@NonNull IpSecTransform outIpSecTransform) {
- Slog.v(TAG, "ChildTransformsMigrated; token " + mToken);
+ logDbg("ChildTransformsMigrated; token " + mToken);
migrationCompleted(mToken, inIpSecTransform, outIpSecTransform);
}
@@ -2047,10 +2106,48 @@
public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) {
// Nothing to be done; no references to the IpSecTransform are held, and this transform
// will be closed by the IKE library.
- Slog.v(TAG, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
+ logDbg("ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
}
}
+ private String getLogPrefix() {
+ return "["
+ + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup)
+ + "-"
+ + mConnectionConfig.getGatewayConnectionName()
+ + "]: ";
+ }
+
+ private void logVdbg(String msg) {
+ if (VDBG) {
+ Slog.v(TAG, getLogPrefix() + msg);
+ }
+ }
+
+ private void logDbg(String msg) {
+ Slog.d(TAG, getLogPrefix() + msg);
+ }
+
+ private void logDbg(String msg, Throwable tr) {
+ Slog.d(TAG, getLogPrefix() + msg, tr);
+ }
+
+ private void logErr(String msg) {
+ Slog.e(TAG, getLogPrefix() + msg);
+ }
+
+ private void logErr(String msg, Throwable tr) {
+ Slog.e(TAG, getLogPrefix() + msg, tr);
+ }
+
+ private void logWtf(String msg) {
+ Slog.wtf(TAG, getLogPrefix() + msg);
+ }
+
+ private void logWtf(String msg, Throwable tr) {
+ Slog.wtf(TAG, getLogPrefix() + msg, tr);
+ }
+
/**
* Dumps the state of this VcnGatewayConnection for logging and debugging purposes.
*
diff --git a/services/core/java/com/android/server/vcn/util/LogUtils.java b/services/core/java/com/android/server/vcn/util/LogUtils.java
new file mode 100644
index 0000000..93728ce
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/util/LogUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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 com.android.server.vcn.util;
+
+import android.annotation.Nullable;
+import android.os.ParcelUuid;
+
+import com.android.internal.util.HexDump;
+
+/** @hide */
+public class LogUtils {
+ /**
+ * Returns the hash of the subscription group in hexadecimal format.
+ *
+ * @return the hexadecimal encoded string if uuid was non-null, else {@code null}
+ */
+ @Nullable
+ public static String getHashedSubscriptionGroup(@Nullable ParcelUuid uuid) {
+ if (uuid == null) {
+ return null;
+ }
+
+ return HexDump.toHexString(uuid.hashCode());
+ }
+}
diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java
index 2983e63..a63ee46 100644
--- a/telecomm/java/android/telecom/CallerInfo.java
+++ b/telecomm/java/android/telecom/CallerInfo.java
@@ -406,8 +406,7 @@
// Change the callerInfo number ONLY if it is an emergency number
// or if it is the voicemail number. If it is either, take a
// shortcut and skip the query.
- TelephonyManager tm = context.getSystemService(TelephonyManager.class);
- if (tm.isEmergencyNumber(number)) {
+ if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
return new CallerInfo().markAsEmergency(context);
} else if (PhoneNumberUtils.isVoiceMailNumber(null, subId, number)) {
return new CallerInfo().markAsVoiceMail(context, subId);
diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
index a9e1a8f..bf49f3c 100644
--- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
+++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java
@@ -483,7 +483,16 @@
// check to see if these are recognized numbers, and use shortcuts if we can.
TelephonyManager tm = context.getSystemService(TelephonyManager.class);
- if (tm.isEmergencyNumber(number)) {
+ boolean isEmergencyNumber = false;
+ try {
+ isEmergencyNumber = tm.isEmergencyNumber(number);
+ } catch (IllegalStateException ise) {
+ // Ignore the exception that Telephony is not up. Use PhoneNumberUtils API now.
+ // Ideally the PhoneNumberUtils API needs to be removed once the
+ // telphony service not up issue can be fixed (b/187412989)
+ isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(context, number);
+ }
+ if (isEmergencyNumber) {
cw.event = EVENT_EMERGENCY_NUMBER;
} else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) {
cw.event = EVENT_VOICEMAIL_NUMBER;
diff --git a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
index 0b47547..e9b7d95 100644
--- a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
+++ b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.telephony;
+package com.android.internal.telephony;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index b8b60da..16614c8 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -40,7 +40,6 @@
import android.os.UserHandle;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
-import android.telephony.PackageChangeReceiver;
import android.telephony.TelephonyManager;
import android.util.Log;
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index d1a893f..7403327 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -713,15 +713,8 @@
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VT_AVAILABLE_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
* @see #isAvailable(int, int)
- *
- * @param imsRegTech The IMS registration technology, can be one of the following:
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
- * @param capability The IMS MmTel capability to query, can be one of the following:
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
+ * @param imsRegTech The IMS registration technology.
+ * @param capability The IMS MmTel capability to query.
* @return {@code true} if the MmTel IMS capability is capable for this subscription, false
* otherwise.
* @hide
@@ -748,14 +741,8 @@
*
* @see #isCapable(int, int)
*
- * @param imsRegTech The IMS registration technology, can be one of the following:
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
- * @param capability The IMS MmTel capability to query, can be one of the following:
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
+ * @param imsRegTech The IMS registration technology.
+ * @param capability The IMS MmTel capability to query.
* @return {@code true} if the MmTel IMS capability is available for this subscription, false
* otherwise.
* @hide
diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java
index 8a31211..6867c86 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.java
+++ b/telephony/java/android/telephony/ims/RcsConfig.java
@@ -22,10 +22,10 @@
import android.content.Context;
import android.database.Cursor;
import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.provider.Telephony.SimInfo;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.telephony.Rlog;
@@ -36,7 +36,9 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -44,23 +46,138 @@
* RCS config data and methods to process the config
* @hide
*/
-public final class RcsConfig implements Parcelable {
+public final class RcsConfig {
private static final String LOG_TAG = "RcsConfig";
private static final boolean DBG = Build.IS_ENG;
- // Tag for Rcs Volte single registration defined in RCC.07 A.1.6.2
- private static final String TAG_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";
+ // Tag and attribute defined in RCC.07 A.2
+ private static final String TAG_CHARACTERISTIC = "characteristic";
+ private static final String TAG_PARM = "parm";
+ private static final String ATTRIBUTE_TYPE = "type";
+ private static final String ATTRIBUTE_NAME = "name";
+ private static final String ATTRIBUTE_VALUE = "value";
+ // Keyword for Rcs Volte single registration defined in RCC.07 A.1.6.2
+ private static final String PARM_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";
- private final HashMap<String, String> mValues = new HashMap<>();
+ /**
+ * Characteristic of the RCS provisioning config
+ */
+ public static class Characteristic {
+ private String mType;
+ private final Map<String, String> mParms = new ArrayMap<>();
+ private final Set<Characteristic> mSubs = new ArraySet<>();
+ private final Characteristic mParent;
- private RcsConfig(HashMap<String, String> values) {
- mValues.putAll(values);
+ private Characteristic(String type, Characteristic parent) {
+ mType = type;
+ mParent = parent;
+ }
+
+ private String getType() {
+ return mType;
+ }
+
+ private Map<String, String> getParms() {
+ return mParms;
+ }
+
+ private Set<Characteristic> getSubs() {
+ return mSubs;
+ }
+
+ private Characteristic getParent() {
+ return mParent;
+ }
+
+ private Characteristic getSubByType(String type) {
+ if (TextUtils.equals(mType, type)) {
+ return this;
+ }
+ Characteristic result = null;
+ for (Characteristic sub : mSubs) {
+ result = sub.getSubByType(type);
+ if (result != null) {
+ break;
+ }
+ }
+ return result;
+ }
+
+ private boolean hasSubByType(String type) {
+ return getSubByType(type) != null;
+ }
+
+ private String getParmValue(String name) {
+ String value = mParms.get(name);
+ if (value == null) {
+ for (Characteristic sub : mSubs) {
+ value = sub.getParmValue(name);
+ if (value != null) {
+ break;
+ }
+ }
+ }
+ return value;
+ }
+
+ boolean hasParm(String name) {
+ if (mParms.containsKey(name)) {
+ return true;
+ }
+
+ for (Characteristic sub : mSubs) {
+ if (sub.hasParm(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[" + mType + "]: ");
+ if (DBG) {
+ sb.append(mParms);
+ }
+ for (Characteristic sub : mSubs) {
+ sb.append("\n");
+ sb.append(sub.toString().replace("\n", "\n\t"));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Characteristic)) {
+ return false;
+ }
+
+ Characteristic o = (Characteristic) obj;
+
+ return TextUtils.equals(mType, o.mType) && mParms.equals(o.mParms)
+ && mSubs.equals(o.mSubs);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mType, mParms, mSubs);
+ }
}
+ private final Characteristic mRoot;
+ private Characteristic mCurrent;
+ private final byte[] mData;
+
public RcsConfig(byte[] data) throws IllegalArgumentException {
if (data == null || data.length == 0) {
throw new IllegalArgumentException("Empty data");
}
+ mRoot = new Characteristic(null, null);
+ mCurrent = mRoot;
+ mData = data;
+ Characteristic current = mRoot;
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
@@ -69,16 +186,51 @@
xpp.setInput(inputStream, null);
int eventType = xpp.getEventType();
String tag = null;
- while (eventType != XmlPullParser.END_DOCUMENT) {
+ while (eventType != XmlPullParser.END_DOCUMENT && current != null) {
if (eventType == XmlPullParser.START_TAG) {
- tag = xpp.getName().trim();
- } else if (eventType == XmlPullParser.END_TAG) {
- tag = null;
- } else if (eventType == XmlPullParser.TEXT) {
- String value = xpp.getText().trim();
- if (!TextUtils.isEmpty(tag) && !TextUtils.isEmpty(value)) {
- mValues.put(tag, value);
+ tag = xpp.getName().trim().toLowerCase();
+ if (TAG_CHARACTERISTIC.equals(tag)) {
+ int count = xpp.getAttributeCount();
+ String type = null;
+ if (count > 0) {
+ for (int i = 0; i < count; i++) {
+ String name = xpp.getAttributeName(i).trim().toLowerCase();
+ if (ATTRIBUTE_TYPE.equals(name)) {
+ type = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
+ name).trim().toLowerCase();
+ break;
+ }
+ }
+ }
+ Characteristic next = new Characteristic(type, current);
+ current.getSubs().add(next);
+ current = next;
+ } else if (TAG_PARM.equals(tag)) {
+ int count = xpp.getAttributeCount();
+ String key = null;
+ String value = null;
+ if (count > 1) {
+ for (int i = 0; i < count; i++) {
+ String name = xpp.getAttributeName(i).trim().toLowerCase();
+ if (ATTRIBUTE_NAME.equals(name)) {
+ key = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
+ name).trim().toLowerCase();
+ } else if (ATTRIBUTE_VALUE.equals(name)) {
+ value = xpp.getAttributeValue(xpp.getAttributeNamespace(i),
+ name).trim();
+ }
+ }
+ }
+ if (key != null && value != null) {
+ current.getParms().put(key, value);
+ }
}
+ } else if (eventType == XmlPullParser.END_TAG) {
+ tag = xpp.getName().trim().toLowerCase();
+ if (TAG_CHARACTERISTIC.equals(tag)) {
+ current = current.getParent();
+ }
+ tag = null;
}
eventType = xpp.next();
}
@@ -102,7 +254,8 @@
* @return Returns the config value if it exists, or defaultVal.
*/
public @Nullable String getString(@NonNull String tag, @Nullable String defaultVal) {
- return mValues.containsKey(tag) ? mValues.get(tag) : defaultVal;
+ String value = mCurrent.getParmValue(tag.trim().toLowerCase());
+ return value != null ? value : defaultVal;
}
/**
@@ -115,7 +268,7 @@
*/
public int getInteger(@NonNull String tag, int defaultVal) {
try {
- return Integer.parseInt(mValues.get(tag));
+ return Integer.parseInt(getString(tag, null));
} catch (NumberFormatException e) {
logd("error to getInteger for " + tag + " due to " + e);
}
@@ -131,10 +284,8 @@
* @return Returns the config value if it exists, or defaultVal.
*/
public boolean getBoolean(@NonNull String tag, boolean defaultVal) {
- if (!mValues.containsKey(tag)) {
- return defaultVal;
- }
- return Boolean.parseBoolean(mValues.get(tag));
+ String value = getString(tag, null);
+ return value != null ? Boolean.parseBoolean(value) : defaultVal;
}
/**
@@ -145,15 +296,70 @@
* @return Returns true if it exists, or false.
*/
public boolean hasConfig(@NonNull String tag) {
- return mValues.containsKey(tag);
+ return mCurrent.hasParm(tag.trim().toLowerCase());
+ }
+
+ /**
+ * Return the Characteristic with the given type
+ */
+ public @Nullable Characteristic getCharacteristic(@NonNull String type) {
+ return mCurrent.getSubByType(type.trim().toLowerCase());
+ }
+
+ /**
+ * Check whether the Characteristic with the given type exists
+ */
+ public boolean hasCharacteristic(@NonNull String type) {
+ return mCurrent.getSubByType(type.trim().toLowerCase()) != null;
+ }
+
+ /**
+ * Set current Characteristic to given Characteristic
+ */
+ public void setCurrentCharacteristic(@NonNull Characteristic current) {
+ if (current != null) {
+ mCurrent = current;
+ }
+ }
+
+ /**
+ * Move current Characteristic to parent layer
+ */
+ public boolean moveToParent() {
+ if (mCurrent.getParent() == null) {
+ return false;
+ }
+ mCurrent = mCurrent.getParent();
+ return true;
+ }
+
+ /**
+ * Move current Characteristic to the root
+ */
+ public void moveToRoot() {
+ mCurrent = mRoot;
+ }
+
+ /**
+ * Return root Characteristic
+ */
+ public @NonNull Characteristic getRoot() {
+ return mRoot;
+ }
+
+ /**
+ * Return current Characteristic
+ */
+ public @NonNull Characteristic getCurrentCharacteristic() {
+ return mCurrent;
}
/**
* Check whether Rcs Volte single registration is supported by the config.
*/
public boolean isRcsVolteSingleRegistrationSupported() {
- return getBoolean(TAG_SINGLE_REGISTRATION, false)
- || getInteger(TAG_SINGLE_REGISTRATION, 0) != 0;
+ return getBoolean(PARM_SINGLE_REGISTRATION, false)
+ || getInteger(PARM_SINGLE_REGISTRATION, 0) != 0;
}
@Override
@@ -161,12 +367,10 @@
final StringBuilder sb = new StringBuilder();
sb.append("[RCS Config]");
if (DBG) {
- mValues.forEach((t, v) -> {
- sb.append("\n");
- sb.append(t);
- sb.append(" : ");
- sb.append(v);
- });
+ sb.append("=== Root ===\n");
+ sb.append(mRoot);
+ sb.append("=== Current ===\n");
+ sb.append(mCurrent);
}
return sb.toString();
}
@@ -179,12 +383,12 @@
RcsConfig other = (RcsConfig) obj;
- return mValues.equals(other.mValues);
+ return mRoot.equals(other.mRoot) && mCurrent.equals(other.mCurrent);
}
@Override
public int hashCode() {
- return mValues.hashCode();
+ return Objects.hash(mRoot, mCurrent);
}
/**
@@ -275,38 +479,6 @@
return isCompressed ? data : decompressGzip(data);
}
- /**
- * {@link Parcelable#writeToParcel}
- */
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeMap(mValues);
- }
-
- /**
- * {@link Parcelable.Creator}
- *
- */
- public static final @NonNull Parcelable.Creator<RcsConfig>
- CREATOR = new Creator<RcsConfig>() {
- @Override
- public RcsConfig createFromParcel(Parcel in) {
- HashMap<String, String> values = in.readHashMap(null);
- return values == null ? null : new RcsConfig(values);
- }
-
- @Override
- public RcsConfig[] newArray(int size) {
- return new RcsConfig[size];
- }
- };
-
- /**
- * {@link Parcelable#describeContents}
- */
- public int describeContents() {
- return 0;
- }
-
private static void logd(String msg) {
Rlog.d(LOG_TAG, msg);
}
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index c49121f..4713b76 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -82,6 +82,8 @@
AccessNetworkConstants.TRANSPORT_TYPE_INVALID);
put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ put(ImsRegistrationImplBase.REGISTRATION_TECH_NR,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
}};
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 23032f0..35324a3c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -56,7 +56,8 @@
@IntDef(value = {
REGISTRATION_TECH_NONE,
REGISTRATION_TECH_LTE,
- REGISTRATION_TECH_IWLAN
+ REGISTRATION_TECH_IWLAN,
+ REGISTRATION_TECH_NR
})
@Retention(RetentionPolicy.SOURCE)
public @interface ImsRegistrationTech {}
@@ -65,13 +66,18 @@
*/
public static final int REGISTRATION_TECH_NONE = -1;
/**
- * IMS is registered to IMS via LTE.
+ * This ImsService is registered to IMS via LTE.
*/
public static final int REGISTRATION_TECH_LTE = 0;
/**
- * IMS is registered to IMS via IWLAN.
+ * This ImsService is registered to IMS via IWLAN.
*/
public static final int REGISTRATION_TECH_IWLAN = 1;
+ // REGISTRATION_TECH = 2 omitted purposefully.
+ /**
+ * This ImsService is registered to IMS via NR.
+ */
+ public static final int REGISTRATION_TECH_NR = 3;
// Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current
// state.
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 9bd639b..b58aa11 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -32,7 +32,7 @@
java_sdk_library {
name: "android.test.base",
- srcs: ["src/**/*.java"],
+ srcs: [":android-test-base-sources"],
errorprone: {
javacflags: ["-Xep:DepAnn:ERROR"],
@@ -66,7 +66,7 @@
name: "android.test.base_static",
installable: false,
- srcs: ["src/**/*.java"],
+ srcs: [":android-test-base-sources"],
errorprone: {
javacflags: ["-Xep:DepAnn:ERROR"],
@@ -114,6 +114,12 @@
],
}
+filegroup {
+ name: "android-test-base-sources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+}
+
// Make the current.txt available for use by the cts/tests/signature tests.
// ========================================================================
filegroup {
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index b83bce6..107292c 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -29,7 +29,7 @@
name: "android.test.mock",
srcs: [
- "src/**/*.java",
+ ":android-test-mock-sources",
// Note: Below are NOT APIs of this library. We only take APIs under
// the android.test.mock package. They however provide private APIs that
// android.test.mock APIs references to.
@@ -61,3 +61,9 @@
"api/current.txt",
],
}
+
+filegroup {
+ name: "android-test-mock-sources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+}
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index fe007e39..c380ae3 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -29,7 +29,7 @@
java_sdk_library {
name: "android.test.runner",
- srcs: ["src/**/*.java"],
+ srcs: [":android-test-runner-sources"],
errorprone: {
javacflags: ["-Xep:DepAnn:ERROR"],
@@ -76,7 +76,7 @@
java_library_static {
name: "repackaged.android.test.runner",
- srcs: ["src/**/*.java"],
+ srcs: [":android-test-runner-sources"],
exclude_srcs: [
"src/android/test/ActivityUnitTestCase.java",
"src/android/test/ApplicationTestCase.java",
@@ -108,3 +108,9 @@
"api/current.txt",
],
}
+
+filegroup {
+ name: "android-test-runner-sources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 32c95f1..cf2c9c7 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -16,9 +16,14 @@
package com.android.server;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.INetd.IF_STATE_DOWN;
import static android.net.INetd.IF_STATE_UP;
+import static android.net.IpSecManager.DIRECTION_FWD;
+import static android.net.IpSecManager.DIRECTION_IN;
+import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
@@ -56,6 +61,7 @@
import android.os.ParcelFileDescriptor;
import android.system.Os;
import android.test.mock.MockContext;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
@@ -71,6 +77,7 @@
import java.net.Socket;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Set;
/** Unit tests for {@link IpSecService}. */
@SmallTest
@@ -119,7 +126,18 @@
AppOpsManager mMockAppOps = mock(AppOpsManager.class);
ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);
- MockContext mMockContext = new MockContext() {
+ TestContext mTestContext = new TestContext();
+
+ private class TestContext extends MockContext {
+ private Set<String> mAllowedPermissions = new ArraySet<>(Arrays.asList(
+ android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
+ android.Manifest.permission.NETWORK_STACK,
+ PERMISSION_MAINLINE_NETWORK_STACK));
+
+ private void setAllowedPermissions(String... permissions) {
+ mAllowedPermissions = new ArraySet<>(permissions);
+ }
+
@Override
public Object getSystemService(String name) {
switch(name) {
@@ -147,20 +165,22 @@
@Override
public void enforceCallingOrSelfPermission(String permission, String message) {
- if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
+ if (mAllowedPermissions.contains(permission)) {
return;
+ } else {
+ throw new SecurityException("Unavailable permission requested");
}
- throw new SecurityException("Unavailable permission requested");
}
@Override
public int checkCallingOrSelfPermission(String permission) {
- if (android.Manifest.permission.NETWORK_STACK.equals(permission)) {
+ if (mAllowedPermissions.contains(permission)) {
return PERMISSION_GRANTED;
+ } else {
+ return PERMISSION_DENIED;
}
- throw new UnsupportedOperationException();
}
- };
+ }
INetd mMockNetd;
PackageManager mMockPkgMgr;
@@ -194,7 +214,7 @@
mMockNetd = mock(INetd.class);
mMockPkgMgr = mock(PackageManager.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
+ mIpSecService = new IpSecService(mTestContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
@@ -664,6 +684,21 @@
assertNotNull(createTunnelResp);
assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
+ for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT, DIRECTION_FWD}) {
+ for (int selAddrFamily : ADDRESS_FAMILIES) {
+ verify(mMockNetd).ipSecAddSecurityPolicy(
+ eq(mUid),
+ eq(selAddrFamily),
+ eq(direction),
+ anyString(),
+ anyString(),
+ eq(0),
+ anyInt(), // iKey/oKey
+ anyInt(), // mask
+ eq(createTunnelResp.resourceId));
+ }
+ }
+
return createTunnelResp;
}
@@ -798,16 +833,51 @@
}
@Test
- public void testApplyTunnelModeTransform() throws Exception {
- verifyApplyTunnelModeTransformCommon(false);
+ public void testApplyTunnelModeTransformOutbound() throws Exception {
+ verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
}
@Test
- public void testApplyTunnelModeTransformReleasedSpi() throws Exception {
- verifyApplyTunnelModeTransformCommon(true);
+ public void testApplyTunnelModeTransformOutboundNonNetworkStack() throws Exception {
+ mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
+ verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
}
- public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply) throws Exception {
+ @Test
+ public void testApplyTunnelModeTransformOutboundReleasedSpi() throws Exception {
+ verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_OUT);
+ }
+
+ @Test
+ public void testApplyTunnelModeTransformInbound() throws Exception {
+ verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
+ }
+
+ @Test
+ public void testApplyTunnelModeTransformInboundNonNetworkStack() throws Exception {
+ mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
+ verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
+ }
+
+ @Test
+ public void testApplyTunnelModeTransformForward() throws Exception {
+ verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
+ }
+
+ @Test
+ public void testApplyTunnelModeTransformForwardNonNetworkStack() throws Exception {
+ mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
+
+ try {
+ verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
+ fail("Expected security exception due to use of forward policies without NETWORK_STACK"
+ + " or MAINLINE_NETWORK_STACK permission");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction)
+ throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
@@ -825,17 +895,17 @@
int transformResourceId = createTransformResp.resourceId;
int tunnelResourceId = createTunnelResp.resourceId;
mIpSecService.applyTunnelModeTransform(
- tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
+ tunnelResourceId, direction, transformResourceId, BLESSED_PACKAGE);
for (int selAddrFamily : ADDRESS_FAMILIES) {
verify(mMockNetd)
.ipSecUpdateSecurityPolicy(
eq(mUid),
eq(selAddrFamily),
- eq(IpSecManager.DIRECTION_OUT),
+ eq(direction),
anyString(),
anyString(),
- eq(TEST_SPI),
+ eq(direction == DIRECTION_OUT ? TEST_SPI : 0),
anyInt(), // iKey/oKey
anyInt(), // mask
eq(tunnelResourceId));
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index eedaac4..39f7386 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -16,8 +16,11 @@
package com.android.server.vcn;
+import static android.net.IpSecManager.DIRECTION_FWD;
import static android.net.IpSecManager.DIRECTION_IN;
import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
@@ -54,6 +57,8 @@
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.net.vcn.VcnManager.VcnErrorCode;
import androidx.test.filters.SmallTest;
@@ -143,8 +148,9 @@
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
}
- @Test
- public void testCreatedTransformsAreApplied() throws Exception {
+ private void verifyVcnTransformsApplied(
+ VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform)
+ throws Exception {
for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction);
mTestLooper.dispatchAll();
@@ -154,7 +160,40 @@
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
}
- assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ verify(mIpSecSvc, expectForwardTransform ? times(1) : never())
+ .applyTunnelModeTransform(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(DIRECTION_FWD), anyInt(), any());
+
+ assertEquals(vcnGatewayConnection.mConnectedState, vcnGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testCreatedTransformsAreApplied() throws Exception {
+ verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */);
+ }
+
+ @Test
+ public void testCreatedTransformsAreAppliedWithDun() throws Exception {
+ VcnGatewayConnectionConfig gatewayConfig =
+ VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(
+ NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN);
+ VcnGatewayConnection gatewayConnection =
+ new VcnGatewayConnection(
+ mVcnContext,
+ TEST_SUB_GRP,
+ TEST_SUBSCRIPTION_SNAPSHOT,
+ gatewayConfig,
+ mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
+ mDeps);
+ gatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ final VcnIkeSession session =
+ gatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
+ gatewayConnection.setIkeSession(session);
+ gatewayConnection.transitionTo(gatewayConnection.mConnectedState);
+ mTestLooper.dispatchAll();
+
+ verifyVcnTransformsApplied(gatewayConnection, true /* expectForwardTransform */);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 284f1f8..1ecb4c9 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -220,7 +220,7 @@
protected VcnChildSessionCallback getChildSessionCallback() {
ArgumentCaptor<ChildSessionCallback> captor =
ArgumentCaptor.forClass(ChildSessionCallback.class);
- verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
+ verify(mDeps, atLeastOnce()).newIkeSession(any(), any(), any(), any(), captor.capture());
return (VcnChildSessionCallback) captor.getValue();
}
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index c19ae3b..a117aa0 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -43,8 +43,8 @@
* cccc dd
*/
fun Iterable<Pair<String, String>>.columnize(separator: String = " | "): String {
- val col1w = map { (a, _) -> a.length }.max()!!
- val col2w = map { (_, b) -> b.length }.max()!!
+ val col1w = map { (a, _) -> a.length }.maxOrNull()!!
+ val col2w = map { (_, b) -> b.length }.maxOrNull()!!
return map { it.first.padEnd(col1w) + separator + it.second.padEnd(col2w) }.joinToString("\n")
}