Merge "Fix empty anr file when process exit early" into main
diff --git a/apct-tests/perftests/packagemanager/AndroidTest.xml b/apct-tests/perftests/packagemanager/AndroidTest.xml
index c9d45a6..db938e4 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/api/StubLibraries.bp b/api/StubLibraries.bp
index 65ec4d4..3e277e8 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -54,34 +54,34 @@
baseline_file: ":non-updatable-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/public/api",
- dest: "android-non-updatable.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/public/api",
- dest: "android-non-updatable-removed.txt",
- },
- ],
soong_config_variables: {
release_hidden_api_exportable_stubs: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable.txt",
tag: ".exportable.api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".exportable.removed-api.txt",
},
],
conditions_default: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
},
],
@@ -134,34 +134,34 @@
baseline_file: ":non-updatable-system-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/system/api",
- dest: "android-non-updatable.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/system/api",
- dest: "android-non-updatable-removed.txt",
- },
- ],
soong_config_variables: {
release_hidden_api_exportable_stubs: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable.txt",
tag: ".exportable.api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".exportable.removed-api.txt",
},
],
conditions_default: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
},
],
@@ -189,56 +189,58 @@
baseline_file: ":non-updatable-test-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "android.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "removed.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "android-non-updatable.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "android-non-updatable-removed.txt",
- },
- ],
soong_config_variables: {
release_hidden_api_exportable_stubs: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
tag: ".exportable.api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "removed.txt",
tag: ".exportable.removed-api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable.txt",
tag: ".exportable.api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".exportable.removed-api.txt",
},
],
conditions_default: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
tag: ".api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "removed.txt",
tag: ".removed-api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
},
],
@@ -271,34 +273,34 @@
baseline_file: ":non-updatable-module-lib-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/module-lib/api",
- dest: "android-non-updatable.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/module-lib/api",
- dest: "android-non-updatable-removed.txt",
- },
- ],
soong_config_variables: {
release_hidden_api_exportable_stubs: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable.txt",
tag: ".exportable.api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".exportable.removed-api.txt",
},
],
conditions_default: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
},
],
diff --git a/api/coverage/tools/Android.bp b/api/coverage/tools/Android.bp
index 3e16912..caaca99 100644
--- a/api/coverage/tools/Android.bp
+++ b/api/coverage/tools/Android.bp
@@ -30,3 +30,24 @@
type: "full",
},
}
+
+java_test_host {
+ name: "extract-flagged-apis-test",
+ srcs: ["ExtractFlaggedApisTest.kt"],
+ libs: [
+ "extract_flagged_apis_proto",
+ "junit",
+ "libprotobuf-java-full",
+ ],
+ static_libs: [
+ "truth",
+ "truth-liteproto-extension",
+ "truth-proto-extension",
+ ],
+ data: [
+ ":extract-flagged-apis",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index d5adfd0..5efda98 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -17,6 +17,7 @@
package android.platform.coverage
import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.Item
import com.android.tools.metalava.model.MethodItem
import com.android.tools.metalava.model.text.ApiFile
import java.io.File
@@ -28,12 +29,10 @@
val builder = FlagApiMap.newBuilder()
for (pkg in cb.getPackages().packages) {
val packageName = pkg.qualifiedName()
- pkg.allClasses()
- .filter { it.methods().size > 0 }
- .forEach {
- extractFlaggedApisFromClass(it, it.methods(), packageName, builder)
- extractFlaggedApisFromClass(it, it.constructors(), packageName, builder)
- }
+ pkg.allClasses().forEach {
+ extractFlaggedApisFromClass(it, it.methods(), packageName, builder)
+ extractFlaggedApisFromClass(it, it.constructors(), packageName, builder)
+ }
}
val flagApiMap = builder.build()
FileWriter(args[1]).use { it.write(flagApiMap.toString()) }
@@ -45,20 +44,10 @@
packageName: String,
builder: FlagApiMap.Builder
) {
- val classFlag =
- classItem.modifiers
- .findAnnotation("android.annotation.FlaggedApi")
- ?.findAttribute("value")
- ?.value
- ?.value() as? String
+ if (methods.isEmpty()) return
+ val classFlag = getClassFlag(classItem)
for (method in methods) {
- val methodFlag =
- method.modifiers
- .findAnnotation("android.annotation.FlaggedApi")
- ?.findAttribute("value")
- ?.value
- ?.value() as? String
- ?: classFlag
+ val methodFlag = getFlagAnnotation(method) ?: classFlag
val api =
JavaMethod.newBuilder()
.setPackageName(packageName)
@@ -82,3 +71,23 @@
builder.putFlagToApi(flag, apis)
}
}
+
+fun getClassFlag(classItem: ClassItem): String? {
+ var classFlag = getFlagAnnotation(classItem)
+ var cur = classItem
+ // If a class is not an inner class, use its @FlaggedApi annotation value.
+ // Otherwise, use the flag value of the closest outer class that is annotated by @FlaggedApi.
+ while (cur.isInnerClass() && classFlag == null) {
+ cur = cur.parent() as ClassItem
+ classFlag = getFlagAnnotation(cur)
+ }
+ return classFlag
+}
+
+fun getFlagAnnotation(item: Item): String? {
+ return item.modifiers
+ .findAnnotation("android.annotation.FlaggedApi")
+ ?.findAttribute("value")
+ ?.value
+ ?.value() as? String
+}
diff --git a/api/coverage/tools/ExtractFlaggedApisTest.kt b/api/coverage/tools/ExtractFlaggedApisTest.kt
new file mode 100644
index 0000000..427be36
--- /dev/null
+++ b/api/coverage/tools/ExtractFlaggedApisTest.kt
@@ -0,0 +1,238 @@
+/*
+ * 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.platform.coverage
+
+import com.google.common.truth.extensions.proto.ProtoTruth.assertThat
+import com.google.protobuf.TextFormat
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardOpenOption
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ExtractFlaggedApisTest {
+
+ companion object {
+ const val COMMAND = "java -jar extract-flagged-apis.jar %s %s"
+ }
+
+ private var apiTextFile: Path = Files.createTempFile("current", ".txt")
+ private var flagToApiMap: Path = Files.createTempFile("flag_api_map", ".textproto")
+
+ @Before
+ fun setup() {
+ apiTextFile = Files.createTempFile("current", ".txt")
+ flagToApiMap = Files.createTempFile("flag_api_map", ".textproto")
+ }
+
+ @After
+ fun cleanup() {
+ Files.deleteIfExists(apiTextFile)
+ Files.deleteIfExists(flagToApiMap)
+ }
+
+ @Test
+ fun extractFlaggedApis_onlyMethodFlag_useMethodFlag() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.net.ipsec.ike {
+ public final class IkeSession implements java.lang.AutoCloseable {
+ method @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public void dump(@NonNull java.io.PrintWriter);
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api =
+ JavaMethod.newBuilder()
+ .setPackageName("android.net.ipsec.ike")
+ .setClassName("IkeSession")
+ .setMethodName("dump")
+ api.addParameters("java.io.PrintWriter")
+ addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api")
+ assertThat(result).isEqualTo(expected.build())
+ }
+
+ @Test
+ fun extractFlaggedApis_onlyClassFlag_useClassFlag() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.net.ipsec.ike {
+ @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public final class IkeSession implements java.lang.AutoCloseable {
+ method public void dump(@NonNull java.io.PrintWriter);
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api =
+ JavaMethod.newBuilder()
+ .setPackageName("android.net.ipsec.ike")
+ .setClassName("IkeSession")
+ .setMethodName("dump")
+ api.addParameters("java.io.PrintWriter")
+ addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api")
+ assertThat(result).isEqualTo(expected.build())
+ }
+
+ @Test
+ fun extractFlaggedApis_flaggedConstructorsAreFlaggedApis() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.app.pinner {
+ @FlaggedApi("android.app.pinner_service_client_api") public class PinnerServiceClient {
+ ctor @FlaggedApi("android.app.pinner_service_client_api") public PinnerServiceClient();
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api =
+ JavaMethod.newBuilder()
+ .setPackageName("android.app.pinner")
+ .setClassName("PinnerServiceClient")
+ .setMethodName("PinnerServiceClient")
+ addFlaggedApi(expected, api, "android.app.pinner_service_client_api")
+ assertThat(result).isEqualTo(expected.build())
+ }
+
+ @Test
+ fun extractFlaggedApis_unflaggedNestedClassShouldUseOuterClassFlag() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.location.provider {
+ @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public final class ForwardGeocodeRequest implements android.os.Parcelable {
+ method public int describeContents();
+ }
+ public static final class ForwardGeocodeRequest.Builder {
+ method @NonNull public android.location.provider.ForwardGeocodeRequest build();
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api1 =
+ JavaMethod.newBuilder()
+ .setPackageName("android.location.provider")
+ .setClassName("ForwardGeocodeRequest")
+ .setMethodName("describeContents")
+ addFlaggedApi(expected, api1, "Flags.FLAG_NEW_GEOCODER")
+ val api2 =
+ JavaMethod.newBuilder()
+ .setPackageName("android.location.provider")
+ .setClassName("ForwardGeocodeRequest.Builder")
+ .setMethodName("build")
+ addFlaggedApi(expected, api2, "Flags.FLAG_NEW_GEOCODER")
+ assertThat(result).ignoringRepeatedFieldOrder().isEqualTo(expected.build())
+ }
+
+ @Test
+ fun extractFlaggedApis_unflaggedNestedClassShouldUseOuterClassFlag_deeplyNested() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.package.xyz {
+ @FlaggedApi(outer_class_flag) public final class OuterClass {
+ method public int apiInOuterClass();
+ }
+ public final class OuterClass.Deeply.NestedClass {
+ method public void apiInNestedClass();
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api1 =
+ JavaMethod.newBuilder()
+ .setPackageName("android.package.xyz")
+ .setClassName("OuterClass")
+ .setMethodName("apiInOuterClass")
+ addFlaggedApi(expected, api1, "outer_class_flag")
+ val api2 =
+ JavaMethod.newBuilder()
+ .setPackageName("android.package.xyz")
+ .setClassName("OuterClass.Deeply.NestedClass")
+ .setMethodName("apiInNestedClass")
+ addFlaggedApi(expected, api2, "outer_class_flag")
+ assertThat(result).ignoringRepeatedFieldOrder().isEqualTo(expected.build())
+ }
+
+ private fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) {
+ if (builder.containsFlagToApi(flag)) {
+ val updatedApis =
+ builder.getFlagToApiOrThrow(flag).toBuilder().addJavaMethods(api).build()
+ builder.putFlagToApi(flag, updatedApis)
+ } else {
+ val apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
+ builder.putFlagToApi(flag, apis)
+ }
+ }
+
+ private fun createCommand(): Array<String> {
+ val command =
+ String.format(COMMAND, apiTextFile.toAbsolutePath(), flagToApiMap.toAbsolutePath())
+ return command.split(" ").toTypedArray()
+ }
+}
diff --git a/config/Android.bp b/config/Android.bp
index 6a6f848..dd681ca 100644
--- a/config/Android.bp
+++ b/config/Android.bp
@@ -33,3 +33,9 @@
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 48949f8..588396a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -31980,7 +31980,7 @@
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 1ac887b..5330fef 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -968,6 +968,7 @@
boolean autoStopProfiler;
boolean streamingOutput;
int mClockType;
+ int mProfilerOutputVersion;
boolean profiling;
boolean handlingProfiling;
public void setProfiler(ProfilerInfo profilerInfo) {
@@ -995,6 +996,7 @@
autoStopProfiler = profilerInfo.autoStopProfiler;
streamingOutput = profilerInfo.streamingOutput;
mClockType = profilerInfo.clockType;
+ mProfilerOutputVersion = profilerInfo.profilerOutputVersion;
}
public void startProfiling() {
if (profileFd == null || profiling) {
@@ -1002,9 +1004,11 @@
}
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 @@
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 f7a3d78..bcae22a 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -32,7 +32,8 @@
* {@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 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 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 @@
this.clockType = clockType;
this.agent = agent;
this.attachAgentDuringBind = attachAgentDuringBind;
+ this.profilerOutputVersion = profilerOutputVersion;
}
public ProfilerInfo(ProfilerInfo in) {
@@ -104,6 +115,7 @@
agent = in.agent;
attachAgentDuringBind = in.attachAgentDuringBind;
clockType = in.clockType;
+ profilerOutputVersion = in.profilerOutputVersion;
}
/**
@@ -125,13 +137,29 @@
}
/**
+ * 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 @@
out.writeString(agent);
out.writeBoolean(attachAgentDuringBind);
out.writeInt(clockType);
+ out.writeInt(profilerOutputVersion);
}
/** @hide */
@@ -186,6 +215,7 @@
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 @@
agent = in.readString();
attachAgentDuringBind = in.readBoolean();
clockType = in.readInt();
+ profilerOutputVersion = in.readInt();
}
@Override
@@ -226,9 +257,9 @@
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 @@
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/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index a51a740..d9a18d7 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -42,12 +42,6 @@
private static DdmHandleHello mInstance = new DdmHandleHello();
- private static final String[] FRAMEWORK_FEATURES = new String[] {
- "opengl-tracing",
- "view-hierarchy",
- "support_boot_stages"
- };
-
/* singleton, do not instantiate */
private DdmHandleHello() {}
@@ -193,22 +187,25 @@
if (false)
Log.v("ddm-heap", "Got feature list request");
- int size = 4 + 4 * (vmFeatures.length + FRAMEWORK_FEATURES.length);
- for (int i = vmFeatures.length-1; i >= 0; i--)
+ String[] fmFeatures = Debug.getFeatureList();
+ int size = 4 + 4 * (vmFeatures.length + fmFeatures.length);
+ for (int i = vmFeatures.length - 1; i >= 0; i--) {
size += vmFeatures[i].length() * 2;
- for (int i = FRAMEWORK_FEATURES.length-1; i>= 0; i--)
- size += FRAMEWORK_FEATURES[i].length() * 2;
+ }
+ for (int i = fmFeatures.length - 1; i >= 0; i--) {
+ size += fmFeatures[i].length() * 2;
+ }
ByteBuffer out = ByteBuffer.allocate(size);
out.order(ChunkHandler.CHUNK_ORDER);
- out.putInt(vmFeatures.length + FRAMEWORK_FEATURES.length);
+ out.putInt(vmFeatures.length + fmFeatures.length);
for (int i = vmFeatures.length-1; i >= 0; i--) {
out.putInt(vmFeatures[i].length());
putString(out, vmFeatures[i]);
}
- for (int i = FRAMEWORK_FEATURES.length-1; i >= 0; i--) {
- out.putInt(FRAMEWORK_FEATURES[i].length());
- putString(out, FRAMEWORK_FEATURES[i]);
+ for (int i = fmFeatures.length - 1; i >= 0; i--) {
+ out.putInt(fmFeatures[i].length());
+ putString(out, fmFeatures[i]);
}
return new Chunk(CHUNK_FEAT, out);
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 6246dd7..91cdf8d 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -124,6 +124,22 @@
"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 @@
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 e64823a..6fde398 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -34,4 +34,14 @@
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 d681a2c..d1531a1 100644
--- a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
@@ -162,12 +162,21 @@
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 5871717..a7d17f5 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 @@
/**
* 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/java/android/os/Debug.java b/core/java/android/os/Debug.java
index f785cca..a55398a 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -110,6 +110,12 @@
private static final String DEFAULT_TRACE_BODY = "dmtrace";
private static final String DEFAULT_TRACE_EXTENSION = ".trace";
+ private static final String[] FRAMEWORK_FEATURES = new String[] {
+ "opengl-tracing",
+ "view-hierarchy",
+ "support_boot_stages",
+ };
+
/**
* This class is used to retrieved various statistics about the memory mappings for this
* process. The returned info is broken down by dalvik, native, and other. All results are in kB.
@@ -1106,6 +1112,17 @@
}
/**
+ * Returns an array of strings that identify Framework features. This is
+ * used by DDMS to determine what sorts of operations the Framework can
+ * perform.
+ *
+ * @hide
+ */
+ public static String[] getFeatureList() {
+ return FRAMEWORK_FEATURES;
+ }
+
+ /**
* Change the JDWP port.
*
* @deprecated no longer needed or useful
diff --git a/core/java/android/os/OomKillRecord.java b/core/java/android/os/OomKillRecord.java
index ca1d49a..78fbce6 100644
--- a/core/java/android/os/OomKillRecord.java
+++ b/core/java/android/os/OomKillRecord.java
@@ -25,7 +25,7 @@
* Note that this class fields' should be equivalent to the struct
* <b>OomKill</b> inside
* <pre>
- * system/memory/libmeminfo/libmemevents/include/memevents.h
+ * system/memory/libmeminfo/libmemevents/include/memevents/bpf_types.h
* </pre>
*
* @hide
@@ -36,14 +36,27 @@
private int mUid;
private String mProcessName;
private short mOomScoreAdj;
+ private long mTotalVmInKb;
+ private long mAnonRssInKb;
+ private long mFileRssInKb;
+ private long mShmemRssInKb;
+ private long mPgTablesInKb;
public OomKillRecord(long timeStampInMillis, int pid, int uid,
- String processName, short oomScoreAdj) {
+ String processName, short oomScoreAdj,
+ long totalVmInKb, long anonRssInKb,
+ long fileRssInKb, long shmemRssInKb,
+ long pgTablesInKb) {
this.mTimeStampInMillis = timeStampInMillis;
this.mPid = pid;
this.mUid = uid;
this.mProcessName = processName;
this.mOomScoreAdj = oomScoreAdj;
+ this.mTotalVmInKb = totalVmInKb;
+ this.mAnonRssInKb = anonRssInKb;
+ this.mFileRssInKb = fileRssInKb;
+ this.mShmemRssInKb = shmemRssInKb;
+ this.mPgTablesInKb = pgTablesInKb;
}
/**
@@ -55,7 +68,8 @@
FrameworkStatsLog.write(
FrameworkStatsLog.KERNEL_OOM_KILL_OCCURRED,
mUid, mPid, mOomScoreAdj, mTimeStampInMillis,
- mProcessName);
+ mProcessName, mTotalVmInKb, mAnonRssInKb,
+ mFileRssInKb, mShmemRssInKb, mPgTablesInKb);
}
public long getTimestampMilli() {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 8c6bf79..6412ddb 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -21,6 +21,7 @@
config_namespace: "ANDROID",
bool_variables: [
"release_binder_death_recipient_weak_from_jni",
+ "release_package_libandroid_runtime_punch_holes",
],
properties: [
"cflags",
@@ -63,6 +64,9 @@
release_binder_death_recipient_weak_from_jni: {
cflags: ["-DBINDER_DEATH_RECIPIENT_WEAK_FROM_JNI"],
},
+ release_package_libandroid_runtime_punch_holes: {
+ cflags: ["-DENABLE_PUNCH_HOLES"],
+ },
},
cpp_std: "gnu++20",
@@ -120,6 +124,7 @@
srcs: [
"AndroidRuntime.cpp",
"com_android_internal_content_F2fsUtils.cpp",
+ "com_android_internal_content_FileSystemUtils.cpp",
"com_android_internal_content_NativeLibraryHelper.cpp",
"com_google_android_gles_jni_EGLImpl.cpp",
"com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp
new file mode 100644
index 0000000..01920de
--- /dev/null
+++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp
@@ -0,0 +1,329 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FileSystemUtils"
+
+#include "com_android_internal_content_FileSystemUtils.h"
+
+#include <android-base/file.h>
+#include <android-base/hex.h>
+#include <android-base/unique_fd.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <array>
+#include <fstream>
+#include <vector>
+
+using android::base::HexString;
+using android::base::ReadFullyAtOffset;
+
+namespace android {
+bool punchHoles(const char *filePath, const uint64_t offset,
+ const std::vector<Elf64_Phdr> &programHeaders) {
+ 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("Total number of LOAD segments %zu", programHeaders.size());
+
+ ALOGD("Size before punching holes st_blocks: %" PRIu64
+ ", st_blksize: %ld, st_size: %" PRIu64 "",
+ beforePunch.st_blocks, beforePunch.st_blksize,
+ static_cast<uint64_t>(beforePunch.st_size));
+ }
+
+ 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;
+ }
+
+ // read in chunks of 64KB
+ constexpr uint64_t kChunkSize = 64 * 1024;
+
+ // malloc is used to gracefully handle oom which might occur during the allocation of buffer.
+ // allocating using new or vector here results in oom/exception on failure where as malloc will
+ // return nullptr.
+ std::unique_ptr<uint8_t, decltype(&free)> buffer(static_cast<uint8_t *>(malloc(kChunkSize)),
+ &free);
+ if (buffer == nullptr) {
+ ALOGE("Failed to allocate read buffer");
+ return false;
+ }
+
+ for (size_t index = 0; programHeaders.size() >= 2 && index < programHeaders.size() - 1;
+ index++) {
+ // find LOAD segments from program headers, calculate padding and punch holes
+ uint64_t punchOffset;
+ if (__builtin_add_overflow(programHeaders[index].p_offset, programHeaders[index].p_filesz,
+ &punchOffset)) {
+ ALOGE("Overflow occurred when adding offset and filesize");
+ return false;
+ }
+
+ uint64_t punchLen;
+ if (__builtin_sub_overflow(programHeaders[index + 1].p_offset, punchOffset, &punchLen)) {
+ ALOGE("Overflow occurred when calculating length");
+ return false;
+ }
+
+ if (punchLen < blockSize) {
+ continue;
+ }
+
+ uint64_t punchStartOffset;
+ if (__builtin_add_overflow(offset, punchOffset, &punchStartOffset)) {
+ ALOGE("Overflow occurred when calculating length");
+ return false;
+ }
+
+ uint64_t position = punchStartOffset;
+ uint64_t endPosition;
+ if (__builtin_add_overflow(position, punchLen, &endPosition)) {
+ ALOGE("Overflow occurred when calculating length");
+ return false;
+ }
+
+ // Read content in kChunkSize and verify it is zero
+ while (position <= endPosition) {
+ uint64_t uncheckedChunkEnd;
+ if (__builtin_add_overflow(position, kChunkSize, &uncheckedChunkEnd)) {
+ ALOGE("Overflow occurred when calculating uncheckedChunkEnd");
+ return false;
+ }
+
+ uint64_t readLength;
+ if (__builtin_sub_overflow(std::min(uncheckedChunkEnd, endPosition), position,
+ &readLength)) {
+ ALOGE("Overflow occurred when calculating readLength");
+ return false;
+ }
+
+ if (!ReadFullyAtOffset(fd, buffer.get(), readLength, position)) {
+ ALOGE("Failed to read content to punch holes");
+ return false;
+ }
+
+ IF_ALOGD() {
+ ALOGD("Punching holes for length:%" PRIu64 " content which should be zero: %s",
+ readLength, HexString(buffer.get(), readLength).c_str());
+ }
+
+ bool isZero = std::all_of(buffer.get(), buffer.get() + readLength,
+ [](uint8_t i) constexpr { return i == 0; });
+ if (!isZero) {
+ ALOGE("Found non zero content while trying to punch hole. Skipping operation");
+ return false;
+ }
+
+ position = uncheckedChunkEnd;
+ }
+
+ // if we have a uncompressed file which is being opened from APK, use the offset to
+ // punch native lib inside Apk.
+ int result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, punchStartOffset,
+ punchLen);
+ if (result < 0) {
+ ALOGE("fallocate failed to punch hole, error:%d", errno);
+ return false;
+ }
+ }
+
+ 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("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;
+}
+
+bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
+ // Open Elf file
+ Elf64_Ehdr ehdr;
+ std::ifstream inputStream(filePath, std::ifstream::in);
+
+ // If this is a zip file, set the offset so that we can read elf file directly
+ inputStream.seekg(offset);
+ // read executable headers
+ inputStream.read((char *)&ehdr, sizeof(ehdr));
+ if (!inputStream.good()) {
+ return false;
+ }
+
+ // only consider elf64 for punching holes
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) {
+ ALOGW("Provided file is not ELF64");
+ return false;
+ }
+
+ // read the program headers from elf file
+ uint64_t programHeaderOffset = ehdr.e_phoff;
+ uint16_t programHeaderNum = ehdr.e_phnum;
+
+ IF_ALOGD() {
+ ALOGD("Punching holes in file: %s programHeaderOffset: %" PRIu64 " programHeaderNum: %hu",
+ filePath, programHeaderOffset, programHeaderNum);
+ }
+
+ // if this is a zip file, also consider elf offset inside a file
+ uint64_t phOffset;
+ if (__builtin_add_overflow(offset, programHeaderOffset, &phOffset)) {
+ ALOGE("Overflow occurred when calculating phOffset");
+ return false;
+ }
+ inputStream.seekg(phOffset);
+
+ std::vector<Elf64_Phdr> programHeaders;
+ for (int headerIndex = 0; headerIndex < programHeaderNum; headerIndex++) {
+ Elf64_Phdr header;
+ inputStream.read((char *)&header, sizeof(header));
+ if (!inputStream.good()) {
+ return false;
+ }
+
+ if (header.p_type != PT_LOAD) {
+ continue;
+ }
+ programHeaders.push_back(header);
+ }
+
+ 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
new file mode 100644
index 0000000..52445e2
--- /dev/null
+++ b/core/jni/com_android_internal_content_FileSystemUtils.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <sys/types.h>
+
+namespace android {
+
+/*
+ * This function deallocates space used by zero padding at the end of LOAD segments in given
+ * uncompressed ELF file. Read ELF headers and find out the offset and sizes of LOAD segments.
+ * [fallocate(2)](http://man7.org/linux/man-pages/man2/fallocate.2.html) is used to deallocate the
+ * zero ranges at the end of LOAD segments. If ELF file is present inside of ApK/Zip file, offset to
+ * the start of the ELF file should be provided.
+ */
+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 149e57a..9b8dab7 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>
@@ -36,6 +37,7 @@
#include <memory>
+#include "com_android_internal_content_FileSystemUtils.h"
#include "core_jni_helpers.h"
#define RS_BITCODE_SUFFIX ".bc"
@@ -144,8 +146,9 @@
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;
}
@@ -169,6 +172,21 @@
return INSTALL_FAILED_INVALID_APK;
}
+#ifdef ENABLE_PUNCH_HOLES
+ // if library is uncompressed, punch hole in it in place
+ if (!punchHolesInElf64(zipFile->getZipFileName(), offset)) {
+ ALOGW("Failed to punch uncompressed elf file :%s inside apk : %s at offset: "
+ "%" 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;
}
@@ -269,6 +287,25 @@
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 86261ec..9941b83 100644
--- a/core/proto/android/app/profilerinfo.proto
+++ b/core/proto/android/app/profilerinfo.proto
@@ -36,4 +36,5 @@
// 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/res/OWNERS b/core/res/OWNERS
index 6924248..3c2bc0d 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -4,7 +4,6 @@
cinek@google.com
dsandler@android.com
dsandler@google.com
-dupin@google.com
hackbod@android.com
hackbod@google.com
ilyamaty@google.com
@@ -46,7 +45,7 @@
# Wear
per-file res/*-watch/* = file:/WEAR_OWNERS
-# Peformance
+# Performance
per-file res/values/config.xml = file:/PERFORMANCE_OWNERS
per-file res/values/symbols.xml = file:/PERFORMANCE_OWNERS
@@ -60,3 +59,11 @@
# TV Input Framework
per-file res/values/config_tv_external_input_logging.xml = file:/services/core/java/com/android/server/tv/OWNERS
+
+# SysUi Color Team
+per-file res/values/colors.xml = arteiro@google.com
+per-file res/values/attrs.xml = arteiro@google.com
+per-file res/values/styles.xml = arteiro@google.com
+per-file res/values/symbols.xml = arteiro@google.com
+per-file res/values/themes_device_defaults.xml = arteiro@google.com
+per-file res/values/styles_material.xml = arteiro@google.com
\ No newline at end of file
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index c8625b9..9bb72d9 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -28,7 +28,7 @@
standard SMS rate. The user is warned when the destination phone number matches the
"pattern" or "premium" regexes, and does not match the "free" or "standard" regexes. -->
- <!-- Harmonised European Short Codes are 6 digit numbers starting with 116 (free helplines).
+ <!-- Harmonised European Short Codes are 7 digit numbers starting with 116 (free helplines).
Premium patterns include short codes from: http://aonebill.com/coverage&tariffs
and http://mobilcent.com/info-worldwide.asp and extracted from:
http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
@@ -39,8 +39,8 @@
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
- <!-- Argentina: 5 digits, known short codes listed -->
- <shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077|78887" />
+ <!-- Argentina: 6 digits, known short codes listed -->
+ <shortcode country="ar" pattern="\\d{1,6}" free="11711|28291|44077|78887|191289|39010" />
<!-- Armenia: 3-5 digits, emergency numbers 10[123] -->
<shortcode country="am" pattern="\\d{3,5}" premium="11[2456]1|3024" free="10[123]|71522|71512|71502" />
@@ -67,7 +67,7 @@
<shortcode country="bh" pattern="\\d{1,5}" free="81181|85999" />
<!-- Brazil: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000" />
+ <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000|2652" />
<!-- Belarus: 4 digits -->
<shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
@@ -163,7 +163,7 @@
<shortcode country="in" pattern="\\d{1,5}" free="59336|53969" />
<!-- Indonesia: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363|93457" />
+ <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363|93457|99265" />
<!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:
http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
@@ -172,6 +172,9 @@
<!-- Israel: 1-5 digits, known premium codes listed -->
<shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477|6681" />
+ <!-- Iran: 4-6 digits, known premium codes listed -->
+ <shortcode country="ir" pattern="\\d{4,6}" free="700791|700792" />
+
<!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
<shortcode country="it" pattern="\\d{5}" premium="44[0-4]\\d{2}|47[0-4]\\d{2}|48[0-4]\\d{2}|44[5-9]\\d{4}|47[5-9]\\d{4}|48[5-9]\\d{4}|455\\d{2}|499\\d{2}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" />
@@ -219,11 +222,11 @@
<!-- Mozambique: 1-5 digits (standard system default, not country specific) -->
<shortcode country="mz" pattern="\\d{1,5}" free="1714" />
- <!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="mx" pattern="\\d{4,6}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346" />
+ <!-- Mexico: 4-7 digits (not confirmed), known premium codes listed -->
+ <shortcode country="mx" pattern="\\d{4,7}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346|3030303" />
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
- <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
+ <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668|66966" />
<!-- Namibia: 1-5 digits (standard system default, not country specific) -->
<shortcode country="na" pattern="\\d{1,5}" free="40005" />
@@ -255,6 +258,9 @@
<!-- Palestine: 5 digits, known premium codes listed -->
<shortcode country="ps" pattern="\\d{1,5}" free="37477|6681" />
+ <!-- Paraguay: 6 digits, known premium codes listed -->
+ <shortcode country="py" pattern="\\d{6}" free="191289" />
+
<!-- Poland: 4-5 digits (not confirmed), known premium codes listed, plus EU -->
<shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}|8012|80921" />
@@ -275,7 +281,7 @@
<shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/>
<!-- Rwanda: 4 digits -->
- <shortcode country="rw" pattern="\\d{4}" free="5060" />
+ <shortcode country="rw" pattern="\\d{4}" free="5060|5061" />
<!-- Saudi Arabia -->
<shortcode country="sa" pattern="\\d{1,5}" free="8145" />
@@ -309,7 +315,10 @@
<shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
<!-- Tanzania: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="tz" pattern="\\d{1,5}" free="15046|15234" />
+ <shortcode country="tz" pattern="\\d{1,5}" free="15046|15234|15324" />
+
+ <!-- Tunisia: 5 digits, known premium codes listed -->
+ <shortcode country="tn" pattern="\\d{5}" free="85799" />
<!-- Turkey -->
<shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493|3193" />
@@ -324,8 +333,11 @@
visual voicemail code for T-Mobile: 122 -->
<shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611|96831" />
- <!--Uruguay : 1-5 digits (standard system default, not country specific) -->
- <shortcode country="uy" pattern="\\d{1,5}" free="55002" />
+ <!--Uruguay : 1-6 digits (standard system default, not country specific) -->
+ <shortcode country="uy" pattern="\\d{1,6}" free="55002|191289" />
+
+ <!-- Venezuela: 1-6 digits (standard system default, not country specific) -->
+ <shortcode country="ve" pattern="\\d{1,6}" free="538352" />
<!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
<shortcode country="vn" pattern="\\d{1,5}" free="5001|9055|8079" />
@@ -336,6 +348,9 @@
<!-- South Africa -->
<shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056|33009" />
+ <!-- Yemen -->
+ <shortcode country="ye" pattern="\\d{1,4}" free="5081" />
+
<!-- Zimbabwe -->
<shortcode country="zw" pattern="\\d{1,5}" free="33679" />
diff --git a/core/tests/FileSystemUtilsTest/Android.bp b/core/tests/FileSystemUtilsTest/Android.bp
new file mode 100644
index 0000000..53c22df
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/Android.bp
@@ -0,0 +1,78 @@
+// 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 {
+ default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_android_kernel",
+}
+
+cc_library {
+ name: "libpunchtest",
+ stl: "none",
+ host_supported: true,
+ srcs: ["jni/android_test_jni_source.cpp"],
+ header_libs: ["jni_headers"],
+}
+
+android_test_helper_app {
+ name: "embedded_native_libs_test_app",
+ srcs: ["apk_embedded_native_libs/src/**/*.java"],
+ manifest: "apk_embedded_native_libs/embedded_native_libs_test_app.xml",
+ compile_multilib: "64",
+ jni_libs: [
+ "libpunchtest",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "platform-test-annotations",
+ ],
+ use_embedded_native_libs: true,
+}
+
+android_test_helper_app {
+ name: "extract_native_libs_test_app",
+ srcs: ["apk_extract_native_libs/src/**/*.java"],
+ manifest: "apk_extract_native_libs/extract_native_libs_test_app.xml",
+ compile_multilib: "64",
+ jni_libs: [
+ "libpunchtest",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "platform-test-annotations",
+ ],
+ use_embedded_native_libs: false,
+}
+
+java_test_host {
+ name: "FileSystemUtilsTests",
+ // Include all test java files
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "junit",
+ "platform-test-annotations",
+ "truth",
+ ],
+ libs: [
+ "tradefed",
+ "compatibility-host-util",
+ "compatibility-tradefed",
+ ],
+ data: [
+ ":embedded_native_libs_test_app",
+ ":extract_native_libs_test_app",
+ ],
+ test_suites: ["general-tests"],
+ test_config: "AndroidTest.xml",
+}
diff --git a/core/tests/FileSystemUtilsTest/AndroidManifest.xml b/core/tests/FileSystemUtilsTest/AndroidManifest.xml
new file mode 100644
index 0000000..acd5ef3
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:installLocation="internalOnly"
+ package="com.android.internal.content.fstests">
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.internal.content.fstests"
+ android:label="Frameworks FileSystemUtils Tests" />
+
+</manifest>
diff --git a/core/tests/FileSystemUtilsTest/AndroidTest.xml b/core/tests/FileSystemUtilsTest/AndroidTest.xml
new file mode 100644
index 0000000..27f49b2
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<configuration description="Runs FileSystemUtilsTest.">
+ <option name="test-suite-tag" value="apct"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="embedded_native_libs_test_app.apk" />
+ <option name="test-file-name" value="extract_native_libs_test_app.apk" />
+ </target_preparer>
+
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="FileSystemUtilsTests.jar" />
+ </test>
+</configuration>
diff --git a/core/tests/FileSystemUtilsTest/TEST_MAPPING b/core/tests/FileSystemUtilsTest/TEST_MAPPING
new file mode 100644
index 0000000..d41e981
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "FileSystemUtilsTests"
+ }
+ ]
+}
diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml
new file mode 100644
index 0000000..868f7f3
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.test.embedded">
+ <application android:extractNativeLibs="false">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name=".MainActivity"
+ android:exported="true"
+ android:process=":NewProcess">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.test.embedded"/>
+</manifest>
\ No newline at end of file
diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java
new file mode 100644
index 0000000..efa2a39
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java
@@ -0,0 +1,60 @@
+/*
+ * 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.test.embedded;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.annotation.VisibleForTesting;
+
+public class MainActivity extends Activity {
+
+ static {
+ System.loadLibrary("punchtest");
+ }
+
+ @VisibleForTesting
+ static final String INTENT_TYPE = "android.test.embedded.EMBEDDED_LIB_LOADED";
+
+ @VisibleForTesting
+ static final String KEY_OPERAND_1 = "OP1";
+
+ @VisibleForTesting
+ static final String KEY_OPERAND_2 = "OP2";
+
+ @VisibleForTesting
+ static final String KEY_RESULT = "RESULT";
+
+ @Override
+ public void onCreate(Bundle savedOnstanceState) {
+ super.onCreate(savedOnstanceState);
+
+ Intent received = getIntent();
+ int op1 = received.getIntExtra(KEY_OPERAND_1, -1);
+ int op2 = received.getIntExtra(KEY_OPERAND_2, -1);
+ int result = add(op1, op2);
+
+ // Send broadcast so that test can know app has launched and lib is loaded
+ // attach result which has been fetched from JNI lib
+ Intent intent = new Intent(INTENT_TYPE);
+ intent.putExtra(KEY_RESULT, result);
+ sendBroadcast(intent);
+ }
+
+ private native int add(int op1, int op2);
+}
diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java
new file mode 100644
index 0000000..d7d67b8
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.test.embedded;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class PunchEmbeddedLibTest {
+
+ @Test
+ public void testPunchedNativeLibs_embeddedLib() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ CountDownLatch receivedSignal = new CountDownLatch(1);
+
+ // Test app is expected to receive this and perform addition of operands using punched lib
+ int op1 = 48;
+ int op2 = 75;
+ IntentFilter intentFilter = new IntentFilter(MainActivity.INTENT_TYPE);
+ BroadcastReceiver broadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ receivedSignal.countDown();
+ int result = intent.getIntExtra(MainActivity.KEY_RESULT, 1000);
+ Assert.assertEquals(result, op1 + op2);
+
+ }
+ };
+ context.registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED);
+
+ Intent launchIntent =
+ context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
+ launchIntent.putExtra(MainActivity.KEY_OPERAND_1, op1);
+ launchIntent.putExtra(MainActivity.KEY_OPERAND_2, op2);
+ context.startActivity(launchIntent);
+
+ Assert.assertTrue("Failed to launch app", receivedSignal.await(10, TimeUnit.SECONDS));
+ }
+}
diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml
new file mode 100644
index 0000000..6db96f7
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.test.extract">
+ <application android:extractNativeLibs="true">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name=".MainActivity"
+ android:exported="true"
+ android:process=":NewProcess">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.test.extract"/>
+</manifest>
\ No newline at end of file
diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java
new file mode 100644
index 0000000..b1c157e
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java
@@ -0,0 +1,60 @@
+/*
+ * 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.test.extract;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.annotation.VisibleForTesting;
+
+public class MainActivity extends Activity {
+
+ static {
+ System.loadLibrary("punchtest");
+ }
+
+ @VisibleForTesting
+ static final String INTENT_TYPE = "android.test.extract.EXTRACTED_LIB_LOADED";
+
+ @VisibleForTesting
+ static final String KEY_OPERAND_1 = "OP1";
+
+ @VisibleForTesting
+ static final String KEY_OPERAND_2 = "OP2";
+
+ @VisibleForTesting
+ static final String KEY_RESULT = "RESULT";
+
+ @Override
+ public void onCreate(Bundle savedOnstanceState) {
+ super.onCreate(savedOnstanceState);
+
+ Intent received = getIntent();
+ int op1 = received.getIntExtra(KEY_OPERAND_1, -1);
+ int op2 = received.getIntExtra(KEY_OPERAND_2, -1);
+ int result = subtract(op1, op2);
+
+ // Send broadcast so that test can know app has launched and lib is loaded
+ // attach result which has been fetched from JNI lib
+ Intent intent = new Intent(INTENT_TYPE);
+ intent.putExtra(KEY_RESULT, result);
+ sendBroadcast(intent);
+ }
+
+ private native int subtract(int op1, int op2);
+}
diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java
new file mode 100644
index 0000000..7cc1017
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.test.extract;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class PunchExtractedLibTest {
+
+ @Test
+ public void testPunchedNativeLibs_extractedLib() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ CountDownLatch receivedSignal = new CountDownLatch(1);
+
+ // Test app is expected to receive this and perform subtraction using extracted lib
+ int op1 = 100;
+ int op2 = 71;
+ IntentFilter intentFilter = new IntentFilter(MainActivity.INTENT_TYPE);
+ BroadcastReceiver broadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ receivedSignal.countDown();
+ int result = intent.getIntExtra(MainActivity.KEY_RESULT, 1000);
+ Assert.assertEquals(result, op1 - op2);
+ }
+ };
+ context.registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED);
+
+ Intent launchIntent =
+ context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
+ launchIntent.putExtra(MainActivity.KEY_OPERAND_1, op1);
+ launchIntent.putExtra(MainActivity.KEY_OPERAND_2, op2);
+ context.startActivity(launchIntent);
+
+ Assert.assertTrue("Failed to launch app", receivedSignal.await(10, TimeUnit.SECONDS));
+ }
+}
diff --git a/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp b/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp
new file mode 100644
index 0000000..2a5ba81
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include <jni.h>
+
+// This will be called from embedded_native_libs_test_app
+extern "C" JNIEXPORT
+jint JNICALL Java_android_test_embedded_MainActivity_add(JNIEnv*, jclass, jint op1, jint op2) {
+ return op1 + op2;
+}
+
+// This will be called from extract_native_libs_test_app
+extern "C" JNIEXPORT
+jint JNICALL Java_android_test_extract_MainActivity_subtract(JNIEnv*, jclass, jint op1, jint op2) {
+ return op1 - op2;
+}
+
+// Initialize JNI
+jint JNI_OnLoad(JavaVM *jvm, void */* reserved */) {
+ JNIEnv *e;
+
+ // Check JNI version
+ if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
diff --git a/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java b/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java
new file mode 100644
index 0000000..77802e5
--- /dev/null
+++ b/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.android.internal.content;
+
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.AppModeFull;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class FileSystemUtilsTest extends BaseHostJUnit4Test {
+
+ @Test
+ @AppModeFull
+ public void runPunchedApp_embeddedNativeLibs() throws DeviceNotAvailableException {
+ String appPackage = "android.test.embedded";
+ String testName = "PunchEmbeddedLibTest";
+ assertTrue(isPackageInstalled(appPackage));
+ runDeviceTests(appPackage, appPackage + "." + testName);
+ }
+
+ @Test
+ @AppModeFull
+ public void runPunchedApp_extractedNativeLibs() throws DeviceNotAvailableException {
+ String appPackage = "android.test.extract";
+ String testName = "PunchExtractedLibTest";
+ assertTrue(isPackageInstalled(appPackage));
+ runDeviceTests(appPackage, appPackage + "." + testName);
+ }
+}
diff --git a/core/tests/coretests/src/android/tracing/OWNERS b/core/tests/coretests/src/android/tracing/OWNERS
new file mode 100644
index 0000000..86a7e88
--- /dev/null
+++ b/core/tests/coretests/src/android/tracing/OWNERS
@@ -0,0 +1 @@
+include platform/development:/tools/winscope/OWNERS
\ No newline at end of file
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 2f2215f..d1d7c14 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 @@
// 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/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index e346b51..58d692d 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,4 @@
xutan@google.com
# Give submodule owners in shell resource approval
-per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
index ec09827..afddfab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
@@ -1,3 +1,2 @@
# WM shell sub-module pip owner
hwwang@google.com
-mateuszc@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
index 6dabb3b..79d1793 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
@@ -1,4 +1,3 @@
# WM shell sub-module pip owner
hwwang@google.com
-mateuszc@google.com
gabiyev@google.com
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 9d4b426..839c7b6 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -119,30 +119,41 @@
* 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;
}
@@ -310,3 +321,7 @@
return true;
}
+
+const char* ZipFileRO::getZipFileName() {
+ return mFileName;
+}
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index be1f98f..f7c5007 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -151,6 +151,10 @@
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
@@ -187,6 +191,8 @@
*/
bool uncompressEntry(ZipEntryRO entry, int fd) const;
+ const char* getZipFileName();
+
~ZipFileRO();
private:
diff --git a/location/Android.bp b/location/Android.bp
index eb7cd01..5ba35ac 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -26,6 +26,7 @@
"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 f5deb2b..10da632 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 0c23d8c..589e9b7 100644
--- a/location/api/current.txt
+++ b/location/api/current.txt
@@ -412,8 +412,8 @@
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 b1cf96d..075fbb1 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -113,13 +113,13 @@
}
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 17c4a77..4708db2 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -5230,6 +5230,13 @@
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 @@
// 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 82561f9..8a13c03 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -2099,9 +2099,14 @@
}
if (i == 0) {
*initialOffset = offset;
+ if (CC_UNLIKELY(*initialOffset < 0)) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: offset/size in BufferInfo";
+ }
+ return BAD_VALUE;
+ }
}
- if (CC_UNLIKELY((offset > UINT32_MAX)
- || ((long)(offset + size) > UINT32_MAX)
+ if (CC_UNLIKELY(((ssize_t)(UINT32_MAX - offset) < (ssize_t)size)
|| ((offset - *initialOffset) != *totalSize))) {
if (errorDetailMsg) {
*errorDetailMsg = "Error: offset/size in BufferInfo";
@@ -2886,6 +2891,10 @@
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 +2902,26 @@
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 8ed4bf2..3fc8f26 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 @@
* 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 @@
/**
* 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 @@
* 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/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
deleted file mode 100644
index a6ae68f..0000000
--- a/packages/CrashRecovery/services/java/com/android/util/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.util;
-
-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/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
deleted file mode 100644
index 948ebcca..0000000
--- a/packages/CrashRecovery/services/java/com/android/util/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.util;
-
-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/SettingsLib/aconfig/OWNERS b/packages/SettingsLib/aconfig/OWNERS
new file mode 100644
index 0000000..ba02d20
--- /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/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 78cacec..796e391 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -60,7 +60,6 @@
lynhan@google.com
madym@google.com
mankoff@google.com
-mateuszc@google.com
matiashe@google.com
mgalhardo@google.com
michaelmikhil@google.com
diff --git a/proto/src/am_capabilities.proto b/proto/src/am_capabilities.proto
index d97bf81..fc9f7a45 100644
--- a/proto/src/am_capabilities.proto
+++ b/proto/src/am_capabilities.proto
@@ -7,6 +7,16 @@
string name = 1;
}
+message VMCapability {
+ string name = 1;
+}
+
+message FrameworkCapability {
+ string name = 1;
+}
+
message Capabilities {
repeated Capability values = 1;
+ repeated VMCapability vm_capabilities = 2;
+ repeated FrameworkCapability framework_capabilities = 3;
}
diff --git a/services/Android.bp b/services/Android.bp
index 32a8bbb..888e044 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -285,34 +285,34 @@
baseline_file: "api/lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/system-server/api",
- dest: "android-non-updatable.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/system-server/api",
- dest: "android-non-updatable-removed.txt",
- },
- ],
soong_config_variables: {
release_hidden_api_exportable_stubs: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android-non-updatable.txt",
tag: ".exportable.api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".exportable.removed-api.txt",
},
],
conditions_default: {
dists: [
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
+ targets: ["sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
},
],
diff --git a/packages/CrashRecovery/services/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
similarity index 100%
rename from packages/CrashRecovery/services/java/com/android/server/ExplicitHealthCheckController.java
rename to 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 bdc4a7a..2545620 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -22,6 +22,7 @@
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 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
similarity index 99%
rename from packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
rename to services/core/java/com/android/server/PackageWatchdog.java
index 8891b50..6f20adf 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -39,13 +39,13 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.BackgroundThread;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.Xml;
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;
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
similarity index 100%
rename from packages/CrashRecovery/services/java/com/android/server/RescueParty.java
rename to services/core/java/com/android/server/RescueParty.java
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 2b35231..0ff0264 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.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 @@
throws RemoteException {
super.setCeStorageProtection_enforcePermission();
- mVold.setCeStorageProtection(userId, HexDump.toHexString(secret));
+ mVold.setCeStorageProtection(userId, secret);
}
/* Only for use by LockSettingsService */
@@ -3280,7 +3279,7 @@
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 7c66731..c13f02e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -96,6 +96,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.IProgressListener;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallback;
@@ -124,6 +125,8 @@
import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.am.nano.Capabilities;
import com.android.server.am.nano.Capability;
+import com.android.server.am.nano.FrameworkCapability;
+import com.android.server.am.nano.VMCapability;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.Slogf;
@@ -170,6 +173,8 @@
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;
@@ -195,6 +200,7 @@
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;
@@ -442,6 +448,22 @@
capabilities.values[i] = cap;
}
+ String[] vmCapabilities = Debug.getVmFeatureList();
+ capabilities.vmCapabilities = new VMCapability[vmCapabilities.length];
+ for (int i = 0; i < vmCapabilities.length; i++) {
+ VMCapability cap = new VMCapability();
+ cap.name = vmCapabilities[i];
+ capabilities.vmCapabilities[i] = cap;
+ }
+
+ String[] fmCapabilities = Debug.getFeatureList();
+ capabilities.frameworkCapabilities = new FrameworkCapability[fmCapabilities.length];
+ for (int i = 0; i < fmCapabilities.length; i++) {
+ FrameworkCapability cap = new FrameworkCapability();
+ cap.name = fmCapabilities[i];
+ capabilities.frameworkCapabilities[i] = cap;
+ }
+
try {
getRawOutputStream().write(Capabilities.toByteArray(capabilities));
} catch (IOException e) {
@@ -451,10 +473,16 @@
} else {
// Unfortunately we don't have protobuf text format capabilities here.
// Fallback to line separated list instead for text parser.
- pw.println("Format: 1");
+ pw.println("Format: 2");
for (String capability : CAPABILITIES) {
pw.println(capability);
}
+ for (String capability : Debug.getVmFeatureList()) {
+ pw.println("vm:" + capability);
+ }
+ for (String capability : Debug.getFeatureList()) {
+ pw.println("framework:" + capability);
+ }
}
return 0;
}
@@ -501,6 +529,8 @@
} 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")) {
@@ -553,7 +583,7 @@
} 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;
@@ -659,8 +689,9 @@
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);
@@ -1003,6 +1034,7 @@
mSamplingInterval = 0;
mStreaming = false;
mClockType = ProfilerInfo.CLOCK_TYPE_DEFAULT;
+ mProfilerOutputVersion = ProfilerInfo.OUTPUT_VERSION_DEFAULT;
String process = null;
@@ -1017,6 +1049,8 @@
} 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")) {
@@ -1064,7 +1098,7 @@
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)) {
@@ -4152,6 +4186,7 @@
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:");
@@ -4167,6 +4202,8 @@
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");
@@ -4258,6 +4295,7 @@
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:");
@@ -4267,6 +4305,8 @@
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 9b091b3..1dab8c7 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 @@
}
}
} 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 @@
// 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 @@
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 0bfbee6..5e6cf1a 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 @@
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/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index bccbee9..d10223f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -848,8 +848,10 @@
Slog.d(TAG, "resetLockout(userId=" + userId
+ ", hat=" + (hardwareAuthToken == null ? "null " : "present") + ")");
- mBiometricContext.getAuthSessionCoordinator()
+ mHandler.post(() -> {
+ mBiometricContext.getAuthSessionCoordinator()
.resetLockoutFor(userId, Authenticators.BIOMETRIC_STRONG, -1);
+ });
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
index d9947dd..dc2eff4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
@@ -235,7 +235,7 @@
mApiCallNumber = 0;
}
- void addApiCall(String str) {
+ synchronized void addApiCall(String str) {
mApiCalls[mCurr] = str;
mCurr++;
mCurr %= mSize;
@@ -243,7 +243,7 @@
}
@Override
- public String toString() {
+ public synchronized String toString() {
String buffer = "";
int apiCall = mApiCallNumber > mSize ? mApiCallNumber - mSize : 0;
for (int i = 0; i < mSize; i++) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerNative.java b/services/core/java/com/android/server/pm/PackageManagerNative.java
index d035084..66ecd6e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerNative.java
+++ b/services/core/java/com/android/server/pm/PackageManagerNative.java
@@ -68,6 +68,11 @@
}
}
+ @Override
+ public int getPackageUid(String packageName, long flags, int userId) throws RemoteException {
+ return mPm.snapshotComputer().getPackageUid(packageName, flags, userId);
+ }
+
// NB: this differentiates between preloads and sideloads
@Override
public String getInstallerForPackage(String packageName) throws RemoteException {
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 c091b8e..eb91a72 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/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 2a93255..c8bcc51 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -54,8 +54,10 @@
import android.os.UserManager;
import android.os.ext.SdkExtensions;
import android.provider.DeviceConfig;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.LongArrayQueue;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
@@ -173,6 +175,8 @@
// Accessed on the handler thread only.
private long mRelativeBootTime = calculateRelativeBootTime();
+ private final ArrayMap<Integer, Pair<Context, BroadcastReceiver>> mUserBroadcastReceivers;
+
RollbackManagerServiceImpl(Context context) {
mContext = context;
// Note that we're calling onStart here because this object is only constructed on
@@ -210,6 +214,8 @@
}
});
+ mUserBroadcastReceivers = new ArrayMap<>();
+
UserManager userManager = mContext.getSystemService(UserManager.class);
for (UserHandle user : userManager.getUserHandles(true)) {
registerUserCallbacks(user);
@@ -275,7 +281,9 @@
}
}, enableRollbackTimedOutFilter, null, getHandler());
- IntentFilter userAddedIntentFilter = new IntentFilter(Intent.ACTION_USER_ADDED);
+ IntentFilter userIntentFilter = new IntentFilter();
+ userIntentFilter.addAction(Intent.ACTION_USER_ADDED);
+ userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -287,9 +295,15 @@
return;
}
registerUserCallbacks(UserHandle.of(newUserId));
+ } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (newUserId == -1) {
+ return;
+ }
+ unregisterUserCallbacks(UserHandle.of(newUserId));
}
}
- }, userAddedIntentFilter, null, getHandler());
+ }, userIntentFilter, null, getHandler());
registerTimeChangeReceiver();
}
@@ -335,7 +349,7 @@
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
filter.addDataScheme("package");
- context.registerReceiver(new BroadcastReceiver() {
+ BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
assertInWorkerThread();
@@ -354,7 +368,21 @@
onPackageFullyRemoved(packageName);
}
}
- }, filter, null, getHandler());
+ };
+ context.registerReceiver(receiver, filter, null, getHandler());
+ mUserBroadcastReceivers.put(user.getIdentifier(), new Pair(context, receiver));
+ }
+
+ @AnyThread
+ private void unregisterUserCallbacks(UserHandle user) {
+ Pair<Context, BroadcastReceiver> pair = mUserBroadcastReceivers.get(user.getIdentifier());
+ if (pair == null || pair.first == null || pair.second == null) {
+ Slog.e(TAG, "No receiver found for the user" + user);
+ return;
+ }
+
+ pair.first.unregisterReceiver(pair.second);
+ mUserBroadcastReceivers.remove(user.getIdentifier());
}
@ExtThread
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
similarity index 100%
rename from packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
rename to 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
similarity index 100%
rename from packages/CrashRecovery/services/java/com/android/server/rollback/WatchdogRollbackLogger.java
rename to 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 10e868d..c1d92cf 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 @@
}
@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 4a81c95..440d251 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 @@
* @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 cddc79d..0afb049 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 @@
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/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 37f0450..5a5f7ef 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -626,8 +626,12 @@
* Dumps the state of this Vcn for logging and debugging purposes.
*
* <p>PII and credentials MUST NEVER be dumped here.
+ *
+ * <p>This method is not thread safe and MUST run on the VCN thread.
*/
public void dump(IndentingPrintWriter pw) {
+ mVcnContext.ensureRunningOnLooperThread();
+
pw.println("Vcn (" + mSubscriptionGroup + "):");
pw.increaseIndent();
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index 1383708..6a4c9c2 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 @@
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 @@
@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 @@
// Auto-generated class
mFeatureFlags = new FeatureFlagsImpl();
- mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl();
}
@NonNull
@@ -76,7 +75,16 @@
}
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/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 3094b18..8d378a0 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -2580,8 +2580,12 @@
* Dumps the state of this VcnGatewayConnection for logging and debugging purposes.
*
* <p>PII and credentials MUST NEVER be dumped here.
+ *
+ * <p>This method is not thread safe and MUST run on the VCN thread.
*/
public void dump(IndentingPrintWriter pw) {
+ mVcnContext.ensureRunningOnLooperThread();
+
pw.println("VcnGatewayConnection (" + mConnectionConfig.getGatewayConnectionName() + "):");
pw.increaseIndent();
@@ -2602,6 +2606,19 @@
mUnderlyingNetworkController.dump(pw);
pw.println();
+ if (mIkeSession == null) {
+ pw.println("mIkeSession: null");
+ } else {
+ pw.println("mIkeSession:");
+
+ // Add a try catch block in case IkeSession#dump is not thread-safe
+ try {
+ mIkeSession.dump(pw);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Failed to dump IkeSession: " + e);
+ }
+ }
+
pw.decreaseIndent();
}
@@ -2905,6 +2922,11 @@
public void setNetwork(@NonNull Network network) {
mImpl.setNetwork(network);
}
+
+ /** Dumps the state of the IkeSession */
+ public void dump(@NonNull IndentingPrintWriter pw) {
+ mImpl.dump(pw);
+ }
}
/** Proxy Implementation of WakeLock, used for testing. */
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 ed9fa65..3619253 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.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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
@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 @@
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 @@
+ " 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 @@
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 a1b212f..b9b1060 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 @@
}
}
+ 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/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 79eb0dc..ce47f5c 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -26,3 +26,6 @@
# File related to activity callers
per-file ActivityCallerState.java = file:/core/java/android/app/COMPONENT_CALLER_OWNERS
+
+# Files related to tracing
+per-file *TransitionTracer.java = file:platform/development:/tools/winscope/OWNERS
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 57939bc..b877787 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 @@
@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 @@
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/com_android_server_am_OomConnection.cpp b/services/core/jni/com_android_server_am_OomConnection.cpp
index 054937f..4d07776 100644
--- a/services/core/jni/com_android_server_am_OomConnection.cpp
+++ b/services/core/jni/com_android_server_am_OomConnection.cpp
@@ -92,9 +92,11 @@
memevent_listener.deregisterAllEvents();
jniThrowRuntimeException(env, "Failed creating java string for process name");
}
- jobject java_oom_kill = env->NewObject(sOomKillRecordInfo.clazz, sOomKillRecordInfo.ctor,
- oom_kill.timestamp_ms, oom_kill.pid, oom_kill.uid,
- process_name, oom_kill.oom_score_adj);
+ jobject java_oom_kill =
+ env->NewObject(sOomKillRecordInfo.clazz, sOomKillRecordInfo.ctor,
+ oom_kill.timestamp_ms, oom_kill.pid, oom_kill.uid, process_name,
+ oom_kill.oom_score_adj, oom_kill.total_vm_kb, oom_kill.anon_rss_kb,
+ oom_kill.file_rss_kb, oom_kill.shmem_rss_kb, oom_kill.pgtables_kb);
if (java_oom_kill == NULL) {
memevent_listener.deregisterAllEvents();
jniThrowRuntimeException(env, "Failed to create OomKillRecord object");
@@ -115,8 +117,8 @@
sOomKillRecordInfo.clazz = FindClassOrDie(env, "android/os/OomKillRecord");
sOomKillRecordInfo.clazz = MakeGlobalRefOrDie(env, sOomKillRecordInfo.clazz);
- sOomKillRecordInfo.ctor =
- GetMethodIDOrDie(env, sOomKillRecordInfo.clazz, "<init>", "(JIILjava/lang/String;S)V");
+ sOomKillRecordInfo.ctor = GetMethodIDOrDie(env, sOomKillRecordInfo.clazz, "<init>",
+ "(JIILjava/lang/String;SJJJJJ)V");
return RegisterMethodsOrDie(env, "com/android/server/am/OomConnection", sOomConnectionMethods,
NELEM(sOomConnectionMethods));
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 0000000..abd864c
--- /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 f3b164c..f4c4405 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 @@
} 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 861562d..305108e 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 5c73177..a43cd39 100644
--- a/tests/OneMedia/Android.bp
+++ b/tests/OneMedia/Android.bp
@@ -16,6 +16,7 @@
platform_apis: true,
certificate: "platform",
libs: ["org.apache.http.legacy"],
+ optional_uses_libs: ["org.apache.http.legacy"],
optimize: {
enabled: false,
},
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 fdf8fb8..c8b60e5 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.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 @@
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 @@
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 @@
.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 @@
// 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 @@
xfrmStateReceiver.onResult(newTransformState(1, 1, newReplayBitmap(1)));
verify(mPacketLossCalculator, never())
- .getPacketLossRatePercentage(any(), any(), anyString());
+ .getPacketLossRatePercentage(any(), any(), anyInt(), anyString());
}
@Test
@@ -289,17 +310,19 @@
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 @@
// 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 @@
@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 @@
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 @@
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 @@
// 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 af6daa1..edad678 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 @@
@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 @@
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 9d61111..be5c197 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 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 @@
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 @@
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_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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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);
}
}
}