diff options
58 files changed, 929 insertions, 1035 deletions
diff --git a/apct-tests/perftests/packagemanager/AndroidTest.xml b/apct-tests/perftests/packagemanager/AndroidTest.xml index c9d45a6bda74..db938e4373a3 100644 --- a/apct-tests/perftests/packagemanager/AndroidTest.xml +++ b/apct-tests/perftests/packagemanager/AndroidTest.xml @@ -76,11 +76,6 @@ <option name="test-file-name" value="QueriesAll49.apk"/> </target_preparer> - <test class="com.android.tradefed.testtype.AndroidJUnitTest"> - <option name="package" value="com.android.perftests.packagemanager"/> - <option name="hidden-api-checks" value="false"/> - </test> - <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> <option name="directory-keys" value="/data/local/PackageManagerPerfTests"/> <option name="collect-on-run-ended-only" value="true"/> diff --git a/config/Android.bp b/config/Android.bp index 6a6f848b7d52..dd681ca09723 100644 --- a/config/Android.bp +++ b/config/Android.bp @@ -33,3 +33,9 @@ filegroup { name: "preloaded-classes-denylist", srcs: ["preloaded-classes-denylist"], } + +prebuilt_etc { + name: "dirty-image-objects", + src: "dirty-image-objects", + filename: "dirty-image-objects", +} diff --git a/core/api/current.txt b/core/api/current.txt index 48949f8883bd..588396ac2140 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -31980,7 +31980,7 @@ package android.os { field public static final int S_V2 = 32; // 0x20 field public static final int TIRAMISU = 33; // 0x21 field public static final int UPSIDE_DOWN_CAKE = 34; // 0x22 - field @FlaggedApi("android.os.android_os_build_vanilla_ice_cream") public static final int VANILLA_ICE_CREAM = 10000; // 0x2710 + field public static final int VANILLA_ICE_CREAM = 10000; // 0x2710 } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1ac887b11603..5330feffe8c0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -968,6 +968,7 @@ public final class ActivityThread extends ClientTransactionHandler boolean autoStopProfiler; boolean streamingOutput; int mClockType; + int mProfilerOutputVersion; boolean profiling; boolean handlingProfiling; public void setProfiler(ProfilerInfo profilerInfo) { @@ -995,6 +996,7 @@ public final class ActivityThread extends ClientTransactionHandler autoStopProfiler = profilerInfo.autoStopProfiler; streamingOutput = profilerInfo.streamingOutput; mClockType = profilerInfo.clockType; + mProfilerOutputVersion = profilerInfo.profilerOutputVersion; } public void startProfiling() { if (profileFd == null || profiling) { @@ -1002,9 +1004,11 @@ public final class ActivityThread extends ClientTransactionHandler } try { int bufferSize = SystemProperties.getInt("debug.traceview-buffer-size-mb", 8); + int flags = 0; + flags = mClockType | ProfilerInfo.getFlagsForOutputVersion(mProfilerOutputVersion); VMDebug.startMethodTracing(profileFile, profileFd.getFileDescriptor(), - bufferSize * 1024 * 1024, mClockType, samplingInterval != 0, - samplingInterval, streamingOutput); + bufferSize * 1024 * 1024, flags, samplingInterval != 0, samplingInterval, + streamingOutput); profiling = true; } catch (RuntimeException e) { Slog.w(TAG, "Profiling failed on path " + profileFile, e); @@ -7052,6 +7056,7 @@ public final class ActivityThread extends ClientTransactionHandler mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler; mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput; mProfiler.mClockType = data.initProfilerInfo.clockType; + mProfiler.mProfilerOutputVersion = data.initProfilerInfo.profilerOutputVersion; if (data.initProfilerInfo.attachAgentDuringBind) { agent = data.initProfilerInfo.agent; } diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java index f7a3d78af207..bcae22a38f9e 100644 --- a/core/java/android/app/ProfilerInfo.java +++ b/core/java/android/app/ProfilerInfo.java @@ -32,7 +32,8 @@ import java.util.Objects; * {@hide} */ public class ProfilerInfo implements Parcelable { - + // Version of the profiler output + public static final int OUTPUT_VERSION_DEFAULT = 1; // CLOCK_TYPE_DEFAULT chooses the default used by ART. ART uses CLOCK_TYPE_DUAL by default (see // kDefaultTraceClockSource in art/runtime/runtime_globals.h). public static final int CLOCK_TYPE_DEFAULT = 0x000; @@ -43,6 +44,9 @@ public class ProfilerInfo implements Parcelable { public static final int CLOCK_TYPE_WALL = 0x010; public static final int CLOCK_TYPE_THREAD_CPU = 0x100; public static final int CLOCK_TYPE_DUAL = 0x110; + // The second and third bits of the flags field specify the trace format version. This should + // match with kTraceFormatVersionShift defined in art/runtime/trace.h. + public static final int TRACE_FORMAT_VERSION_SHIFT = 1; private static final String TAG = "ProfilerInfo"; @@ -83,8 +87,14 @@ public class ProfilerInfo implements Parcelable { */ public final int clockType; + /** + * Indicates the version of profiler output. + */ + public final int profilerOutputVersion; + public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop, - boolean streaming, String agent, boolean attachAgentDuringBind, int clockType) { + boolean streaming, String agent, boolean attachAgentDuringBind, int clockType, + int profilerOutputVersion) { profileFile = filename; profileFd = fd; samplingInterval = interval; @@ -93,6 +103,7 @@ public class ProfilerInfo implements Parcelable { this.clockType = clockType; this.agent = agent; this.attachAgentDuringBind = attachAgentDuringBind; + this.profilerOutputVersion = profilerOutputVersion; } public ProfilerInfo(ProfilerInfo in) { @@ -104,6 +115,7 @@ public class ProfilerInfo implements Parcelable { agent = in.agent; attachAgentDuringBind = in.attachAgentDuringBind; clockType = in.clockType; + profilerOutputVersion = in.profilerOutputVersion; } /** @@ -125,13 +137,29 @@ public class ProfilerInfo implements Parcelable { } /** + * Get the flags that need to be passed to VMDebug.startMethodTracing to specify the desired + * output format. + */ + public static int getFlagsForOutputVersion(int version) { + // Only two version 1 and version 2 are supported. Just use the default if we see an unknown + // version. + if (version != 1 || version != 2) { + version = OUTPUT_VERSION_DEFAULT; + } + + // The encoded version in the flags starts from 0, where as the version that we read from + // user starts from 1. So, subtract one before encoding it in the flags. + return (version - 1) << TRACE_FORMAT_VERSION_SHIFT; + } + + /** * Return a new ProfilerInfo instance, with fields populated from this object, * and {@link agent} and {@link attachAgentDuringBind} as given. */ public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) { return new ProfilerInfo(this.profileFile, this.profileFd, this.samplingInterval, this.autoStopProfiler, this.streamingOutput, agent, attachAgentDuringBind, - this.clockType); + this.clockType, this.profilerOutputVersion); } /** @@ -172,6 +200,7 @@ public class ProfilerInfo implements Parcelable { out.writeString(agent); out.writeBoolean(attachAgentDuringBind); out.writeInt(clockType); + out.writeInt(profilerOutputVersion); } /** @hide */ @@ -186,6 +215,7 @@ public class ProfilerInfo implements Parcelable { proto.write(ProfilerInfoProto.STREAMING_OUTPUT, streamingOutput); proto.write(ProfilerInfoProto.AGENT, agent); proto.write(ProfilerInfoProto.CLOCK_TYPE, clockType); + proto.write(ProfilerInfoProto.PROFILER_OUTPUT_VERSION, profilerOutputVersion); proto.end(token); } @@ -211,6 +241,7 @@ public class ProfilerInfo implements Parcelable { agent = in.readString(); attachAgentDuringBind = in.readBoolean(); clockType = in.readInt(); + profilerOutputVersion = in.readInt(); } @Override @@ -226,9 +257,9 @@ public class ProfilerInfo implements Parcelable { return Objects.equals(profileFile, other.profileFile) && autoStopProfiler == other.autoStopProfiler && samplingInterval == other.samplingInterval - && streamingOutput == other.streamingOutput - && Objects.equals(agent, other.agent) - && clockType == other.clockType; + && streamingOutput == other.streamingOutput && Objects.equals(agent, other.agent) + && clockType == other.clockType + && profilerOutputVersion == other.profilerOutputVersion; } @Override @@ -240,6 +271,7 @@ public class ProfilerInfo implements Parcelable { result = 31 * result + (streamingOutput ? 1 : 0); result = 31 * result + Objects.hashCode(agent); result = 31 * result + clockType; + result = 31 * result + profilerOutputVersion; return result; } } diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 6246dd77fd6d..91cdf8d8fcae 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -124,6 +124,22 @@ public class VcnManager { "vcn_network_selection_ipsec_packet_loss_percent_threshold"; /** + * Key for detecting unusually large increases in IPsec packet sequence numbers. + * + * <p>If the sequence number increases by more than this value within a second, it may indicate + * an intentional leap on the server's downlink. To avoid false positives, the packet loss + * detector will suppress loss reporting. + * + * <p>By default, there's no maximum limit enforced, prioritizing detection of lossy networks. + * To reduce false positives, consider setting an appropriate maximum threshold. + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY = + "vcn_network_selection_max_seq_num_increase_per_second"; + + /** * Key for the list of timeouts in minute to stop penalizing an underlying network candidate * * @hide @@ -180,6 +196,7 @@ public class VcnManager { VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY, VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY, + VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY, VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY, VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig index e64823af84cb..6fde39852844 100644 --- a/core/java/android/net/vcn/flags.aconfig +++ b/core/java/android/net/vcn/flags.aconfig @@ -34,4 +34,14 @@ flag{ namespace: "vcn" description: "Re-evaluate IPsec packet loss on LinkProperties or NetworkCapabilities change" bug: "323238888" +} + +flag{ + name: "handle_seq_num_leap" + namespace: "vcn" + description: "Do not report bad network when there is a suspected sequence number leap" + bug: "332598276" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java index d681a2c38f3d..d1531a119a0d 100644 --- a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java +++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java @@ -162,12 +162,21 @@ public final class IkeSessionParamsUtils { result.putInt(IP_VERSION_KEY, params.getIpVersion()); result.putInt(ENCAP_TYPE_KEY, params.getEncapType()); - // TODO: b/185941731 Make sure IkeSessionParamsUtils is automatically updated when a new - // IKE_OPTION is defined in IKE module and added in the IkeSessionParams final List<Integer> enabledIkeOptions = new ArrayList<>(); - for (int option : IKE_OPTIONS) { - if (isIkeOptionValid(option) && params.hasIkeOption(option)) { - enabledIkeOptions.add(option); + + try { + // TODO: b/328844044: Ideally this code should gate the behavior by checking the + // com.android.ipsec.flags.enabled_ike_options_api flag but that flag is not accessible + // right now. We should either update the code when the flag is accessible or remove the + // legacy behavior after VIC SDK finalization + enabledIkeOptions.addAll(params.getIkeOptions()); + } catch (Exception e) { + // getIkeOptions throws. It means the API is not available + enabledIkeOptions.clear(); + for (int option : IKE_OPTIONS) { + if (isIkeOptionValid(option) && params.hasIkeOption(option)) { + enabledIkeOptions.add(option); + } } } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 58717179d64d..a7d17f599fdb 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -17,7 +17,6 @@ package android.os; import android.Manifest; -import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -1228,7 +1227,6 @@ public class Build { /** * Vanilla Ice Cream. */ - @FlaggedApi(Flags.FLAG_ANDROID_OS_BUILD_VANILLA_ICE_CREAM) public static final int VANILLA_ICE_CREAM = CUR_DEVELOPMENT; } diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp index 4bd2d72a1eb4..01920de88496 100644 --- a/core/jni/com_android_internal_content_FileSystemUtils.cpp +++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp @@ -42,7 +42,11 @@ namespace android { bool punchHoles(const char *filePath, const uint64_t offset, const std::vector<Elf64_Phdr> &programHeaders) { struct stat64 beforePunch; - lstat64(filePath, &beforePunch); + if (int result = lstat64(filePath, &beforePunch); result != 0) { + ALOGE("lstat64 failed for filePath %s, error:%d", filePath, errno); + return false; + } + uint64_t blockSize = beforePunch.st_blksize; IF_ALOGD() { ALOGD("Total number of LOAD segments %zu", programHeaders.size()); @@ -152,7 +156,10 @@ bool punchHoles(const char *filePath, const uint64_t offset, IF_ALOGD() { struct stat64 afterPunch; - lstat64(filePath, &afterPunch); + if (int result = lstat64(filePath, &afterPunch); result != 0) { + ALOGD("lstat64 failed for filePath %s, error:%d", filePath, errno); + return false; + } ALOGD("Size after punching holes st_blocks: %" PRIu64 ", st_blksize: %ld, st_size: %" PRIu64 "", afterPunch.st_blocks, afterPunch.st_blksize, @@ -177,7 +184,7 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) { // only consider elf64 for punching holes if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) { - ALOGE("Provided file is not ELF64"); + ALOGW("Provided file is not ELF64"); return false; } @@ -215,4 +222,108 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) { return punchHoles(filePath, offset, programHeaders); } +bool punchHolesInZip(const char *filePath, uint64_t offset, uint16_t extraFieldLen) { + android::base::unique_fd fd(open(filePath, O_RDWR | O_CLOEXEC)); + if (!fd.ok()) { + ALOGE("Can't open file to punch %s", filePath); + return false; + } + + struct stat64 beforePunch; + if (int result = lstat64(filePath, &beforePunch); result != 0) { + ALOGE("lstat64 failed for filePath %s, error:%d", filePath, errno); + return false; + } + + uint64_t blockSize = beforePunch.st_blksize; + IF_ALOGD() { + ALOGD("Extra field length: %hu, Size before punching holes st_blocks: %" PRIu64 + ", st_blksize: %ld, st_size: %" PRIu64 "", + extraFieldLen, beforePunch.st_blocks, beforePunch.st_blksize, + static_cast<uint64_t>(beforePunch.st_size)); + } + + if (extraFieldLen < blockSize) { + ALOGD("Skipping punching apk as extra field length is less than block size"); + return false; + } + + // content is preceded by extra field. Zip offset is offset of exact content. + // move back by extraFieldLen so that scan can be started at start of extra field. + uint64_t extraFieldStart; + if (__builtin_sub_overflow(offset, extraFieldLen, &extraFieldStart)) { + ALOGE("Overflow occurred when calculating start of extra field"); + return false; + } + + constexpr uint64_t kMaxSize = 64 * 1024; + // Use malloc to gracefully handle any oom conditions + std::unique_ptr<uint8_t, decltype(&free)> buffer(static_cast<uint8_t *>(malloc(kMaxSize)), + &free); + if (buffer == nullptr) { + ALOGE("Failed to allocate read buffer"); + return false; + } + + // Read the entire extra fields at once and punch file according to zero stretches. + if (!ReadFullyAtOffset(fd, buffer.get(), extraFieldLen, extraFieldStart)) { + ALOGE("Failed to read extra field content"); + return false; + } + + IF_ALOGD() { + ALOGD("Extra field length: %hu content near offset: %s", extraFieldLen, + HexString(buffer.get(), extraFieldLen).c_str()); + } + + uint64_t currentSize = 0; + while (currentSize < extraFieldLen) { + uint64_t end = currentSize; + // find zero ranges + while (end < extraFieldLen && *(buffer.get() + end) == 0) { + ++end; + } + + uint64_t punchLen; + if (__builtin_sub_overflow(end, currentSize, &punchLen)) { + ALOGW("Overflow occurred when calculating punching length"); + return false; + } + + // Don't punch for every stretch of zero which is found + if (punchLen > blockSize) { + uint64_t punchOffset; + if (__builtin_add_overflow(extraFieldStart, currentSize, &punchOffset)) { + ALOGW("Overflow occurred when calculating punch start offset"); + return false; + } + + ALOGD("Punching hole in apk start: %" PRIu64 " len:%" PRIu64 "", punchOffset, punchLen); + + // Punch hole for this entire stretch. + int result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, punchOffset, + punchLen); + if (result < 0) { + ALOGE("fallocate failed to punch hole inside apk, error:%d", errno); + return false; + } + } + currentSize = end; + ++currentSize; + } + + IF_ALOGD() { + struct stat64 afterPunch; + if (int result = lstat64(filePath, &afterPunch); result != 0) { + ALOGD("lstat64 failed for filePath %s, error:%d", filePath, errno); + return false; + } + ALOGD("punchHolesInApk:: Size after punching holes st_blocks: %" PRIu64 + ", st_blksize: %ld, st_size: %" PRIu64 "", + afterPunch.st_blocks, afterPunch.st_blksize, + static_cast<uint64_t>(afterPunch.st_size)); + } + return true; +} + }; // namespace android diff --git a/core/jni/com_android_internal_content_FileSystemUtils.h b/core/jni/com_android_internal_content_FileSystemUtils.h index a6b145c690d1..52445e2b4229 100644 --- a/core/jni/com_android_internal_content_FileSystemUtils.h +++ b/core/jni/com_android_internal_content_FileSystemUtils.h @@ -28,4 +28,11 @@ namespace android { */ bool punchHolesInElf64(const char* filePath, uint64_t offset); +/* + * This function punches holes in zero segments of Apk file which are introduced during the + * alignment. Alignment tools add padding inside of extra field in local file header. punch holes in + * extra field for zero stretches till the actual file content. + */ +bool punchHolesInZip(const char* filePath, uint64_t offset, uint16_t extraFieldLen); + } // namespace android
\ No newline at end of file diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index faa83f8017f7..9b8dab78b342 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -28,6 +28,7 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <sys/statfs.h> #include <sys/types.h> #include <time.h> #include <unistd.h> @@ -145,8 +146,9 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr uint16_t method; off64_t offset; - - if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, nullptr, &offset, &when, &crc)) { + uint16_t extraFieldLength; + if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, nullptr, &offset, &when, &crc, + &extraFieldLength)) { ALOGE("Couldn't read zip entry info\n"); return INSTALL_FAILED_INVALID_APK; } @@ -177,6 +179,12 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr "%" PRIu64 "", fileName, zipFile->getZipFileName(), offset); } + + // if extra field for this zip file is present with some length, possibility is that it is + // padding added for zip alignment. Punch holes there too. + if (!punchHolesInZip(zipFile->getZipFileName(), offset, extraFieldLength)) { + ALOGW("Failed to punch apk : %s at extra field", zipFile->getZipFileName()); + } #endif // ENABLE_PUNCH_HOLES return INSTALL_SUCCEEDED; @@ -279,6 +287,25 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr return INSTALL_FAILED_CONTAINER_ERROR; } +#ifdef ENABLE_PUNCH_HOLES + // punch extracted elf files as well. This will fail where compression is on (like f2fs) but it + // will be useful for ext4 based systems + struct statfs64 fsInfo; + int result = statfs64(localFileName, &fsInfo); + if (result < 0) { + ALOGW("Failed to stat file :%s", localFileName); + } + + if (result == 0 && fsInfo.f_type == EXT4_SUPER_MAGIC) { + ALOGD("Punching extracted elf file %s on fs:%" PRIu64 "", fileName, + static_cast<uint64_t>(fsInfo.f_type)); + if (!punchHolesInElf64(localFileName, 0)) { + ALOGW("Failed to punch extracted elf file :%s from apk : %s", fileName, + zipFile->getZipFileName()); + } + } +#endif // ENABLE_PUNCH_HOLES + ALOGV("Successfully moved %s to %s\n", localTmpFileName, localFileName); return INSTALL_SUCCEEDED; diff --git a/core/proto/android/app/profilerinfo.proto b/core/proto/android/app/profilerinfo.proto index 86261ecdf54e..9941b83c1cb9 100644 --- a/core/proto/android/app/profilerinfo.proto +++ b/core/proto/android/app/profilerinfo.proto @@ -36,4 +36,5 @@ message ProfilerInfoProto { // Denotes an agent (and its parameters) to attach for profiling. optional string agent = 6; optional int32 clock_type = 7; + optional int32 profiler_output_version = 8; } diff --git a/core/tests/FileSystemUtilsTest/TEST_MAPPING b/core/tests/FileSystemUtilsTest/TEST_MAPPING new file mode 100644 index 000000000000..d41e981cbd67 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "FileSystemUtilsTests" + } + ] +} diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 2f2215fd51a2..d1d7c145680f 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,8 +16,6 @@ package android.security; -import android.compat.annotation.UnsupportedAppUsage; - /** * This class provides some constants and helper methods related to Android's Keystore service. * This class was originally much larger, but its functionality was superseded by other classes. @@ -30,11 +28,4 @@ public class KeyStore { // Used for UID field to indicate the calling UID. public static final int UID_SELF = -1; - - private static final KeyStore KEY_STORE = new KeyStore(); - - @UnsupportedAppUsage - public static KeyStore getInstance() { - return KEY_STORE; - } } diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp index 34a6bc27b93f..839c7b6fef37 100644 --- a/libs/androidfw/ZipFileRO.cpp +++ b/libs/androidfw/ZipFileRO.cpp @@ -119,30 +119,41 @@ ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const * appear to be bogus. */ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, + uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, + uint32_t* pModWhen, uint32_t* pCrc32) const +{ + return getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset, pModWhen, + pCrc32, nullptr); +} + +bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, - uint32_t* pModWhen, uint32_t* pCrc32) const + uint32_t* pModWhen, uint32_t* pCrc32, uint16_t* pExtraFieldSize) const { const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); const ZipEntry& ze = zipEntry->entry; - if (pMethod != NULL) { + if (pMethod != nullptr) { *pMethod = ze.method; } - if (pUncompLen != NULL) { + if (pUncompLen != nullptr) { *pUncompLen = ze.uncompressed_length; } - if (pCompLen != NULL) { + if (pCompLen != nullptr) { *pCompLen = ze.compressed_length; } - if (pOffset != NULL) { + if (pOffset != nullptr) { *pOffset = ze.offset; } - if (pModWhen != NULL) { + if (pModWhen != nullptr) { *pModWhen = ze.mod_time; } - if (pCrc32 != NULL) { + if (pCrc32 != nullptr) { *pCrc32 = ze.crc32; } + if (pExtraFieldSize != nullptr) { + *pExtraFieldSize = ze.extra_field_size; + } return true; } diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h index 031d2e8fd48f..f7c5007c80d2 100644 --- a/libs/androidfw/include/androidfw/ZipFileRO.h +++ b/libs/androidfw/include/androidfw/ZipFileRO.h @@ -151,6 +151,10 @@ public: uint32_t* pCompLen, off64_t* pOffset, uint32_t* pModWhen, uint32_t* pCrc32) const; + bool getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, + uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, + uint32_t* pModWhen, uint32_t* pCrc32, uint16_t* pExtraFieldSize) const; + /* * Create a new FileMap object that maps a subset of the archive. For * an uncompressed entry this effectively provides a pointer to the diff --git a/location/Android.bp b/location/Android.bp index eb7cd01111b2..5ba35ac3328a 100644 --- a/location/Android.bp +++ b/location/Android.bp @@ -26,6 +26,7 @@ java_sdk_library { "com.android.internal.location", ], libs: [ + "android.location.flags-aconfig-java", "app-compat-annotations", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage ], diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING index f5deb2ba3e07..10da632e7b6f 100644 --- a/location/TEST_MAPPING +++ b/location/TEST_MAPPING @@ -2,12 +2,7 @@ "presubmit": [ { "name": "CtsLocationFineTestCases", - "options": [ - { - // TODO: Wait for test to deflake - b/293934372 - "exclude-filter":"android.location.cts.fine.ScanningSettingsTest" - } - ] + "options": [] }, { "name": "CtsLocationCoarseTestCases" diff --git a/location/api/current.txt b/location/api/current.txt index 0c23d8cd77e0..589e9b791e61 100644 --- a/location/api/current.txt +++ b/location/api/current.txt @@ -412,8 +412,8 @@ package android.location { field public static final int TYPE_GPS_L1CA = 257; // 0x101 field public static final int TYPE_GPS_L2CNAV = 258; // 0x102 field public static final int TYPE_GPS_L5CNAV = 259; // 0x103 - field @FlaggedApi(Flags.FLAG_GNSS_API_NAVIC_L1) public static final int TYPE_IRN_L1 = 1795; // 0x703 - field @FlaggedApi(Flags.FLAG_GNSS_API_NAVIC_L1) public static final int TYPE_IRN_L5 = 1794; // 0x702 + field @FlaggedApi("android.location.flags.gnss_api_navic_l1") public static final int TYPE_IRN_L1 = 1795; // 0x703 + field @FlaggedApi("android.location.flags.gnss_api_navic_l1") public static final int TYPE_IRN_L5 = 1794; // 0x702 field @Deprecated public static final int TYPE_IRN_L5CA = 1793; // 0x701 field public static final int TYPE_QZS_L1CA = 1025; // 0x401 field public static final int TYPE_SBS = 513; // 0x201 diff --git a/location/api/system-current.txt b/location/api/system-current.txt index b1cf96d41497..075fbb1f64b3 100644 --- a/location/api/system-current.txt +++ b/location/api/system-current.txt @@ -113,13 +113,13 @@ package android.location { } public final class GnssMeasurementRequest implements android.os.Parcelable { - method @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE) @NonNull public android.os.WorkSource getWorkSource(); + method @FlaggedApi("android.location.flags.gnss_api_measurement_request_work_source") @NonNull public android.os.WorkSource getWorkSource(); method public boolean isCorrelationVectorOutputsEnabled(); } public static final class GnssMeasurementRequest.Builder { method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean); - method @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE) @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource); + method @FlaggedApi("android.location.flags.gnss_api_measurement_request_work_source") @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource); } public final class GnssReflectingPlane implements android.os.Parcelable { diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 17c4a7792b88..4708db27765e 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -5230,6 +5230,13 @@ final public class MediaCodec { setParameters(keys, values); } + private void logAndRun(String message, Runnable r) { + final String TAG = "MediaCodec"; + android.util.Log.d(TAG, "enter: " + message); + r.run(); + android.util.Log.d(TAG, "exit : " + message); + } + /** * Sets an asynchronous callback for actionable MediaCodec events. * @@ -5259,14 +5266,40 @@ final public class MediaCodec { // even if we were to extend this to be callable dynamically, it must // be called when codec is flushed, so no messages are pending. if (newHandler != mCallbackHandler) { - mCallbackHandler.removeMessages(EVENT_SET_CALLBACK); - mCallbackHandler.removeMessages(EVENT_CALLBACK); + if (android.media.codec.Flags.setCallbackStall()) { + logAndRun( + "[new handler] removeMessages(SET_CALLBACK)", + () -> { + mCallbackHandler.removeMessages(EVENT_SET_CALLBACK); + }); + logAndRun( + "[new handler] removeMessages(CALLBACK)", + () -> { + mCallbackHandler.removeMessages(EVENT_CALLBACK); + }); + } else { + mCallbackHandler.removeMessages(EVENT_SET_CALLBACK); + mCallbackHandler.removeMessages(EVENT_CALLBACK); + } mCallbackHandler = newHandler; } } } else if (mCallbackHandler != null) { - mCallbackHandler.removeMessages(EVENT_SET_CALLBACK); - mCallbackHandler.removeMessages(EVENT_CALLBACK); + if (android.media.codec.Flags.setCallbackStall()) { + logAndRun( + "[null handler] removeMessages(SET_CALLBACK)", + () -> { + mCallbackHandler.removeMessages(EVENT_SET_CALLBACK); + }); + logAndRun( + "[null handler] removeMessages(CALLBACK)", + () -> { + mCallbackHandler.removeMessages(EVENT_CALLBACK); + }); + } else { + mCallbackHandler.removeMessages(EVENT_SET_CALLBACK); + mCallbackHandler.removeMessages(EVENT_CALLBACK); + } } if (mCallbackHandler != null) { diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 82561f982a03..4f9917b19110 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -2886,6 +2886,10 @@ static void extractMemoryFromContext( jint offset, jint size, sp<hardware::HidlMemory> *memory) { + if ((offset + size) > context->capacity()) { + ALOGW("extractMemoryFromContext: offset + size provided exceed capacity"); + return; + } *memory = context->toHidlMemory(); if (*memory == nullptr) { if (!context->mBlock) { @@ -2893,23 +2897,26 @@ static void extractMemoryFromContext( return; } ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)", - context->capacity()); + context->capacity()); if (!obtain(context, context->capacity(), context->mCodecNames, true /* secure */)) { ALOGW("extractMemoryFromContext: failed to obtain secure block"); return; } - C2WriteView view = context->mBlock->map().get(); - if (view.error() != C2_OK) { - ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error()); - return; - } - uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer()); - memcpy(memoryPtr + offset, view.base() + offset, size); - context->mBlock.reset(); - context->mReadWriteMapping.reset(); *memory = context->toHidlMemory(); } + if (context->mBlock == nullptr || context->mReadWriteMapping == nullptr) { + ALOGW("extractMemoryFromContext: Cannot extract memory as C2Block is not created/mapped"); + return; + } + if (context->mReadWriteMapping->error() != C2_OK) { + ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", + context->mReadWriteMapping->error()); + return; + } + // We are proceeding to extract memory from C2Block + uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer()); + memcpy(memoryPtr + offset, context->mReadWriteMapping->base() + offset, size); } static void extractBufferFromContext( diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java index 8ed4bf2b9cc3..3fc8f26e38a3 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java @@ -361,6 +361,7 @@ public class MediaRouter2ManagerTest { * Tests if MR2.SessionCallback.onSessionCreated is called * when a route is selected from MR2Manager. */ + @Ignore // Ignored due to flakiness. No plans to fix though, in favor of removal (b/334970551). @Test public void testRouterOnSessionCreated() throws Exception { Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); @@ -500,6 +501,7 @@ public class MediaRouter2ManagerTest { /** * Tests select, transfer, release of routes of a provider */ + @Ignore // Ignored due to flakiness. No plans to fix though, in favor of removal (b/334970551). @Test public void testSelectAndTransferAndRelease() throws Exception { Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); @@ -878,6 +880,7 @@ public class MediaRouter2ManagerTest { * Tests if getSelectableRoutes and getDeselectableRoutes filter routes based on * selected routes */ + @Ignore // Ignored due to flakiness. No plans to fix though, in favor of removal (b/334970551). @Test public void testGetSelectableRoutes_notReturnsSelectedRoutes() throws Exception { Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); diff --git a/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java deleted file mode 100644 index fa4d6afc03d3..000000000000 --- a/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.utils; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import java.io.File; -import java.util.List; -import java.util.Objects; - -/** - * Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java - * - * @hide - */ -public class ArrayUtils { - private ArrayUtils() { /* cannot be instantiated */ } - public static final File[] EMPTY_FILE = new File[0]; - - - /** - * Return first index of {@code value} in {@code array}, or {@code -1} if - * not found. - */ - public static <T> int indexOf(@Nullable T[] array, T value) { - if (array == null) return -1; - for (int i = 0; i < array.length; i++) { - if (Objects.equals(array[i], value)) return i; - } - return -1; - } - - /** @hide */ - public static @NonNull File[] defeatNullable(@Nullable File[] val) { - return (val != null) ? val : EMPTY_FILE; - } - - /** - * Checks if given array is null or has zero elements. - */ - public static boolean isEmpty(@Nullable int[] array) { - return array == null || array.length == 0; - } - - /** - * True if the byte array is null or has length 0. - */ - public static boolean isEmpty(@Nullable byte[] array) { - return array == null || array.length == 0; - } - - /** - * Converts from List of bytes to byte array - * @param list - * @return byte[] - */ - public static byte[] toPrimitive(List<byte[]> list) { - if (list.size() == 0) { - return new byte[0]; - } - int byteLen = list.get(0).length; - byte[] array = new byte[list.size() * byteLen]; - for (int i = 0; i < list.size(); i++) { - for (int j = 0; j < list.get(i).length; j++) { - array[i * byteLen + j] = list.get(i)[j]; - } - } - return array; - } - - /** - * Adds value to given array if not already present, providing set-like - * behavior. - */ - public static @NonNull int[] appendInt(@Nullable int[] cur, int val) { - return appendInt(cur, val, false); - } - - /** - * Adds value to given array. - */ - public static @NonNull int[] appendInt(@Nullable int[] cur, int val, - boolean allowDuplicates) { - if (cur == null) { - return new int[] { val }; - } - final int n = cur.length; - if (!allowDuplicates) { - for (int i = 0; i < n; i++) { - if (cur[i] == val) { - return cur; - } - } - } - int[] ret = new int[n + 1]; - System.arraycopy(cur, 0, ret, 0, n); - ret[n] = val; - return ret; - } -} diff --git a/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java deleted file mode 100644 index afcf6895fd0d..000000000000 --- a/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.utils; - -import android.annotation.NonNull; -import android.os.Handler; -import android.os.HandlerThread; - -import com.android.internal.annotations.GuardedBy; - -import java.util.concurrent.Executor; - -/** - * Thread for asynchronous event processing. This thread is configured as - * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU - * resources will be dedicated to it, and it will "have less chance of impacting - * the responsiveness of the user interface." - * <p> - * This thread is best suited for tasks that the user is not actively waiting - * for, or for tasks that the user expects to be executed eventually. - * - * @see com.android.internal.os.BackgroundThread - * - * TODO: b/326916057 depend on modules-utils-backgroundthread instead - * @hide - */ -public final class BackgroundThread extends HandlerThread { - private static final Object sLock = new Object(); - - @GuardedBy("sLock") - private static BackgroundThread sInstance; - @GuardedBy("sLock") - private static Handler sHandler; - @GuardedBy("sLock") - private static HandlerExecutor sHandlerExecutor; - - private BackgroundThread() { - super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND); - } - - @GuardedBy("sLock") - private static void ensureThreadLocked() { - if (sInstance == null) { - sInstance = new BackgroundThread(); - sInstance.start(); - sHandler = new Handler(sInstance.getLooper()); - sHandlerExecutor = new HandlerExecutor(sHandler); - } - } - - /** - * Get the singleton instance of this class. - * - * @return the singleton instance of this class - */ - @NonNull - public static BackgroundThread get() { - synchronized (sLock) { - ensureThreadLocked(); - return sInstance; - } - } - - /** - * Get the singleton {@link Handler} for this class. - * - * @return the singleton {@link Handler} for this class. - */ - @NonNull - public static Handler getHandler() { - synchronized (sLock) { - ensureThreadLocked(); - return sHandler; - } - } - - /** - * Get the singleton {@link Executor} for this class. - * - * @return the singleton {@link Executor} for this class. - */ - @NonNull - public static Executor getExecutor() { - synchronized (sLock) { - ensureThreadLocked(); - return sHandlerExecutor; - } - } -} diff --git a/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java deleted file mode 100644 index e4923bfc4ecb..000000000000 --- a/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.utils; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Bits and pieces copied from hidden API of android.os.FileUtils. - * - * @hide - */ -public class FileUtils { - /** - * Read a text file into a String, optionally limiting the length. - * - * @param file to read (will not seek, so things like /proc files are OK) - * @param max length (positive for head, negative of tail, 0 for no limit) - * @param ellipsis to add of the file was truncated (can be null) - * @return the contents of the file, possibly truncated - * @throws IOException if something goes wrong reading the file - * @hide - */ - public static @Nullable String readTextFile(@Nullable File file, @Nullable int max, - @Nullable String ellipsis) throws IOException { - InputStream input = new FileInputStream(file); - // wrapping a BufferedInputStream around it because when reading /proc with unbuffered - // input stream, bytes read not equal to buffer size is not necessarily the correct - // indication for EOF; but it is true for BufferedInputStream due to its implementation. - BufferedInputStream bis = new BufferedInputStream(input); - try { - long size = file.length(); - if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes - if (size > 0 && (max == 0 || size < max)) max = (int) size; - byte[] data = new byte[max + 1]; - int length = bis.read(data); - if (length <= 0) return ""; - if (length <= max) return new String(data, 0, length); - if (ellipsis == null) return new String(data, 0, max); - return new String(data, 0, max) + ellipsis; - } else if (max < 0) { // "tail" mode: keep the last N - int len; - boolean rolled = false; - byte[] last = null; - byte[] data = null; - do { - if (last != null) rolled = true; - byte[] tmp = last; - last = data; - data = tmp; - if (data == null) data = new byte[-max]; - len = bis.read(data); - } while (len == data.length); - - if (last == null && len <= 0) return ""; - if (last == null) return new String(data, 0, len); - if (len > 0) { - rolled = true; - System.arraycopy(last, len, last, 0, last.length - len); - System.arraycopy(data, 0, last, last.length - len, len); - } - if (ellipsis == null || !rolled) return new String(last); - return ellipsis + new String(last); - } else { // "cat" mode: size unknown, read it all in streaming fashion - ByteArrayOutputStream contents = new ByteArrayOutputStream(); - int len; - byte[] data = new byte[1024]; - do { - len = bis.read(data); - if (len > 0) contents.write(data, 0, len); - } while (len == data.length); - return contents.toString(); - } - } finally { - bis.close(); - input.close(); - } - } - - /** - * Perform an fsync on the given FileOutputStream. The stream at this - * point must be flushed but not yet closed. - * - * @hide - */ - public static boolean sync(FileOutputStream stream) { - try { - if (stream != null) { - stream.getFD().sync(); - } - return true; - } catch (IOException e) { - } - return false; - } - - /** - * List the files in the directory or return empty file. - * - * @hide - */ - public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) { - return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles()) - : ArrayUtils.EMPTY_FILE; - } -} diff --git a/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java deleted file mode 100644 index fdb15e2333d5..000000000000 --- a/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.utils; - -import android.annotation.NonNull; -import android.os.Handler; - -import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.concurrent.RejectedExecutionException; - -/** - * An adapter {@link Executor} that posts all executed tasks onto the given - * {@link Handler}. - * - * TODO: b/326916057 depend on modules-utils-backgroundthread instead - * @hide - */ -public class HandlerExecutor implements Executor { - private final Handler mHandler; - - public HandlerExecutor(@NonNull Handler handler) { - mHandler = Objects.requireNonNull(handler); - } - - @Override - public void execute(Runnable command) { - if (!mHandler.post(command)) { - throw new RejectedExecutionException(mHandler + " is shutting down"); - } - } -} diff --git a/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java deleted file mode 100644 index 5cdc2536129a..000000000000 --- a/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.utils; - -import libcore.util.EmptyArray; - -import java.util.NoSuchElementException; - -/** - * Copied from frameworks/base/core/java/android/util/LongArrayQueue.java - * - * @hide - */ -public class LongArrayQueue { - - private long[] mValues; - private int mSize; - private int mHead; - private int mTail; - - private long[] newUnpaddedLongArray(int num) { - return new long[num]; - } - /** - * Initializes a queue with the given starting capacity. - * - * @param initialCapacity the capacity. - */ - public LongArrayQueue(int initialCapacity) { - if (initialCapacity == 0) { - mValues = EmptyArray.LONG; - } else { - mValues = newUnpaddedLongArray(initialCapacity); - } - mSize = 0; - mHead = mTail = 0; - } - - /** - * Initializes a queue with default starting capacity. - */ - public LongArrayQueue() { - this(16); - } - - /** @hide */ - public static int growSize(int currentSize) { - return currentSize <= 4 ? 8 : currentSize * 2; - } - - private void grow() { - if (mSize < mValues.length) { - throw new IllegalStateException("Queue not full yet!"); - } - final int newSize = growSize(mSize); - final long[] newArray = newUnpaddedLongArray(newSize); - final int r = mValues.length - mHead; // Number of elements on and to the right of head. - System.arraycopy(mValues, mHead, newArray, 0, r); - System.arraycopy(mValues, 0, newArray, r, mHead); - mValues = newArray; - mHead = 0; - mTail = mSize; - } - - /** - * Returns the number of elements in the queue. - */ - public int size() { - return mSize; - } - - /** - * Removes all elements from this queue. - */ - public void clear() { - mSize = 0; - mHead = mTail = 0; - } - - /** - * Adds a value to the tail of the queue. - * - * @param value the value to be added. - */ - public void addLast(long value) { - if (mSize == mValues.length) { - grow(); - } - mValues[mTail] = value; - mTail = (mTail + 1) % mValues.length; - mSize++; - } - - /** - * Removes an element from the head of the queue. - * - * @return the element at the head of the queue. - * @throws NoSuchElementException if the queue is empty. - */ - public long removeFirst() { - if (mSize == 0) { - throw new NoSuchElementException("Queue is empty!"); - } - final long ret = mValues[mHead]; - mHead = (mHead + 1) % mValues.length; - mSize--; - return ret; - } - - /** - * Returns the element at the given position from the head of the queue, where 0 represents the - * head of the queue. - * - * @param position the position from the head of the queue. - * @return the element found at the given position. - * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or - * {@code position} >= {@link #size()} - */ - public long get(int position) { - if (position < 0 || position >= mSize) { - throw new IndexOutOfBoundsException("Index " + position - + " not valid for a queue of size " + mSize); - } - final int index = (mHead + position) % mValues.length; - return mValues[index]; - } - - /** - * Returns the element at the head of the queue, without removing it. - * - * @return the element at the head of the queue. - * @throws NoSuchElementException if the queue is empty - */ - public long peekFirst() { - if (mSize == 0) { - throw new NoSuchElementException("Queue is empty!"); - } - return mValues[mHead]; - } - - /** - * Returns the element at the tail of the queue. - * - * @return the element at the tail of the queue. - * @throws NoSuchElementException if the queue is empty. - */ - public long peekLast() { - if (mSize == 0) { - throw new NoSuchElementException("Queue is empty!"); - } - final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1; - return mValues[index]; - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - if (mSize <= 0) { - return "{}"; - } - - final StringBuilder buffer = new StringBuilder(mSize * 64); - buffer.append('{'); - buffer.append(get(0)); - for (int i = 1; i < mSize; i++) { - buffer.append(", "); - buffer.append(get(i)); - } - buffer.append('}'); - return buffer.toString(); - } -} diff --git a/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java deleted file mode 100644 index dbbef61f6777..000000000000 --- a/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.utils; - -import android.annotation.NonNull; -import android.system.ErrnoException; -import android.system.Os; - -import com.android.modules.utils.TypedXmlPullParser; - -import libcore.util.XmlObjectFactory; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Copied over partly from frameworks/base/core/java/com/android/internal/util/XmlUtils.java - * - * @hide - */ -public class XmlUtils { - - private static final String STRING_ARRAY_SEPARATOR = ":"; - - /** @hide */ - public static final void beginDocument(XmlPullParser parser, String firstElementName) - throws XmlPullParserException, IOException { - int type; - while ((type = parser.next()) != parser.START_TAG - && type != parser.END_DOCUMENT) { - // Do nothing - } - - if (type != parser.START_TAG) { - throw new XmlPullParserException("No start tag found"); - } - - if (!parser.getName().equals(firstElementName)) { - throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() - + ", expected " + firstElementName); - } - } - - /** @hide */ - public static boolean nextElementWithin(XmlPullParser parser, int outerDepth) - throws IOException, XmlPullParserException { - for (;;) { - int type = parser.next(); - if (type == XmlPullParser.END_DOCUMENT - || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) { - return false; - } - if (type == XmlPullParser.START_TAG - && parser.getDepth() == outerDepth + 1) { - return true; - } - } - } - - private static XmlPullParser newPullParser() { - try { - XmlPullParser parser = XmlObjectFactory.newXmlPullParser(); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - return parser; - } catch (XmlPullParserException e) { - throw new AssertionError(); - } - } - - /** @hide */ - public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in) - throws IOException { - final byte[] magic = new byte[4]; - if (in instanceof FileInputStream) { - try { - Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0); - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } else { - if (!in.markSupported()) { - in = new BufferedInputStream(in); - } - in.mark(8); - in.read(magic); - in.reset(); - } - - final TypedXmlPullParser xml; - xml = (TypedXmlPullParser) newPullParser(); - try { - xml.setInput(in, "UTF_8"); - } catch (XmlPullParserException e) { - throw new IOException(e); - } - return xml; - } -} diff --git a/packages/SettingsLib/aconfig/OWNERS b/packages/SettingsLib/aconfig/OWNERS new file mode 100644 index 000000000000..ba02d20b1ae4 --- /dev/null +++ b/packages/SettingsLib/aconfig/OWNERS @@ -0,0 +1,2 @@ +# go/android-fwk-media-solutions for info on areas of ownership. +per-file settingslib_media_flag_declarations.aconfig = file:platform/frameworks/av:/media/janitors/media_solutions_OWNERS diff --git a/packages/CrashRecovery/services/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java index 3d610d3747c9..3d610d3747c9 100644 --- a/packages/CrashRecovery/services/java/com/android/server/ExplicitHealthCheckController.java +++ b/services/core/java/com/android/server/ExplicitHealthCheckController.java diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index bdc4a7afae89..2545620a2630 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -22,6 +22,7 @@ per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Battery* = file:/BATTERY_STATS_OWNERS per-file *BinaryTransparency* = file:/core/java/android/transparency/OWNERS per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS +per-file ExplicitHealthCheckController.java = file:/services/core/java/com/android/server/crashrecovery/OWNERS per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS per-file **IpSec* = file:/services/core/java/com/android/server/net/OWNERS per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS @@ -35,9 +36,9 @@ per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationSer per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS per-file MmsServiceBroker.java = file:/telephony/OWNERS per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS -per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS +per-file PackageWatchdog.java = file:/services/core/java/com/android/server/crashrecovery/OWNERS per-file PinnerService.java = file:/core/java/android/app/pinner/OWNERS -per-file RescueParty.java = shuc@google.com, ancr@google.com, harshitmahajan@google.com +per-file RescueParty.java = file:/services/core/java/com/android/server/crashrecovery/OWNERS per-file SensitiveContentProtectionManagerService.java = file:/core/java/android/permission/OWNERS per-file SystemClockTime.java = file:/services/core/java/com/android/server/timedetector/OWNERS per-file SystemTimeZone.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 75a8bdfe5416..6f20adf74ee2 100644 --- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -39,15 +39,15 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.LongArrayQueue; import android.util.Slog; import android.util.Xml; -import android.utils.BackgroundThread; -import android.utils.LongArrayQueue; -import android.utils.XmlUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index f86eb61c365f..271d552fc574 100644 --- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -31,6 +31,7 @@ import android.content.pm.VersionedPackage; import android.crashrecovery.flags.Flags; import android.os.Build; import android.os.Environment; +import android.os.FileUtils; import android.os.PowerManager; import android.os.RecoverySystem; import android.os.SystemClock; @@ -43,11 +44,10 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Slog; -import android.utils.ArrayUtils; -import android.utils.FileUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.server.PackageWatchdog.FailureReasons; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 2b35231a51f8..0ff0264da4ae 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -146,7 +146,6 @@ import com.android.internal.os.FuseUnavailableMountException; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; -import com.android.internal.util.HexDump; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.modules.utils.TypedXmlPullParser; @@ -3270,7 +3269,7 @@ class StorageManagerService extends IStorageManager.Stub throws RemoteException { super.setCeStorageProtection_enforcePermission(); - mVold.setCeStorageProtection(userId, HexDump.toHexString(secret)); + mVold.setCeStorageProtection(userId, secret); } /* Only for use by LockSettingsService */ @@ -3280,7 +3279,7 @@ class StorageManagerService extends IStorageManager.Stub super.unlockCeStorage_enforcePermission(); if (StorageManager.isFileEncrypted()) { - mVold.unlockCeStorage(userId, HexDump.toHexString(secret)); + mVold.unlockCeStorage(userId, secret); } synchronized (mLock) { mCeUnlockedUsers.append(userId); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index de039fbdd509..c13f02ebdf1b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -173,6 +173,8 @@ final class ActivityManagerShellCommand extends ShellCommand { private static final DateTimeFormatter LOG_NAME_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss", Locale.ROOT); + private static final String PROFILER_OUTPUT_VERSION_FLAG = "--profiler-output-version"; + // IPC interface to activity manager -- don't need to do additional security checks. final IActivityManager mInterface; final IActivityTaskManager mTaskInterface; @@ -198,6 +200,7 @@ final class ActivityManagerShellCommand extends ShellCommand { private String mAgent; // Agent to attach on startup. private boolean mAttachAgentDuringBind; // Whether agent should be attached late. private int mClockType; // Whether we need thread cpu / wall clock / both. + private int mProfilerOutputVersion; // The version of the profiler output. private int mDisplayId; private int mTaskDisplayAreaFeatureId; private int mWindowingMode; @@ -526,6 +529,8 @@ final class ActivityManagerShellCommand extends ShellCommand { } else if (opt.equals("--clock-type")) { String clock_type = getNextArgRequired(); mClockType = ProfilerInfo.getClockTypeFromString(clock_type); + } else if (opt.equals(PROFILER_OUTPUT_VERSION_FLAG)) { + mProfilerOutputVersion = Integer.parseInt(getNextArgRequired()); } else if (opt.equals("--streaming")) { mStreaming = true; } else if (opt.equals("--attach-agent")) { @@ -578,7 +583,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } else if (opt.equals("--splashscreen-show-icon")) { mShowSplashScreen = true; } else if (opt.equals("--dismiss-keyguard-if-insecure") - || opt.equals("--dismiss-keyguard")) { + || opt.equals("--dismiss-keyguard")) { mDismissKeyguardIfInsecure = true; } else { return false; @@ -684,8 +689,9 @@ final class ActivityManagerShellCommand extends ShellCommand { return 1; } } - profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop, - mStreaming, mAgent, mAttachAgentDuringBind, mClockType); + profilerInfo = + new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop, mStreaming, + mAgent, mAttachAgentDuringBind, mClockType, mProfilerOutputVersion); } pw.println("Starting: " + intent); @@ -1028,6 +1034,7 @@ final class ActivityManagerShellCommand extends ShellCommand { mSamplingInterval = 0; mStreaming = false; mClockType = ProfilerInfo.CLOCK_TYPE_DEFAULT; + mProfilerOutputVersion = ProfilerInfo.OUTPUT_VERSION_DEFAULT; String process = null; @@ -1042,6 +1049,8 @@ final class ActivityManagerShellCommand extends ShellCommand { } else if (opt.equals("--clock-type")) { String clock_type = getNextArgRequired(); mClockType = ProfilerInfo.getClockTypeFromString(clock_type); + } else if (opt.equals(PROFILER_OUTPUT_VERSION_FLAG)) { + mProfilerOutputVersion = Integer.parseInt(getNextArgRequired()); } else if (opt.equals("--streaming")) { mStreaming = true; } else if (opt.equals("--sampling")) { @@ -1089,7 +1098,7 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming, - null, false, mClockType); + null, false, mClockType, mProfilerOutputVersion); } if (!mInterface.profileControl(process, userId, start, profilerInfo, profileType)) { @@ -4177,6 +4186,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Print this help text."); pw.println(" start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]"); pw.println(" [--sampling INTERVAL] [--clock-type <TYPE>] [--streaming]"); + pw.println(" [" + PROFILER_OUTPUT_VERSION_FLAG + " NUMBER]"); pw.println(" [-R COUNT] [-S] [--track-allocation]"); pw.println(" [--user <USER_ID> | current] [--suspend] <INTENT>"); pw.println(" Start an Activity. Options are:"); @@ -4192,6 +4202,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" The default value is dual. (use with --start-profiler)"); pw.println(" --streaming: stream the profiling output to the specified file"); pw.println(" (use with --start-profiler)"); + pw.println(" " + PROFILER_OUTPUT_VERSION_FLAG + " Specify the version of the"); + pw.println(" profiling output (use with --start-profiler)"); pw.println(" -P <FILE>: like above, but profiling stops when app goes idle"); pw.println(" --attach-agent <agent>: attach the given agent before binding"); pw.println(" --attach-agent-bind <agent>: attach the given agent during binding"); @@ -4283,6 +4295,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --dump-file <FILE>: Specify the file the trace should be dumped to."); pw.println(" profile start [--user <USER_ID> current]"); pw.println(" [--clock-type <TYPE>]"); + pw.println(" [" + PROFILER_OUTPUT_VERSION_FLAG + " VERSION]"); pw.println(" [--sampling INTERVAL | --streaming] <PROCESS> <FILE>"); pw.println(" Start profiler on a process. The given <PROCESS> argument"); pw.println(" may be either a process name or pid. Options are:"); @@ -4292,6 +4305,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --clock-type <TYPE>: use the specified clock to report timestamps."); pw.println(" The type can be one of wall | thread-cpu | dual. The default"); pw.println(" value is dual."); + pw.println(" " + PROFILER_OUTPUT_VERSION_FLAG + "VERSION: specifies the output"); + pw.println(" format version"); pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds"); pw.println(" between samples."); pw.println(" --streaming: stream the profiling output to the specified file."); diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index 9b091b3a9c17..1dab8c72bc9f 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -2484,8 +2484,8 @@ public class AppProfiler { } } } else if (instr != null && instr.mProfileFile != null) { - profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false, - null, false, 0); + profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false, null, + false, 0, ProfilerInfo.OUTPUT_VERSION_DEFAULT); } if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) { // We need to do a debuggable check here. See setAgentApp for why the check is @@ -2495,7 +2495,8 @@ public class AppProfiler { // Do not overwrite already requested agent. if (profilerInfo == null) { profilerInfo = new ProfilerInfo(null, null, 0, false, false, - mAppAgentMap.get(processName), true, 0); + mAppAgentMap.get(processName), true, 0, + ProfilerInfo.OUTPUT_VERSION_DEFAULT); } else if (profilerInfo.agent == null) { profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true); } @@ -2622,14 +2623,16 @@ public class AppProfiler { if (mProfileData.getProfilerInfo() != null) { pw.println(" mProfileFile=" + mProfileData.getProfilerInfo().profileFile + " mProfileFd=" + mProfileData.getProfilerInfo().profileFd); - pw.println(" mSamplingInterval=" - + mProfileData.getProfilerInfo().samplingInterval + pw.println( + " mSamplingInterval=" + mProfileData.getProfilerInfo().samplingInterval + " mAutoStopProfiler=" + mProfileData.getProfilerInfo().autoStopProfiler + " mStreamingOutput=" + mProfileData.getProfilerInfo().streamingOutput + " mClockType=" - + mProfileData.getProfilerInfo().clockType); + + mProfileData.getProfilerInfo().clockType + + " mProfilerOutputVersion=" + + mProfileData.getProfilerInfo().profilerOutputVersion); pw.println(" mProfileType=" + mProfileType); } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 0bfbee694366..5e6cf1ab73c6 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -7855,6 +7855,7 @@ public class AudioService extends IAudioService.Stub DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET); DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE); + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID); DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET); DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET); DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET); diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 6f8a46be089f..1387ba915147 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -63,7 +63,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.DeadObjectException; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -85,7 +84,6 @@ import com.android.server.uri.UriGrantsManagerInternal; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.CopyOnWriteArrayList; @@ -183,6 +181,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR private final boolean mVolumeAdjustmentForRemoteGroupSessions; private final Object mLock = new Object(); + // This field is partially guarded by mLock. Writes and non-atomic iterations (for example: + // index-based-iterations) must be guarded by mLock. But it is safe to acquire an iterator + // without acquiring mLock. private final CopyOnWriteArrayList<ISessionControllerCallbackHolder> mControllerCallbackHolders = new CopyOnWriteArrayList<>(); @@ -770,24 +771,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } playbackState = mPlaybackState; } - Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null; - for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { - try { - holder.mCallback.onPlaybackStateChanged(playbackState); - } catch (DeadObjectException e) { - if (deadCallbackHolders == null) { - deadCallbackHolders = new ArrayList<>(); - } - deadCallbackHolders.add(holder); - logCallbackException("Removing dead callback in pushPlaybackStateUpdate", holder, - e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushPlaybackStateUpdate", holder, e); - } - } - if (deadCallbackHolders != null) { - removeControllerHoldersSafely(deadCallbackHolders); - } + performOnCallbackHolders( + "pushPlaybackStateUpdate", + holder -> holder.mCallback.onPlaybackStateChanged(playbackState)); } private void pushMetadataUpdate() { @@ -798,23 +784,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } metadata = mMetadata; } - Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null; - for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { - try { - holder.mCallback.onMetadataChanged(metadata); - } catch (DeadObjectException e) { - if (deadCallbackHolders == null) { - deadCallbackHolders = new ArrayList<>(); - } - deadCallbackHolders.add(holder); - logCallbackException("Removing dead callback in pushMetadataUpdate", holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushMetadataUpdate", holder, e); - } - } - if (deadCallbackHolders != null) { - removeControllerHoldersSafely(deadCallbackHolders); - } + performOnCallbackHolders( + "pushMetadataUpdate", holder -> holder.mCallback.onMetadataChanged(metadata)); } private void pushQueueUpdate() { @@ -825,31 +796,18 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } toSend = mQueue == null ? null : new ArrayList<>(mQueue); } - Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null; - for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { - ParceledListSlice<QueueItem> parcelableQueue = null; - if (toSend != null) { - parcelableQueue = new ParceledListSlice<>(toSend); - // Limit the size of initial Parcel to prevent binder buffer overflow - // as onQueueChanged is an async binder call. - parcelableQueue.setInlineCountLimit(1); - } - - try { - holder.mCallback.onQueueChanged(parcelableQueue); - } catch (DeadObjectException e) { - if (deadCallbackHolders == null) { - deadCallbackHolders = new ArrayList<>(); - } - deadCallbackHolders.add(holder); - logCallbackException("Removing dead callback in pushQueueUpdate", holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushQueueUpdate", holder, e); - } - } - if (deadCallbackHolders != null) { - removeControllerHoldersSafely(deadCallbackHolders); - } + performOnCallbackHolders( + "pushQueueUpdate", + holder -> { + ParceledListSlice<QueueItem> parcelableQueue = null; + if (toSend != null) { + parcelableQueue = new ParceledListSlice<>(toSend); + // Limit the size of initial Parcel to prevent binder buffer overflow + // as onQueueChanged is an async binder call. + parcelableQueue.setInlineCountLimit(1); + } + holder.mCallback.onQueueChanged(parcelableQueue); + }); } private void pushQueueTitleUpdate() { @@ -860,23 +818,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } queueTitle = mQueueTitle; } - Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null; - for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { - try { - holder.mCallback.onQueueTitleChanged(queueTitle); - } catch (DeadObjectException e) { - if (deadCallbackHolders == null) { - deadCallbackHolders = new ArrayList<>(); - } - deadCallbackHolders.add(holder); - logCallbackException("Removing dead callback in pushQueueTitleUpdate", holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushQueueTitleUpdate", holder, e); - } - } - if (deadCallbackHolders != null) { - removeControllerHoldersSafely(deadCallbackHolders); - } + performOnCallbackHolders( + "pushQueueTitleUpdate", holder -> holder.mCallback.onQueueTitleChanged(queueTitle)); } private void pushExtrasUpdate() { @@ -887,23 +830,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } extras = mExtras; } - Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null; - for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { - try { - holder.mCallback.onExtrasChanged(extras); - } catch (DeadObjectException e) { - if (deadCallbackHolders == null) { - deadCallbackHolders = new ArrayList<>(); - } - deadCallbackHolders.add(holder); - logCallbackException("Removing dead callback in pushExtrasUpdate", holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushExtrasUpdate", holder, e); - } - } - if (deadCallbackHolders != null) { - removeControllerHoldersSafely(deadCallbackHolders); - } + performOnCallbackHolders( + "pushExtrasUpdate", holder -> holder.mCallback.onExtrasChanged(extras)); } private void pushVolumeUpdate() { @@ -914,23 +842,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } info = getVolumeAttributes(); } - Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null; - for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { - try { - holder.mCallback.onVolumeInfoChanged(info); - } catch (DeadObjectException e) { - if (deadCallbackHolders == null) { - deadCallbackHolders = new ArrayList<>(); - } - deadCallbackHolders.add(holder); - logCallbackException("Removing dead callback in pushVolumeUpdate", holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushVolumeUpdate", holder, e); - } - } - if (deadCallbackHolders != null) { - removeControllerHoldersSafely(deadCallbackHolders); - } + performOnCallbackHolders( + "pushVolumeUpdate", holder -> holder.mCallback.onVolumeInfoChanged(info)); } private void pushEvent(String event, Bundle data) { @@ -939,23 +852,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR return; } } - Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null; - for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { - try { - holder.mCallback.onEvent(event, data); - } catch (DeadObjectException e) { - if (deadCallbackHolders == null) { - deadCallbackHolders = new ArrayList<>(); - } - deadCallbackHolders.add(holder); - logCallbackException("Removing dead callback in pushEvent", holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushEvent", holder, e); - } - } - if (deadCallbackHolders != null) { - removeControllerHoldersSafely(deadCallbackHolders); - } + performOnCallbackHolders("pushEvent", holder -> holder.mCallback.onEvent(event, data)); } private void pushSessionDestroyed() { @@ -966,20 +863,37 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR return; } } + performOnCallbackHolders( + "pushSessionDestroyed", + holder -> { + holder.mCallback.asBinder().unlinkToDeath(holder.mDeathMonitor, 0); + holder.mCallback.onSessionDestroyed(); + }); + // After notifying clear all listeners + synchronized (mLock) { + mControllerCallbackHolders.clear(); + } + } + + private interface ControllerCallbackCall { + + void performOn(ISessionControllerCallbackHolder holder) throws RemoteException; + } + + private void performOnCallbackHolders(String operationName, ControllerCallbackCall call) { + ArrayList<ISessionControllerCallbackHolder> deadCallbackHolders = new ArrayList<>(); for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) { try { - holder.mCallback.asBinder().unlinkToDeath(holder.mDeathMonitor, 0); - holder.mCallback.onSessionDestroyed(); - } catch (NoSuchElementException e) { - logCallbackException("error unlinking to binder death", holder, e); - } catch (DeadObjectException e) { - logCallbackException("Removing dead callback in pushSessionDestroyed", holder, e); - } catch (RemoteException e) { - logCallbackException("unexpected exception in pushSessionDestroyed", holder, e); + call.performOn(holder); + } catch (RemoteException | NoSuchElementException exception) { + deadCallbackHolders.add(holder); + logCallbackException( + "Exception while executing: " + operationName, holder, exception); } } - // After notifying clear all listeners - removeControllerHoldersSafely(null); + synchronized (mLock) { + mControllerCallbackHolders.removeAll(deadCallbackHolders); + } } private PlaybackState getStateWithUpdatedPosition() { @@ -1027,17 +941,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR return -1; } - private void removeControllerHoldersSafely( - Collection<ISessionControllerCallbackHolder> holders) { - synchronized (mLock) { - if (holders == null) { - mControllerCallbackHolders.clear(); - } else { - mControllerCallbackHolders.removeAll(holders); - } - } - } - private PlaybackInfo getVolumeAttributes() { int volumeType; AudioAttributes attributes; diff --git a/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING b/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING index c091b8e68236..eb91a72c127a 100644 --- a/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING +++ b/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING @@ -5,12 +5,7 @@ }, { "name": "CtsLocationFineTestCases", - "options": [ - { - // TODO: Wait for test to deflake - b/293934372 - "exclude-filter":"android.location.cts.fine.ScanningSettingsTest" - } - ] + "options": [] }, { "name": "CtsLocationNoneTestCases" diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 93f26aefb692..93f26aefb692 100644 --- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java index 519c0edfc532..519c0edfc532 100644 --- a/packages/CrashRecovery/services/java/com/android/server/rollback/WatchdogRollbackLogger.java +++ b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java diff --git a/services/core/java/com/android/server/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java index 10e868d06766..c1d92cffe1a7 100644 --- a/services/core/java/com/android/server/tracing/TracingServiceProxy.java +++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java @@ -119,8 +119,13 @@ public class TracingServiceProxy extends SystemService { } @Override - public void onStart() { - publishBinderService(TRACING_SERVICE_PROXY_BINDER_NAME, mTracingServiceProxy); + public void onStart() {} + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { + publishBinderService(TRACING_SERVICE_PROXY_BINDER_NAME, mTracingServiceProxy); + } } private void notifyTraceur(boolean sessionStolen) { diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java index 4a81c95f0b8f..440d2514537c 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java @@ -89,8 +89,34 @@ public class CasResource { * @param ownerId the removing client id of the owner. */ public void removeOwner(int ownerId) { - mAvailableSessionNum += mOwnerClientIdsToSessionNum.get(ownerId); - mOwnerClientIdsToSessionNum.remove(ownerId); + if (mOwnerClientIdsToSessionNum.containsKey(ownerId)) { + mAvailableSessionNum += mOwnerClientIdsToSessionNum.get(ownerId); + mOwnerClientIdsToSessionNum.remove(ownerId); + } + } + + /** + * Remove a single session from resource + * + * @param ownerId the client Id of the owner of the session + */ + public void removeSession(int ownerId) { + if (mOwnerClientIdsToSessionNum.containsKey(ownerId)) { + int sessionNum = mOwnerClientIdsToSessionNum.get(ownerId); + if (sessionNum > 0) { + mOwnerClientIdsToSessionNum.put(ownerId, --sessionNum); + mAvailableSessionNum++; + } + } + } + + /** + * Check if there are any open sessions owned by a client + * + * @param ownerId the client Id of the owner of the sessions + */ + public boolean hasOpenSessions(int ownerId) { + return mOwnerClientIdsToSessionNum.get(ownerId) > 0; } public Set<Integer> getOwnerClientIds() { diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index cddc79db6106..0afb049d31c7 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -1924,11 +1924,13 @@ public class TunerResourceManagerService extends SystemService implements IBinde ownerProfile.useCiCam(grantingId); } - private void updateCasClientMappingOnRelease( - @NonNull CasResource releasingCas, int ownerClientId) { - ClientProfile ownerProfile = getClientProfile(ownerClientId); - releasingCas.removeOwner(ownerClientId); - ownerProfile.releaseCas(); + private void updateCasClientMappingOnRelease(@NonNull CasResource cas, int ownerClientId) { + cas.removeSession(ownerClientId); + if (!cas.hasOpenSessions(ownerClientId)) { + ClientProfile ownerProfile = getClientProfile(ownerClientId); + cas.removeOwner(ownerClientId); + ownerProfile.releaseCas(); + } } private void updateCiCamClientMappingOnRelease( diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java index 1383708d8a5c..6a4c9c26d314 100644 --- a/services/core/java/com/android/server/vcn/VcnContext.java +++ b/services/core/java/com/android/server/vcn/VcnContext.java @@ -18,6 +18,7 @@ package com.android.server.vcn; import android.annotation.NonNull; import android.content.Context; +import android.net.IpSecTransformState; import android.net.vcn.FeatureFlags; import android.net.vcn.FeatureFlagsImpl; import android.os.Looper; @@ -34,7 +35,6 @@ public class VcnContext { @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final FeatureFlags mFeatureFlags; - @NonNull private final android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -49,7 +49,6 @@ public class VcnContext { // Auto-generated class mFeatureFlags = new FeatureFlagsImpl(); - mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl(); } @NonNull @@ -76,7 +75,16 @@ public class VcnContext { } public boolean isFlagIpSecTransformStateEnabled() { - return mCoreNetFeatureFlags.ipsecTransformState(); + // TODO: b/328844044: Ideally this code should gate the behavior by checking the + // android.net.platform.flags.ipsec_transform_state flag but that flag is not accessible + // right now. We should either update the code when the flag is accessible or remove the + // legacy behavior after VIC SDK finalization + try { + new IpSecTransformState.Builder(); + return true; + } catch (Exception e) { + return false; + } } @NonNull diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index ed9fa65dee15..36192537493a 100644 --- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -16,8 +16,10 @@ package com.android.server.vcn.routeselection; +import static com.android.internal.annotations.VisibleForTesting.Visibility; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -38,6 +40,10 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.VcnContext; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.BitSet; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -56,8 +62,51 @@ import java.util.concurrent.TimeUnit; public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final String TAG = IpSecPacketLossDetector.class.getSimpleName(); + private static final int PACKET_LOSS_PERCENT_UNAVAILABLE = -1; + + // Ignore the packet loss detection result if the expected packet number is smaller than 10. + // Solarwinds NPM uses 10 ICMP echos to calculate packet loss rate (as per + // https://thwack.solarwinds.com/products/network-performance-monitor-npm/f/forum/63829/how-is-packet-loss-calculated) @VisibleForTesting(visibility = Visibility.PRIVATE) - static final int PACKET_LOSS_UNAVALAIBLE = -1; + static final int MIN_VALID_EXPECTED_RX_PACKET_NUM = 10; + + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"PACKET_LOSS_"}, + value = { + PACKET_LOSS_RATE_VALID, + PACKET_LOSS_RATE_INVALID, + PACKET_LOSS_UNUSUAL_SEQ_NUM_LEAP, + }) + @Target({ElementType.TYPE_USE}) + private @interface PacketLossResultType {} + + /** Indicates a valid packet loss rate is available */ + private static final int PACKET_LOSS_RATE_VALID = 0; + + /** + * Indicates that the detector cannot get a valid packet loss rate due to one of the following + * reasons: + * + * <ul> + * <li>The replay window did not proceed and thus all packets might have been delivered out of + * order + * <li>The expected received packet number is too small and thus the detection result is not + * reliable + * <li>There are unexpected errors + * </ul> + */ + private static final int PACKET_LOSS_RATE_INVALID = 1; + + /** + * The sequence number increase is unusually large and might be caused an intentional leap on + * the server's downlink + * + * <p>Inbound sequence number will not always increase consecutively. During load balancing the + * server might add a big leap on the sequence number intentionally. In such case a high packet + * loss rate does not always indicate a lossy network + */ + private static final int PACKET_LOSS_UNUSUAL_SEQ_NUM_LEAP = 2; // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and @@ -68,8 +117,12 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static final int POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT = 20; + // By default, there's no maximum limit enforced + private static final int MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED = -1; + private long mPollIpSecStateIntervalMs; - private final int mPacketLossRatePercentThreshold; + private int mPacketLossRatePercentThreshold; + private int mMaxSeqNumIncreasePerSecond; @NonNull private final Handler mHandler; @NonNull private final PowerManager mPowerManager; @@ -108,6 +161,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); + mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); // Register for system broadcasts to monitor idle mode change final IntentFilter intentFilter = new IntentFilter(); @@ -172,6 +226,24 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { return IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + static int getMaxSeqNumIncreasePerSecond(@Nullable PersistableBundleWrapper carrierConfig) { + int maxSeqNumIncrease = MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED; + if (Flags.handleSeqNumLeap() && carrierConfig != null) { + maxSeqNumIncrease = + carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY, + MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED); + } + + if (maxSeqNumIncrease < MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) { + logE(TAG, "Invalid value of MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY " + maxSeqNumIncrease); + return MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED; + } + + return maxSeqNumIncrease; + } + @Override protected void onSelectedUnderlyingNetworkChanged() { if (!isSelectedUnderlyingNetwork()) { @@ -207,6 +279,11 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { // The already scheduled event will not be affected. The followup events will be scheduled // with the new interval mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); + + if (Flags.handleSeqNumLeap()) { + mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); + mMaxSeqNumIncreasePerSecond = getMaxSeqNumIncreasePerSecond(carrierConfig); + } } @Override @@ -307,30 +384,40 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { return; } - final int packetLossRate = + final PacketLossCalculationResult calculateResult = mPacketLossCalculator.getPacketLossRatePercentage( - mLastIpSecTransformState, state, getLogPrefix()); + mLastIpSecTransformState, + state, + mMaxSeqNumIncreasePerSecond, + getLogPrefix()); - if (packetLossRate == PACKET_LOSS_UNAVALAIBLE) { + if (calculateResult.getResultType() == PACKET_LOSS_RATE_INVALID) { return; } final String logMsg = - "packetLossRate: " - + packetLossRate + "calculateResult: " + + calculateResult + "% in the past " + (state.getTimestampMillis() - mLastIpSecTransformState.getTimestampMillis()) + "ms"; mLastIpSecTransformState = state; - if (packetLossRate < mPacketLossRatePercentThreshold) { + if (calculateResult.getPacketLossRatePercent() < mPacketLossRatePercentThreshold) { logV(logMsg); + + // In both "valid" or "unusual_seq_num_leap" cases, notify that the network has passed + // the validation onValidationResultReceivedInternal(false /* isFailed */); } else { logInfo(logMsg); - onValidationResultReceivedInternal(true /* isFailed */); + if (calculateResult.getResultType() == PACKET_LOSS_RATE_VALID) { + onValidationResultReceivedInternal(true /* isFailed */); + } + + // In both "valid" or "unusual_seq_num_leap" cases, trigger network validation if (Flags.validateNetworkOnIpsecLoss()) { // Trigger re-validation of the underlying network; if it fails, the VCN will // attempt to migrate away. @@ -343,9 +430,10 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { @VisibleForTesting(visibility = Visibility.PRIVATE) public static class PacketLossCalculator { /** Calculate the packet loss rate between two timestamps */ - public int getPacketLossRatePercentage( + public PacketLossCalculationResult getPacketLossRatePercentage( @NonNull IpSecTransformState oldState, @NonNull IpSecTransformState newState, + int maxSeqNumIncreasePerSecond, String logPrefix) { logVIpSecTransform("oldState", oldState, logPrefix); logVIpSecTransform("newState", newState, logPrefix); @@ -359,7 +447,23 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { if (oldSeqHi == newSeqHi || newSeqHi < replayWindowSize) { // The replay window did not proceed and all packets might have been delivered out // of order - return PACKET_LOSS_UNAVALAIBLE; + return PacketLossCalculationResult.invalid(); + } + + boolean isUnusualSeqNumLeap = false; + + // Handle sequence number leap + if (Flags.handleSeqNumLeap() + && maxSeqNumIncreasePerSecond != MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED) { + final long timeDiffMillis = + newState.getTimestampMillis() - oldState.getTimestampMillis(); + final long maxSeqNumIncrease = timeDiffMillis * maxSeqNumIncreasePerSecond / 1000; + + // Sequence numbers are unsigned 32-bit values. If maxSeqNumIncrease overflows, + // isUnusualSeqNumLeap can never be true. + if (maxSeqNumIncrease >= 0 && newSeqHi - oldSeqHi >= maxSeqNumIncrease) { + isUnusualSeqNumLeap = true; + } } // Get the expected packet count by assuming there is no packet loss. In this case, SA @@ -381,15 +485,23 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { + " actualPktCntDiff: " + actualPktCntDiff); + if (Flags.handleSeqNumLeap() && expectedPktCntDiff < MIN_VALID_EXPECTED_RX_PACKET_NUM) { + // The sample size is too small to ensure a reliable detection result + return PacketLossCalculationResult.invalid(); + } + if (expectedPktCntDiff < 0 || expectedPktCntDiff == 0 || actualPktCntDiff < 0 || actualPktCntDiff > expectedPktCntDiff) { logWtf(TAG, "Impossible values for expectedPktCntDiff or" + " actualPktCntDiff"); - return PACKET_LOSS_UNAVALAIBLE; + return PacketLossCalculationResult.invalid(); } - return 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff); + final int percent = 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff); + return isUnusualSeqNumLeap + ? PacketLossCalculationResult.unusualSeqNumLeap(percent) + : PacketLossCalculationResult.valid(percent); } } @@ -409,4 +521,64 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { private static long getPacketCntInReplayWindow(@NonNull IpSecTransformState state) { return BitSet.valueOf(state.getReplayBitmap()).cardinality(); } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class PacketLossCalculationResult { + @PacketLossResultType private final int mResultType; + private final int mPacketLossRatePercent; + + private PacketLossCalculationResult(@PacketLossResultType int type, int percent) { + mResultType = type; + mPacketLossRatePercent = percent; + } + + /** Construct an instance that contains a valid packet loss rate */ + public static PacketLossCalculationResult valid(int percent) { + return new PacketLossCalculationResult(PACKET_LOSS_RATE_VALID, percent); + } + + /** Construct an instance indicating the inability to get a valid packet loss rate */ + public static PacketLossCalculationResult invalid() { + return new PacketLossCalculationResult( + PACKET_LOSS_RATE_INVALID, PACKET_LOSS_PERCENT_UNAVAILABLE); + } + + /** Construct an instance indicating that there is an unusual sequence number leap */ + public static PacketLossCalculationResult unusualSeqNumLeap(int percent) { + return new PacketLossCalculationResult(PACKET_LOSS_UNUSUAL_SEQ_NUM_LEAP, percent); + } + + @PacketLossResultType + public int getResultType() { + return mResultType; + } + + public int getPacketLossRatePercent() { + return mPacketLossRatePercent; + } + + @Override + public int hashCode() { + return Objects.hash(mResultType, mPacketLossRatePercent); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof PacketLossCalculationResult)) { + return false; + } + + final PacketLossCalculationResult rhs = (PacketLossCalculationResult) other; + return mResultType == rhs.mResultType + && mPacketLossRatePercent == rhs.mPacketLossRatePercent; + } + + @Override + public String toString() { + return "mResultType: " + + mResultType + + " | mPacketLossRatePercent: " + + mPacketLossRatePercent; + } + } } diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java index a1b212f8d3d7..b9b10606a188 100644 --- a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java +++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -272,6 +272,11 @@ public abstract class NetworkMetricMonitor implements AutoCloseable { } } + protected static void logE(String className, String msgWithPrefix) { + Slog.w(className, msgWithPrefix); + LOCAL_LOG.log("[ERROR ] " + className + msgWithPrefix); + } + protected static void logWtf(String className, String msgWithPrefix) { Slog.wtf(className, msgWithPrefix); LOCAL_LOG.log("[WTF ] " + className + msgWithPrefix); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 57939bc4f348..b8777870b565 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -896,8 +896,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void grantInputChannel(int displayId, SurfaceControl surface, - IBinder clientToken, IBinder hostInputToken, int flags, int privateFlags, int type, - int inputFeatures, IBinder windowToken, IBinder inputTransferToken, + IBinder clientToken, IBinder hostInputToken, int flags, int privateFlags, + int inputFeatures, int type, IBinder windowToken, IBinder inputTransferToken, String inputHandleName, InputChannel outInputChannel) { if (hostInputToken == null && !mCanAddInternalSystemWindow) { // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to @@ -909,7 +909,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { try { mService.grantInputChannel(this, mUid, mPid, displayId, surface, clientToken, hostInputToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0, - type, inputFeatures, windowToken, inputTransferToken, inputHandleName, + inputFeatures, type, windowToken, inputTransferToken, inputHandleName, outInputChannel); } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/core/jni/linux/usb/f_accessory.h b/services/core/jni/linux/usb/f_accessory.h new file mode 100644 index 000000000000..abd864cabc5d --- /dev/null +++ b/services/core/jni/linux/usb/f_accessory.h @@ -0,0 +1,34 @@ +/* + * This file is auto-generated. Modifications will be lost. + * + * See https://android.googlesource.com/platform/bionic/+/master/libc/kernel/ + * for more information. + */ +#ifndef _UAPI_LINUX_USB_F_ACCESSORY_H +#define _UAPI_LINUX_USB_F_ACCESSORY_H +#define USB_ACCESSORY_VENDOR_ID 0x18D1 +#define USB_ACCESSORY_PRODUCT_ID 0x2D00 +#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01 +#define ACCESSORY_STRING_MANUFACTURER 0 +#define ACCESSORY_STRING_MODEL 1 +#define ACCESSORY_STRING_DESCRIPTION 2 +#define ACCESSORY_STRING_VERSION 3 +#define ACCESSORY_STRING_URI 4 +#define ACCESSORY_STRING_SERIAL 5 +#define ACCESSORY_GET_PROTOCOL 51 +#define ACCESSORY_SEND_STRING 52 +#define ACCESSORY_START 53 +#define ACCESSORY_REGISTER_HID 54 +#define ACCESSORY_UNREGISTER_HID 55 +#define ACCESSORY_SET_HID_REPORT_DESC 56 +#define ACCESSORY_SEND_HID_EVENT 57 +#define ACCESSORY_SET_AUDIO_MODE 58 +#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256]) +#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256]) +#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[256]) +#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256]) +#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256]) +#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256]) +#define ACCESSORY_IS_START_REQUESTED _IO('M', 7) +#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8) +#endif diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java index f3b164c6501c..f4c44051c942 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java @@ -203,6 +203,9 @@ public class OverlayPackagesProvider { } catch (PackageManager.NameNotFoundException e) { return false; } + if (packageInfo.applicationInfo == null || packageInfo.applicationInfo.metaData == null) { + return false; + } final String metadataKey = sActionToMetadataKeyMap.get(provisioningAction); return packageInfo.applicationInfo.metaData.getBoolean(metadataKey); } diff --git a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING index 861562d11f10..305108ea0229 100644 --- a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING +++ b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING @@ -1,31 +1,11 @@ { "presubmit": [ { - "name": "FrameworksServicesTests", - "options": [ - { - "include-filter": "com.android.server.pm." - }, - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - }, - { - "exclude-annotation": "org.junit.Ignore" - } - ] + "name": "FrameworksServicesTests_pm_presubmit" } ], "postsubmit": [ { - // Presubmit is intentional here while testing with SLO checker. - // Tests are flaky, waiting to bypass. - "name": "FrameworksServicesTests_pm_presubmit" - }, - { - // Leave postsubmit here when migrating "name": "FrameworksServicesTests_pm_postsubmit" } ] diff --git a/tests/OneMedia/Android.bp b/tests/OneMedia/Android.bp index 5c7317735bc7..a43cd39f0dcb 100644 --- a/tests/OneMedia/Android.bp +++ b/tests/OneMedia/Android.bp @@ -16,6 +16,7 @@ android_app { platform_apis: true, certificate: "platform", libs: ["org.apache.http.legacy"], + optional_uses_libs: ["org.apache.http.legacy"], optimize: { enabled: false, }, diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 1fdf97a4c821..093923f3ed53 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -45,13 +45,13 @@ import android.os.test.TestLooper; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.DeviceConfig; import android.util.AtomicFile; +import android.util.LongArrayQueue; import android.util.Xml; -import android.utils.LongArrayQueue; -import android.utils.XmlUtils; import androidx.test.InstrumentationRegistry; import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.PackageWatchdog.HealthCheckState; diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index fdf8fb8d3c41..c8b60e5c335f 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -17,9 +17,11 @@ package com.android.server.vcn.routeselection; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY; +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY; import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; -import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.PACKET_LOSS_UNAVALAIBLE; +import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.MIN_VALID_EXPECTED_RX_PACKET_NUM; +import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.getMaxSeqNumIncreasePerSecond; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; @@ -44,6 +46,7 @@ import android.net.IpSecTransformState; import android.os.OutcomeReceiver; import android.os.PowerManager; +import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculationResult; import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator; import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper; import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; @@ -65,6 +68,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { private static final int REPLAY_BITMAP_LEN_BYTE = 512; private static final int REPLAY_BITMAP_LEN_BIT = REPLAY_BITMAP_LEN_BYTE * 8; private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD = 5; + private static final int MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED = -1; private static final long POLL_IPSEC_STATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(30L); @Mock private IpSecTransformWrapper mIpSecTransform; @@ -91,6 +95,9 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY), anyInt())) .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD); + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY), anyInt())) + .thenReturn(MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED); when(mDependencies.getPacketLossCalculator()).thenReturn(mPacketLossCalculator); @@ -112,6 +119,20 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { .build(); } + private static IpSecTransformState newNextTransformState( + IpSecTransformState before, + long timeDiffMillis, + long rxSeqNoDiff, + long packtCountDiff, + int packetInWin) { + return new IpSecTransformState.Builder() + .setTimestampMillis(before.getTimestampMillis() + timeDiffMillis) + .setRxHighestSequenceNumber(before.getRxHighestSequenceNumber() + rxSeqNoDiff) + .setPacketCount(before.getPacketCount() + packtCountDiff) + .setReplayBitmap(newReplayBitmap(packetInWin)) + .build(); + } + private static byte[] newReplayBitmap(int receivedPktCnt) { final BitSet bitSet = new BitSet(REPLAY_BITMAP_LEN_BIT); for (int i = 0; i < receivedPktCnt; i++) { @@ -165,7 +186,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { // Verify the first polled state is stored assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); verify(mPacketLossCalculator, never()) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); // Verify next poll is scheduled assertNull(mTestLooper.nextMessage()); @@ -278,7 +299,7 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { xfrmStateReceiver.onResult(newTransformState(1, 1, newReplayBitmap(1))); verify(mPacketLossCalculator, never()) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); } @Test @@ -289,17 +310,19 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { xfrmStateReceiver.onError(new RuntimeException("Test")); verify(mPacketLossCalculator, never()) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); } private void checkHandleLossRate( - int mockPacketLossRate, boolean isLastStateExpectedToUpdate, boolean isCallbackExpected) + PacketLossCalculationResult mockPacketLossRate, + boolean isLastStateExpectedToUpdate, + boolean isCallbackExpected) throws Exception { final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver = startMonitorAndCaptureStateReceiver(); doReturn(mockPacketLossRate) .when(mPacketLossCalculator) - .getPacketLossRatePercentage(any(), any(), anyString()); + .getPacketLossRatePercentage(any(), any(), anyInt(), anyString()); // Mock receiving two states with mTransformStateInitial and an arbitrary transformNew final IpSecTransformState transformNew = newTransformState(1, 1, newReplayBitmap(1)); @@ -309,7 +332,10 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { // Verifications verify(mPacketLossCalculator) .getPacketLossRatePercentage( - eq(mTransformStateInitial), eq(transformNew), anyString()); + eq(mTransformStateInitial), + eq(transformNew), + eq(MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED), + anyString()); if (isLastStateExpectedToUpdate) { assertEquals(transformNew, mIpSecPacketLossDetector.getLastTransformState()); @@ -327,30 +353,53 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { @Test public void testHandleLossRate_validationPass() throws Exception { checkHandleLossRate( - 2, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + PacketLossCalculationResult.valid(2), + true /* isLastStateExpectedToUpdate */, + true /* isCallbackExpected */); } @Test public void testHandleLossRate_validationFail() throws Exception { checkHandleLossRate( - 22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + PacketLossCalculationResult.valid(22), + true /* isLastStateExpectedToUpdate */, + true /* isCallbackExpected */); verify(mConnectivityManager).reportNetworkConnectivity(mNetwork, false); } @Test public void testHandleLossRate_resultUnavalaible() throws Exception { checkHandleLossRate( - PACKET_LOSS_UNAVALAIBLE, + PacketLossCalculationResult.invalid(), false /* isLastStateExpectedToUpdate */, false /* isCallbackExpected */); } + @Test + public void testHandleLossRate_unusualSeqNumLeap_highLossRate() throws Exception { + checkHandleLossRate( + PacketLossCalculationResult.unusualSeqNumLeap(22), + true /* isLastStateExpectedToUpdate */, + false /* isCallbackExpected */); + } + + @Test + public void testHandleLossRate_unusualSeqNumLeap_lowLossRate() throws Exception { + checkHandleLossRate( + PacketLossCalculationResult.unusualSeqNumLeap(2), + true /* isLastStateExpectedToUpdate */, + true /* isCallbackExpected */); + } + private void checkGetPacketLossRate( - IpSecTransformState oldState, IpSecTransformState newState, int expectedLossRate) + IpSecTransformState oldState, + IpSecTransformState newState, + PacketLossCalculationResult expectedLossRate) throws Exception { assertEquals( expectedLossRate, - mPacketLossCalculator.getPacketLossRatePercentage(oldState, newState, TAG)); + mPacketLossCalculator.getPacketLossRatePercentage( + oldState, newState, MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED, TAG)); } private void checkGetPacketLossRate( @@ -362,14 +411,45 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { throws Exception { final IpSecTransformState newState = newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin)); + checkGetPacketLossRate( + oldState, newState, PacketLossCalculationResult.valid(expectedDataLossRate)); + } + + private void checkGetPacketLossRate( + IpSecTransformState oldState, + int rxSeqNo, + int packetCount, + int packetInWin, + PacketLossCalculationResult expectedDataLossRate) + throws Exception { + final IpSecTransformState newState = + newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin)); checkGetPacketLossRate(oldState, newState, expectedDataLossRate); } @Test public void testGetPacketLossRate_replayWindowUnchanged() throws Exception { checkGetPacketLossRate( - mTransformStateInitial, mTransformStateInitial, PACKET_LOSS_UNAVALAIBLE); - checkGetPacketLossRate(mTransformStateInitial, 3000, 2000, 2000, PACKET_LOSS_UNAVALAIBLE); + mTransformStateInitial, + mTransformStateInitial, + PacketLossCalculationResult.invalid()); + checkGetPacketLossRate( + mTransformStateInitial, 3000, 2000, 2000, PacketLossCalculationResult.invalid()); + } + + @Test + public void testGetPacketLossRate_expectedPacketNumTooFew() throws Exception { + final int oldRxNo = 4096; + final int oldPktCnt = 4096; + final int pktCntDiff = MIN_VALID_EXPECTED_RX_PACKET_NUM - 1; + final byte[] bitmapReceiveAll = newReplayBitmap(4096); + + final IpSecTransformState oldState = + newTransformState(oldRxNo, oldPktCnt, bitmapReceiveAll); + final IpSecTransformState newState = + newTransformState(oldRxNo + pktCntDiff, oldPktCnt + pktCntDiff, bitmapReceiveAll); + + checkGetPacketLossRate(oldState, newState, PacketLossCalculationResult.invalid()); } @Test @@ -419,6 +499,45 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { checkGetPacketLossRate(oldState, 20000, 14000, 3000, 10); } + private void checkGetPktLossRate_unusualSeqNumLeap( + int maxSeqNumIncreasePerSecond, + int timeDiffMillis, + int rxSeqNoDiff, + PacketLossCalculationResult expected) + throws Exception { + final IpSecTransformState oldState = mTransformStateInitial; + final IpSecTransformState newState = + newNextTransformState( + oldState, + timeDiffMillis, + rxSeqNoDiff, + 1 /* packtCountDiff */, + 1 /* packetInWin */); + + assertEquals( + expected, + mPacketLossCalculator.getPacketLossRatePercentage( + oldState, newState, maxSeqNumIncreasePerSecond, TAG)); + } + + @Test + public void testGetPktLossRate_unusualSeqNumLeap() throws Exception { + checkGetPktLossRate_unusualSeqNumLeap( + 10000 /* maxSeqNumIncreasePerSecond */, + (int) TimeUnit.SECONDS.toMillis(2L), + 30000 /* rxSeqNoDiff */, + PacketLossCalculationResult.unusualSeqNumLeap(100)); + } + + @Test + public void testGetPktLossRate_unusualSeqNumLeap_smallSeqNumDiff() throws Exception { + checkGetPktLossRate_unusualSeqNumLeap( + 10000 /* maxSeqNumIncreasePerSecond */, + (int) TimeUnit.SECONDS.toMillis(2L), + 5000 /* rxSeqNoDiff */, + PacketLossCalculationResult.valid(100)); + } + // Verify the polling event is scheduled with expected delays private void verifyPollEventDelayAndScheduleNext(long expectedDelayMs) { if (expectedDelayMs > 0) { @@ -445,4 +564,24 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { // Verify the 3rd poll is scheduled with configured delay verifyPollEventDelayAndScheduleNext(POLL_IPSEC_STATE_INTERVAL_MS); } + + @Test + public void testGetMaxSeqNumIncreasePerSecond() throws Exception { + final int seqNumLeapNegative = 500_000; + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY), anyInt())) + .thenReturn(seqNumLeapNegative); + assertEquals(seqNumLeapNegative, getMaxSeqNumIncreasePerSecond(mCarrierConfig)); + } + + @Test + public void testGetMaxSeqNumIncreasePerSecond_negativeValue() throws Exception { + final int seqNumLeapNegative = -10; + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_MAX_SEQ_NUM_INCREASE_PER_SECOND_KEY), anyInt())) + .thenReturn(seqNumLeapNegative); + assertEquals( + MAX_SEQ_NUM_INCREASE_DEFAULT_DISABLED, + getMaxSeqNumIncreasePerSecond(mCarrierConfig)); + } } diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index af6daa17e223..edad67896e8e 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -107,7 +107,6 @@ public abstract class NetworkEvaluationTestBase { @Mock protected Context mContext; @Mock protected Network mNetwork; @Mock protected FeatureFlags mFeatureFlags; - @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags; @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock protected ConnectivityManager mConnectivityManager; @Mock protected TelephonyManager mTelephonyManager; @@ -123,6 +122,7 @@ public abstract class NetworkEvaluationTestBase { mSetFlagsRule.enableFlags(Flags.FLAG_VALIDATE_NETWORK_ON_IPSEC_LOSS); mSetFlagsRule.enableFlags(Flags.FLAG_EVALUATE_IPSEC_LOSS_ON_LP_NC_CHANGE); + mSetFlagsRule.enableFlags(Flags.FLAG_HANDLE_SEQ_NUM_LEAP); when(mNetwork.getNetId()).thenReturn(-1); diff --git a/tools/streaming_proto/java/java_proto_stream_code_generator.cpp b/tools/streaming_proto/java/java_proto_stream_code_generator.cpp index 9d61111fb5bd..be5c197b7c5b 100644 --- a/tools/streaming_proto/java/java_proto_stream_code_generator.cpp +++ b/tools/streaming_proto/java/java_proto_stream_code_generator.cpp @@ -18,11 +18,13 @@ #include <stdio.h> +#include <algorithm> #include <iomanip> #include <iostream> #include <map> #include <sstream> #include <string> +#include <unordered_set> #include "Errors.h" @@ -30,21 +32,39 @@ using namespace android::stream_proto; using namespace google::protobuf::io; using namespace std; +static bool outer_class_name_clashes_with_any_message(const string& outer_class_name, + const vector<DescriptorProto>& messages) { + return any_of(messages.cbegin(), messages.cend(), [&](const DescriptorProto& message) { + return message.name() == outer_class_name; + }); +} + /** * If the descriptor gives us a class name, use that. Otherwise make one up from * the filename of the .proto file. */ -static string make_outer_class_name(const FileDescriptorProto& file_descriptor) { +static string make_outer_class_name(const FileDescriptorProto& file_descriptor, + const vector<DescriptorProto>& messages) { string name = file_descriptor.options().java_outer_classname(); - if (name.size() == 0) { - name = to_camel_case(file_base_name(file_descriptor.name())); - if (name.size() == 0) { - ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE, - "Unable to make an outer class name for file: %s", - file_descriptor.name().c_str()); - name = "Unknown"; - } + if (!name.empty()) { + return name; } + + // Outer class and messages with the same name would result in invalid java (outer class and + // inner class cannot have same names). + // If the outer class name clashes with any message, let's append an "OuterClass" suffix. + // This behavior is consistent with the standard protoc. + name = to_camel_case(file_base_name(file_descriptor.name())); + while (outer_class_name_clashes_with_any_message(name, messages)) { + name += "OuterClass"; + } + + if (name.empty()) { + ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE, "Unable to make an outer class name for file: %s", + file_descriptor.name().c_str()); + name = "Unknown"; + } + return name; } @@ -149,6 +169,12 @@ static void write_message(stringstream& text, const DescriptorProto& message, write_field(text, message.field(i), indented); } + // Extensions + N = message.extension_size(); + for (int i = 0; i < N; i++) { + write_field(text, message.extension(i), indented); + } + text << indent << "}" << endl; text << endl; } @@ -165,7 +191,7 @@ static void write_file(CodeGeneratorResponse* response, const FileDescriptorProt stringstream text; string const package_name = make_java_package(file_descriptor); - string const outer_class_name = make_outer_class_name(file_descriptor); + string const outer_class_name = make_outer_class_name(file_descriptor, messages); text << "// Generated by protoc-gen-javastream. DO NOT MODIFY." << endl; text << "// source: " << file_descriptor.name() << endl << endl; @@ -214,7 +240,7 @@ static void write_file(CodeGeneratorResponse* response, const FileDescriptorProt */ static void write_multiple_files(CodeGeneratorResponse* response, const FileDescriptorProto& file_descriptor, - set<string> messages_to_compile) { + const unordered_set<string>& messages_allowlist) { // If there is anything to put in the outer class file, create one if (file_descriptor.enum_type_size() > 0) { vector<EnumDescriptorProto> enums; @@ -222,7 +248,7 @@ static void write_multiple_files(CodeGeneratorResponse* response, for (int i = 0; i < N; i++) { auto enum_full_name = file_descriptor.package() + "." + file_descriptor.enum_type(i).name(); - if (!messages_to_compile.empty() && !messages_to_compile.count(enum_full_name)) { + if (!messages_allowlist.empty() && !messages_allowlist.count(enum_full_name)) { continue; } enums.push_back(file_descriptor.enum_type(i)); @@ -230,9 +256,10 @@ static void write_multiple_files(CodeGeneratorResponse* response, vector<DescriptorProto> messages; - if (messages_to_compile.empty() || !enums.empty()) { + if (messages_allowlist.empty() || !enums.empty()) { write_file(response, file_descriptor, - make_file_name(file_descriptor, make_outer_class_name(file_descriptor)), + make_file_name(file_descriptor, + make_outer_class_name(file_descriptor, messages)), true, enums, messages); } } @@ -246,12 +273,12 @@ static void write_multiple_files(CodeGeneratorResponse* response, auto message_full_name = file_descriptor.package() + "." + file_descriptor.message_type(i).name(); - if (!messages_to_compile.empty() && !messages_to_compile.count(message_full_name)) { + if (!messages_allowlist.empty() && !messages_allowlist.count(message_full_name)) { continue; } messages.push_back(file_descriptor.message_type(i)); - if (messages_to_compile.empty() || !messages.empty()) { + if (messages_allowlist.empty() || !messages.empty()) { write_file(response, file_descriptor, make_file_name(file_descriptor, file_descriptor.message_type(i).name()), false, enums, messages); @@ -261,14 +288,14 @@ static void write_multiple_files(CodeGeneratorResponse* response, static void write_single_file(CodeGeneratorResponse* response, const FileDescriptorProto& file_descriptor, - set<string> messages_to_compile) { + const unordered_set<string>& messages_allowlist) { int N; vector<EnumDescriptorProto> enums; N = file_descriptor.enum_type_size(); for (int i = 0; i < N; i++) { auto enum_full_name = file_descriptor.package() + "." + file_descriptor.enum_type(i).name(); - if (!messages_to_compile.empty() && !messages_to_compile.count(enum_full_name)) { + if (!messages_allowlist.empty() && !messages_allowlist.count(enum_full_name)) { continue; } @@ -281,22 +308,23 @@ static void write_single_file(CodeGeneratorResponse* response, auto message_full_name = file_descriptor.package() + "." + file_descriptor.message_type(i).name(); - if (!messages_to_compile.empty() && !messages_to_compile.count(message_full_name)) { + if (!messages_allowlist.empty() && !messages_allowlist.count(message_full_name)) { continue; } messages.push_back(file_descriptor.message_type(i)); } - if (messages_to_compile.empty() || !enums.empty() || !messages.empty()) { + if (messages_allowlist.empty() || !enums.empty() || !messages.empty()) { write_file(response, file_descriptor, - make_file_name(file_descriptor, make_outer_class_name(file_descriptor)), true, - enums, messages); + make_file_name(file_descriptor, + make_outer_class_name(file_descriptor, messages)), + true, enums, messages); } } static void parse_args_string(stringstream args_string_stream, - set<string>* messages_to_compile_out) { + unordered_set<string>& messages_allowlist_out) { string line; while (getline(args_string_stream, line, ';')) { stringstream line_ss(line); @@ -305,7 +333,7 @@ static void parse_args_string(stringstream args_string_stream, if (arg_name == "include_filter") { string full_message_name; while (getline(line_ss, full_message_name, ',')) { - messages_to_compile_out->insert(full_message_name); + messages_allowlist_out.insert(full_message_name); } } else { ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE, "Unexpected argument '%s'.", arg_name.c_str()); @@ -316,10 +344,10 @@ static void parse_args_string(stringstream args_string_stream, CodeGeneratorResponse generate_java_protostream_code(CodeGeneratorRequest request) { CodeGeneratorResponse response; - set<string> messages_to_compile; + unordered_set<string> messages_allowlist; auto request_params = request.parameter(); if (!request_params.empty()) { - parse_args_string(stringstream(request_params), &messages_to_compile); + parse_args_string(stringstream(request_params), messages_allowlist); } // Build the files we need. @@ -328,9 +356,9 @@ CodeGeneratorResponse generate_java_protostream_code(CodeGeneratorRequest reques const FileDescriptorProto& file_descriptor = request.proto_file(i); if (should_generate_for_file(request, file_descriptor.name())) { if (file_descriptor.options().java_multiple_files()) { - write_multiple_files(&response, file_descriptor, messages_to_compile); + write_multiple_files(&response, file_descriptor, messages_allowlist); } else { - write_single_file(&response, file_descriptor, messages_to_compile); + write_single_file(&response, file_descriptor, messages_allowlist); } } } |