diff options
137 files changed, 3585 insertions, 2118 deletions
diff --git a/Android.bp b/Android.bp index 5211fe23e1bb..68fc4749fa00 100644 --- a/Android.bp +++ b/Android.bp @@ -398,6 +398,7 @@ java_defaults { ], sdk_version: "core_platform", static_libs: [ + "aconfig_storage_reader_java", "android.hardware.common.fmq-V1-java", "bouncycastle-repackaged-unbundled", "com.android.sysprop.foldlockbehavior", @@ -413,7 +414,6 @@ java_defaults { "modules-utils-fastxmlserializer", "modules-utils-preconditions", "modules-utils-statemachine", - "modules-utils-synchronous-result-receiver", "modules-utils-os", "modules-utils-uieventlogger-interface", "framework-permission-aidl-java", @@ -632,7 +632,6 @@ java_library { "core/java/com/android/internal/util/AsyncService.java", "core/java/com/android/internal/util/Protocol.java", "telephony/java/android/telephony/Annotation.java", - ":net-utils-framework-wifi-common-srcs", ], libs: [ "framework-annotations-lib", diff --git a/CleanSpec.mk b/CleanSpec.mk index 02e8eecbb721..e6801034cd97 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -262,6 +262,7 @@ $(call add-clean-step, rm -rf $(SOONG_OUT_DIR)/.intermediates/frameworks/base/li $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/InProcessTethering) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/OsuLogin) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system_other/system/app/OsuLogin) +$(call add-clean-step, rm -rf $(OUT_DIR)/host/linux-x86/testcases/ravenwood-runtime) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER # ****************************************************************** @@ -14,6 +14,7 @@ michaelwr@google.com #{LAST_RESORT_SUGGESTION} nandana@google.com #{LAST_RESORT_SUGGESTION} narayan@google.com #{LAST_RESORT_SUGGESTION} ogunwale@google.com #{LAST_RESORT_SUGGESTION} +omakoto@google.com #{LAST_RESORT_SUGGESTION} roosa@google.com #{LAST_RESORT_SUGGESTION} smoreland@google.com #{LAST_RESORT_SUGGESTION} yamasani@google.com #{LAST_RESORT_SUGGESTION} @@ -28,7 +29,7 @@ per-file */TEST_MAPPING = * # Support bulk translation updates per-file */res*/values*/*.xml = byi@google.com, delphij@google.com -per-file **.bp,**.mk = hansson@google.com, joeo@google.com, lamontjones@google.com +per-file **.bp,**.mk =joeo@google.com, lamontjones@google.com per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS diff --git a/PERFORMANCE_OWNERS b/PERFORMANCE_OWNERS index 48a020130445..02b0a1ec75e7 100644 --- a/PERFORMANCE_OWNERS +++ b/PERFORMANCE_OWNERS @@ -6,3 +6,4 @@ philipcuadra@google.com shayba@google.com jdduke@google.com shombert@google.com +kevinjeon@google.com diff --git a/Ravenwood.bp b/Ravenwood.bp index f43c37bf637d..912f19d4ca3c 100644 --- a/Ravenwood.bp +++ b/Ravenwood.bp @@ -30,7 +30,7 @@ java_genrule { name: "framework-minus-apex.ravenwood-base", tools: ["hoststubgen"], cmd: "$(location hoststubgen) " + - "@$(location ravenwood/ravenwood-standard-options.txt) " + + "@$(location :ravenwood-standard-options) " + "--debug-log $(location hoststubgen_framework-minus-apex.log) " + "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " + @@ -41,13 +41,13 @@ java_genrule { "--gen-input-dump-file $(location hoststubgen_dump.txt) " + "--in-jar $(location :framework-minus-apex-for-hoststubgen) " + - "--policy-override-file $(location ravenwood/framework-minus-apex-ravenwood-policies.txt) " + - "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ", + "--policy-override-file $(location :ravenwood-framework-policies) " + + "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) ", srcs: [ ":framework-minus-apex-for-hoststubgen", - "ravenwood/framework-minus-apex-ravenwood-policies.txt", - "ravenwood/ravenwood-standard-options.txt", - "ravenwood/ravenwood-annotation-allowed-classes.txt", + ":ravenwood-framework-policies", + ":ravenwood-standard-options", + ":ravenwood-annotation-allowed-classes", ], out: [ "ravenwood.jar", @@ -91,7 +91,7 @@ java_genrule { name: "services.core.ravenwood-base", tools: ["hoststubgen"], cmd: "$(location hoststubgen) " + - "@$(location ravenwood/ravenwood-standard-options.txt) " + + "@$(location :ravenwood-standard-options) " + "--debug-log $(location hoststubgen_services.core.log) " + "--stats-file $(location hoststubgen_services.core_stats.csv) " + @@ -102,13 +102,13 @@ java_genrule { "--gen-input-dump-file $(location hoststubgen_dump.txt) " + "--in-jar $(location :services.core-for-hoststubgen) " + - "--policy-override-file $(location ravenwood/services.core-ravenwood-policies.txt) " + - "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ", + "--policy-override-file $(location :ravenwood-services-policies) " + + "--annotation-allowed-classes-file $(location :ravenwood-annotation-allowed-classes) ", srcs: [ ":services.core-for-hoststubgen", - "ravenwood/services.core-ravenwood-policies.txt", - "ravenwood/ravenwood-standard-options.txt", - "ravenwood/ravenwood-annotation-allowed-classes.txt", + ":ravenwood-services-policies", + ":ravenwood-standard-options", + ":ravenwood-annotation-allowed-classes", ], out: [ "ravenwood.jar", @@ -137,6 +137,7 @@ java_genrule { java_library { name: "services.core.ravenwood-jarjar", + defaults: ["ravenwood-internal-only-visibility-java"], installable: false, static_libs: [ "services.core.ravenwood", @@ -144,88 +145,29 @@ java_library { jarjar_rules: ":ravenwood-services-jarjar-rules", } -java_library { - name: "services.fakes.ravenwood-jarjar", - installable: false, - srcs: [":services.fakes-sources"], - libs: [ - "ravenwood-framework", - "services.core.ravenwood", - ], - jarjar_rules: ":ravenwood-services-jarjar-rules", -} - -java_library { - name: "mockito-ravenwood-prebuilt", - installable: false, - static_libs: [ - "mockito-robolectric-prebuilt", - ], -} - -java_library { - name: "inline-mockito-ravenwood-prebuilt", - installable: false, - static_libs: [ - "inline-mockito-robolectric-prebuilt", - ], -} - // Jars in "ravenwood-runtime" are set to the classpath, sorted alphabetically. // Rename some of the dependencies to make sure they're included in the intended order. java_genrule { name: "100-framework-minus-apex.ravenwood", + defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [":framework-minus-apex.ravenwood"], out: ["100-framework-minus-apex.ravenwood.jar"], - visibility: ["//visibility:private"], } java_genrule { // Use 200 to make sure it comes before the mainline stub ("all-updatable..."). name: "200-kxml2-android", + defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [":kxml2-android"], out: ["200-kxml2-android.jar"], - visibility: ["//visibility:private"], } -android_ravenwood_libgroup { - name: "ravenwood-runtime", - libs: [ - "100-framework-minus-apex.ravenwood", - "200-kxml2-android", - "all-updatable-modules-system-stubs", - "android.test.mock.ravenwood", - "ravenwood-helper-runtime", - "hoststubgen-helper-runtime.ravenwood", - "services.core.ravenwood-jarjar", - "services.fakes.ravenwood-jarjar", - - // Provide runtime versions of utils linked in below - "junit", - "truth", - "flag-junit", - "ravenwood-framework", - "ravenwood-junit-impl", - "ravenwood-junit-impl-flag", - "mockito-ravenwood-prebuilt", - "inline-mockito-ravenwood-prebuilt", - ], - jni_libs: [ - "libandroid_runtime", - ], -} - -android_ravenwood_libgroup { - name: "ravenwood-utils", - libs: [ - "junit", - "truth", - "flag-junit", - "ravenwood-framework", - "ravenwood-junit", - "mockito-ravenwood-prebuilt", - "inline-mockito-ravenwood-prebuilt", - ], +java_genrule { + name: "z00-all-updatable-modules-system-stubs", + defaults: ["ravenwood-internal-only-visibility-genrule"], + cmd: "cp $(in) $(out)", + srcs: [":all-updatable-modules-system-stubs"], + out: ["z00-all-updatable-modules-system-stubs.jar"], } diff --git a/ZYGOTE_OWNERS b/ZYGOTE_OWNERS index f6d15e03a892..6918c16840dd 100644 --- a/ZYGOTE_OWNERS +++ b/ZYGOTE_OWNERS @@ -1,4 +1,4 @@ chriswailes@google.com +hboehm@google.com maco@google.com -narayan@google.com ngeoffray@google.com diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java index c69ae39846bd..36266de04d23 100644 --- a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java +++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java @@ -23,6 +23,9 @@ import androidx.test.filters.LargeTest; import org.conscrypt.TestUtils; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.security.Key; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; @@ -91,21 +94,17 @@ public final class CipherEncryptPerfTest { } } - private Object[] getParams() { - return new Object[][] { - new Object[] {new Config(BufferType.ARRAY, - MyCipherFactory.CONSCRYPT, - Transformation.AES_CBC_PKCS5)}, - new Object[] {new Config(BufferType.ARRAY, - MyCipherFactory.CONSCRYPT, - Transformation.AES_ECB_PKCS5)}, - new Object[] {new Config(BufferType.ARRAY, - MyCipherFactory.CONSCRYPT, - Transformation.AES_GCM_NO)}, - new Object[] {new Config(BufferType.ARRAY, - MyCipherFactory.CONSCRYPT, - Transformation.AES_GCM_SIV)}, - }; + public Collection <Object[]> getParams() { + final List<Object[]> params = new ArrayList<>(); + for (BufferType bufferType : BufferType.values()) { + for (CipherFactory cipherFactory : MyCipherFactory.values()) { + for (Transformation transformation : Transformation.values()) { + params.add(new Object[] {new Config( + bufferType, cipherFactory, transformation)}); + } + } + } + return params; } private EncryptStrategy encryptStrategy; diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java index dd9f4eb7e8d3..d7b1c9a2d3a2 100644 --- a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java +++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java @@ -30,6 +30,9 @@ import java.io.IOException; import java.io.OutputStream; import java.net.SocketException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -40,6 +43,7 @@ import java.util.concurrent.atomic.AtomicLong; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -104,19 +108,26 @@ public final class ClientSocketPerfTest { } } - private Object[] getParams() { - return new Object[][] { - new Object[] {new Config( - EndpointFactory.CONSCRYPT, - EndpointFactory.CONSCRYPT, - 64, - "AES128-GCM", - ChannelType.CHANNEL, - PerfTestProtocol.TLSv13)}, - }; + public Collection getParams() { + final List<Object[]> params = new ArrayList<>(); + for (EndpointFactory endpointFactory : EndpointFactory.values()) { + for (ChannelType channelType : ChannelType.values()) { + for (PerfTestProtocol protocol : PerfTestProtocol.values()) { + params.add(new Object[] {new Config(endpointFactory, + endpointFactory, 64, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + channelType, protocol)}); + params.add(new Object[] {new Config(endpointFactory, + endpointFactory, 512, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + channelType, protocol)}); + params.add(new Object[] {new Config(endpointFactory, + endpointFactory, 4096, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + channelType, protocol)}); + } + } + } + return params; } - private ClientEndpoint client; private ServerEndpoint server; private byte[] message; @@ -186,6 +197,7 @@ public final class ClientSocketPerfTest { */ @Test @Parameters(method = "getParams") + @Ignore("b/351034205") public void time(Config config) throws Exception { reset(); setup(config); diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineFactory.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineFactory.java new file mode 100644 index 000000000000..8a0d52dff3b1 --- /dev/null +++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineFactory.java @@ -0,0 +1,68 @@ +/* + * Copyright 2017 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.conscrypt; + +import org.conscrypt.TestUtils; +import java.security.Security; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + + +/** + * Factory for {@link SSLEngine} instances. + */ +public class EngineFactory { + public EngineFactory() { + this(newConscryptClientContext(), newConscryptServerContext()); + } + + private EngineFactory(SSLContext clientContext, SSLContext serverContext) { + this.clientContext = clientContext; + this.serverContext = serverContext; + } + + private final SSLContext clientContext; + private final SSLContext serverContext; + + public SSLEngine newClientEngine(String cipher) { + SSLEngine engine = initEngine(clientContext.createSSLEngine(), cipher, true); + return engine; + } + + public SSLEngine newServerEngine(String cipher) { + SSLEngine engine = initEngine(serverContext.createSSLEngine(), cipher, false); + return engine; + } + + public void dispose(SSLEngine engine) { + engine.closeOutbound(); + } + + private static SSLContext newConscryptClientContext() { + return TestUtils.newClientSslContext(TestUtils.getConscryptProvider()); + } + + private static SSLContext newConscryptServerContext() { + return TestUtils.newServerSslContext(TestUtils.getConscryptProvider()); + } + + static SSLEngine initEngine(SSLEngine engine, String cipher, boolean client) { + engine.setEnabledProtocols(new String[]{"TLSv1.2", "TLSv1.3"}); + engine.setEnabledCipherSuites(new String[] {cipher}); + engine.setUseClientMode(client); + return engine; + } +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineHandshakePerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineHandshakePerfTest.java new file mode 100644 index 000000000000..cd0ac96b41de --- /dev/null +++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineHandshakePerfTest.java @@ -0,0 +1,207 @@ +/* + * Copyright 2017 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. + */ + +/* + * Copyright 2017 The Netty Project + * + * The Netty Project licenses this file to you 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.conscrypt; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLException; + +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import androidx.test.filters.LargeTest; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Benchmark comparing handshake performance of various engine implementations to conscrypt. + */ +@RunWith(JUnitParamsRunner.class) +@LargeTest +public final class EngineHandshakePerfTest { + @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + /** + * Provider for the test configuration + */ + private class Config { + BufferType a_bufferType; + String c_cipher; + int d_rttMillis; + Config(BufferType bufferType, + String cipher, + int rttMillis) { + a_bufferType = bufferType; + c_cipher = cipher; + d_rttMillis = rttMillis; + } + public BufferType bufferType() { + return a_bufferType; + } + + public String cipher() { + return c_cipher; + } + + public int rttMillis() { + return d_rttMillis; + } + } + + public Collection getParams() { + final List<Object[]> params = new ArrayList<>(); + for (BufferType bufferType : BufferType.values()) { + params.add(new Object[] {new Config(bufferType, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 100)}); + } + return params; + } + + private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0); + + private EngineFactory engineFactory = new EngineFactory(); + private String cipher; + private int rttMillis; + + private ByteBuffer clientApplicationBuffer; + private ByteBuffer clientPacketBuffer; + private ByteBuffer serverApplicationBuffer; + private ByteBuffer serverPacketBuffer; + + private void setup(Config config) throws Exception { + cipher = config.cipher(); + rttMillis = config.rttMillis(); + BufferType bufferType = config.bufferType(); + + SSLEngine clientEngine = engineFactory.newClientEngine(cipher); + SSLEngine serverEngine = engineFactory.newServerEngine(cipher); + + // Create the application and packet buffers for both endpoints. + clientApplicationBuffer = bufferType.newApplicationBuffer(clientEngine); + serverApplicationBuffer = bufferType.newApplicationBuffer(serverEngine); + clientPacketBuffer = bufferType.newPacketBuffer(clientEngine); + serverPacketBuffer = bufferType.newPacketBuffer(serverEngine); + + engineFactory.dispose(clientEngine); + engineFactory.dispose(serverEngine); + } + + @Test + @Parameters(method = "getParams") + public void handshake(Config config) throws Exception { + setup(config); + SSLEngine client = engineFactory.newClientEngine(cipher); + SSLEngine server = engineFactory.newServerEngine(cipher); + clientApplicationBuffer.clear(); + clientPacketBuffer.clear(); + serverApplicationBuffer.clear(); + serverPacketBuffer.clear(); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + client.beginHandshake(); + server.beginHandshake(); + doHandshake(client, server); + } + + engineFactory.dispose(client); + engineFactory.dispose(server); + } + + private void doHandshake(SSLEngine client, SSLEngine server) throws SSLException { + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + // Send as many client-to-server messages as possible + doHalfHandshake(client, server, clientPacketBuffer, serverApplicationBuffer); + + if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING + && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) { + return; + } + + // Do the same with server-to-client messages + doHalfHandshake(server, client, serverPacketBuffer, clientApplicationBuffer); + + if (client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING + && server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) { + return; + } + } + } + + private void doHalfHandshake(SSLEngine sender, SSLEngine receiver, + ByteBuffer senderPacketBuffer, ByteBuffer receiverApplicationBuffer) + throws SSLException { + SSLEngineResult senderResult; + SSLEngineResult receiverResult; + + do { + senderResult = sender.wrap(EMPTY_BUFFER, senderPacketBuffer); + runDelegatedTasks(senderResult, sender); + senderPacketBuffer.flip(); + receiverResult = receiver.unwrap(senderPacketBuffer, receiverApplicationBuffer); + runDelegatedTasks(receiverResult, receiver); + senderPacketBuffer.compact(); + } while (senderResult.getHandshakeStatus() == HandshakeStatus.NEED_WRAP); + + if (rttMillis > 0) { + try { + Thread.sleep(rttMillis / 2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + private static void runDelegatedTasks(SSLEngineResult result, SSLEngine engine) { + if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { + for (;;) { + Runnable task = engine.getDelegatedTask(); + if (task == null) { + break; + } + task.run(); + } + } + } +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineWrapPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineWrapPerfTest.java new file mode 100644 index 000000000000..1fee2183b11e --- /dev/null +++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EngineWrapPerfTest.java @@ -0,0 +1,221 @@ +/* + * Copyright 2017 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. + */ + +/* + * Copyright 2017 The Netty Project + * + * The Netty Project licenses this file to you 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.conscrypt; + +import static org.conscrypt.TestUtils.doEngineHandshake; +import static org.conscrypt.TestUtils.newTextMessage; +import static org.junit.Assert.assertEquals; + +import java.nio.ByteBuffer; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import androidx.test.filters.LargeTest; + +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Benchmark comparing performance of various engine implementations to conscrypt. + */ +@RunWith(JUnitParamsRunner.class) +@LargeTest +public final class EngineWrapPerfTest { + @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + /** + * Provider for the benchmark configuration + */ + private class Config { + BufferType a_bufferType; + int c_messageSize; + String d_cipher; + Config(BufferType bufferType, + int messageSize, + String cipher) { + a_bufferType = bufferType; + c_messageSize = messageSize; + d_cipher = cipher; + } + public BufferType bufferType() { + return a_bufferType; + } + + public int messageSize() { + return c_messageSize; + } + + public String cipher() { + return d_cipher; + } + } + + public Collection getParams() { + final List<Object[]> params = new ArrayList<>(); + for (BufferType bufferType : BufferType.values()) { + params.add(new Object[] {new Config(bufferType, 64, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")}); + params.add(new Object[] {new Config(bufferType, 512, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")}); + params.add(new Object[] {new Config(bufferType, 4096, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")}); + } + return params; + } + + + private EngineFactory engineFactory = new EngineFactory(); + private String cipher; + private SSLEngine clientEngine; + private SSLEngine serverEngine; + + private ByteBuffer messageBuffer; + private ByteBuffer clientApplicationBuffer; + private ByteBuffer clientPacketBuffer; + private ByteBuffer serverApplicationBuffer; + private ByteBuffer serverPacketBuffer; + private ByteBuffer preEncryptedBuffer; + + private void setup(Config config) throws Exception { + cipher = config.cipher(); + BufferType bufferType = config.bufferType(); + + clientEngine = engineFactory.newClientEngine(cipher); + serverEngine = engineFactory.newServerEngine(cipher); + + // Create the application and packet buffers for both endpoints. + clientApplicationBuffer = bufferType.newApplicationBuffer(clientEngine); + serverApplicationBuffer = bufferType.newApplicationBuffer(serverEngine); + clientPacketBuffer = bufferType.newPacketBuffer(clientEngine); + serverPacketBuffer = bufferType.newPacketBuffer(serverEngine); + + // Generate the message to be sent from the client. + int messageSize = config.messageSize(); + messageBuffer = bufferType.newBuffer(messageSize); + messageBuffer.put(newTextMessage(messageSize)); + messageBuffer.flip(); + + // Complete the initial TLS handshake. + doEngineHandshake(clientEngine, serverEngine, clientApplicationBuffer, clientPacketBuffer, + serverApplicationBuffer, serverPacketBuffer, true); + + // Populate the pre-encrypted buffer for use with the unwrap benchmark. + preEncryptedBuffer = bufferType.newBuffer(clientEngine.getSession().getPacketBufferSize()); + doWrap(messageBuffer, preEncryptedBuffer); + doUnwrap(preEncryptedBuffer, serverApplicationBuffer); + } + + void teardown() { + engineFactory.dispose(clientEngine); + engineFactory.dispose(serverEngine); + } + + @Test + @Parameters(method = "getParams") + public void wrap(Config config) throws Exception { + setup(config); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + // Reset the buffers. + messageBuffer.position(0); + clientPacketBuffer.clear(); + // Wrap the original message and create the encrypted data. + doWrap(messageBuffer, clientPacketBuffer); + + // Lightweight comparison - just make sure the data length is correct. + assertEquals(preEncryptedBuffer.limit(), clientPacketBuffer.limit()); + } + teardown(); + } + + /** + * Simple benchmark that sends a single message from client to server. + */ + @Test + @Parameters(method = "getParams") + public void wrapAndUnwrap(Config config) throws Exception { + setup(config); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + // Reset the buffers. + messageBuffer.position(0); + clientPacketBuffer.clear(); + serverApplicationBuffer.clear(); + // Wrap the original message and create the encrypted data. + doWrap(messageBuffer, clientPacketBuffer); + + // Unwrap the encrypted data and get back the original result. + doUnwrap(clientPacketBuffer, serverApplicationBuffer); + + // Lightweight comparison - just make sure the unencrypted data length is correct. + assertEquals(messageBuffer.limit(), serverApplicationBuffer.limit()); + } + teardown(); + } + + private void doWrap(ByteBuffer src, ByteBuffer dst) throws SSLException { + // Wrap the original message and create the encrypted data. + verifyResult(src, clientEngine.wrap(src, dst)); + dst.flip(); + } + + private void doUnwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { + verifyResult(src, serverEngine.unwrap(src, dst)); + dst.flip(); + } + + private void verifyResult(ByteBuffer src, SSLEngineResult result) { + if (result.getStatus() != SSLEngineResult.Status.OK) { + throw new RuntimeException("Operation returned unexpected result " + result); + } + if (result.bytesConsumed() != src.limit()) { + throw new RuntimeException( + String.format(Locale.US, + "Operation didn't consume all bytes. Expected %d, consumed %d.", + src.limit(), result.bytesConsumed())); + } + } +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java index ba2a65a17e84..8916a3c55a9a 100644 --- a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java +++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java @@ -24,6 +24,9 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; import java.io.OutputStream; import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -40,6 +43,7 @@ import androidx.test.filters.LargeTest; import junitparams.JUnitParamsRunner; import junitparams.Parameters; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -94,15 +98,22 @@ public final class ServerSocketPerfTest { } } - private Object[] getParams() { - return new Object[][] { - new Object[] {new Config( - EndpointFactory.CONSCRYPT, - EndpointFactory.CONSCRYPT, - 64, - "AES128-GCM", - ChannelType.CHANNEL)}, - }; + public Collection getParams() { + final List<Object[]> params = new ArrayList<>(); + for (EndpointFactory endpointFactory : EndpointFactory.values()) { + for (ChannelType channelType : ChannelType.values()) { + params.add(new Object[] {new Config(endpointFactory, + endpointFactory, 64, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", channelType)}); + params.add(new Object[] {new Config(endpointFactory, + endpointFactory, 512, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", channelType)}); + params.add(new Object[] {new Config(endpointFactory, + endpointFactory, 4096, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", channelType)}); + } + } + return params; } private ClientEndpoint client; @@ -121,7 +132,8 @@ public final class ServerSocketPerfTest { final ChannelType channelType = config.channelType(); server = config.serverFactory().newServer( - channelType, config.messageSize(), getCommonProtocolSuites(), ciphers(config)); + channelType, config.messageSize(), + new String[] {"TLSv1.3", "TLSv1.2"}, ciphers(config)); server.setMessageProcessor(new MessageProcessor() { @Override public void processMessage(byte[] inMessage, int numBytes, OutputStream os) { @@ -145,7 +157,8 @@ public final class ServerSocketPerfTest { // Always use the same client for consistency across the benchmarks. client = config.clientFactory().newClient( - ChannelType.CHANNEL, server.port(), getCommonProtocolSuites(), ciphers(config)); + ChannelType.CHANNEL, server.port(), + new String[] {"TLSv1.3", "TLSv1.2"}, ciphers(config)); client.start(); // Wait for the initial connection to complete. @@ -189,6 +202,7 @@ public final class ServerSocketPerfTest { @Test @Parameters(method = "getParams") + @Ignore("b/351034205") public void throughput(Config config) throws Exception { setup(config); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java index 78fe73262e4c..3542b0a76803 100644 --- a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java +++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java @@ -31,7 +31,6 @@ public enum Transformation { AES_CBC_PKCS5("AES", "CBC", "PKCS5Padding", new AesKeyGen()), AES_ECB_PKCS5("AES", "ECB", "PKCS5Padding", new AesKeyGen()), AES_GCM_NO("AES", "GCM", "NoPadding", new AesKeyGen()), - AES_GCM_SIV("AES", "GCM_SIV", "NoPadding", new AesKeyGen()), RSA_ECB_PKCS1("RSA", "ECB", "PKCS1Padding", new RsaKeyGen()); Transformation(String algorithm, String mode, String padding, KeyGen keyGen) { diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp index 1653edc77de9..856dba3f804c 100644 --- a/apct-tests/perftests/multiuser/Android.bp +++ b/apct-tests/perftests/multiuser/Android.bp @@ -38,3 +38,10 @@ android_test { ], certificate: "platform", } + +filegroup { + name: "multi_user_trace_config", + srcs: [ + "trace_configs/trace_config_multi_user.textproto", + ], +} diff --git a/api/Android.bp b/api/Android.bp index d4ba964046ee..d9966fd87ac3 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -29,12 +29,14 @@ bootstrap_go_package { pkgPath: "android/soong/api", deps: [ "blueprint", + "blueprint-proptools", "soong", "soong-android", "soong-genrule", "soong-java", ], srcs: ["api.go"], + testSrcs: ["api_test.go"], pluginFor: ["soong_build"], } @@ -60,40 +62,8 @@ metalava_cmd = "$(location metalava)" metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED " metalava_cmd += " --quiet " -soong_config_module_type { - name: "enable_crashrecovery_module", - module_type: "combined_apis_defaults", - config_namespace: "ANDROID", - bool_variables: ["release_crashrecovery_module"], - properties: [ - "bootclasspath", - "system_server_classpath", - ], -} - -soong_config_bool_variable { - name: "release_crashrecovery_module", -} - -enable_crashrecovery_module { - name: "crashrecovery_module_defaults", - soong_config_variables: { - release_crashrecovery_module: { - bootclasspath: [ - "framework-crashrecovery", - ], - system_server_classpath: [ - "service-crashrecovery", - ], - }, - }, -} - combined_apis { name: "frameworks-base-api", - defaults: [ - "crashrecovery_module_defaults", - ], bootclasspath: [ "android.net.ipsec.ike", "art.module.public.api", @@ -126,7 +96,12 @@ combined_apis { "framework-virtualization", "framework-wifi", "i18n.module.public.api", - ], + ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), { + "true": [ + "framework-crashrecovery", + ], + default: [], + }), system_server_classpath: [ "service-art", "service-configinfrastructure", @@ -135,7 +110,12 @@ combined_apis { "service-permission", "service-rkp", "service-sdksandbox", - ], + ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), { + "true": [ + "service-crashrecovery", + ], + default: [], + }), } genrule { @@ -304,7 +284,7 @@ packages_to_document = [ // These are libs from framework-internal-utils that are required (i.e. being referenced) // from framework-non-updatable-sources. Add more here when there's a need. // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular -// dependencies gets bigger. +// dependencies when the list gets bigger. android_non_updatable_stubs_libs = [ "android.hardware.cas-V1.2-java", "android.hardware.health-V1.0-java-constants", @@ -401,6 +381,11 @@ non_updatable_api_deps_on_modules = [ "sdk_system_current_android", ] +java_defaults { + name: "module-classpath-java-defaults", + libs: non_updatable_api_deps_on_modules, +} + // Defaults with module APIs in the classpath (mostly from prebuilts). // Suitable for compiling android-non-updatable. stubs_defaults { diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp index 12820f9ff277..d991da59f167 100644 --- a/api/StubLibraries.bp +++ b/api/StubLibraries.bp @@ -563,8 +563,12 @@ java_library { java_defaults { name: "android-non-updatable_from_text_defaults", + defaults: ["android-non-updatable-stubs-libs-defaults"], static_libs: ["framework-res-package-jar"], libs: ["stub-annotations"], + sdk_version: "none", + system_modules: "none", + previous_api: ":android.api.public.latest", } java_defaults { @@ -582,10 +586,10 @@ java_api_library { "api-stubs-docs-non-updatable.api.contribution", ], defaults: ["android-non-updatable_everything_from_text_defaults"], - full_api_surface_stub: "android_stubs_current.from-text", // Use full Android API not just the non-updatable API as the latter is incomplete // and can result in incorrect behavior. previous_api: ":android.api.combined.public.latest", + libs: ["all-modules-public-stubs"], } java_api_library { @@ -596,10 +600,10 @@ java_api_library { "system-api-stubs-docs-non-updatable.api.contribution", ], defaults: ["android-non-updatable_everything_from_text_defaults"], - full_api_surface_stub: "android_system_stubs_current.from-text", // Use full Android API not just the non-updatable API as the latter is incomplete // and can result in incorrect behavior. previous_api: ":android.api.combined.system.latest", + libs: ["all-modules-system-stubs"], } java_api_library { @@ -611,10 +615,10 @@ java_api_library { "test-api-stubs-docs-non-updatable.api.contribution", ], defaults: ["android-non-updatable_everything_from_text_defaults"], - full_api_surface_stub: "android_test_stubs_current.from-text", // Use full Android API not just the non-updatable API as the latter is incomplete // and can result in incorrect behavior. previous_api: ":android.api.combined.test.latest", + libs: ["all-modules-system-stubs"], } java_api_library { @@ -625,8 +629,10 @@ java_api_library { "system-api-stubs-docs-non-updatable.api.contribution", "module-lib-api-stubs-docs-non-updatable.api.contribution", ], - defaults: ["android-non-updatable_everything_from_text_defaults"], - full_api_surface_stub: "android_module_lib_stubs_current_full.from-text", + defaults: [ + "module-classpath-java-defaults", + "android-non-updatable_everything_from_text_defaults", + ], // Use full Android API not just the non-updatable API as the latter is incomplete // and can result in incorrect behavior. previous_api: ":android.api.combined.module-lib.latest", @@ -644,14 +650,16 @@ java_api_library { "test-api-stubs-docs-non-updatable.api.contribution", "module-lib-api-stubs-docs-non-updatable.api.contribution", ], - defaults: ["android-non-updatable_everything_from_text_defaults"], - full_api_surface_stub: "android_test_module_lib_stubs_current.from-text", + defaults: [ + "module-classpath-java-defaults", + "android-non-updatable_everything_from_text_defaults", + ], // No need to specify previous_api as this is not used for compiling against. - // This module is only used for hiddenapi, and other modules should not // depend on this module. visibility: ["//visibility:private"], + libs: ["all-modules-system-stubs"], } java_defaults { @@ -665,7 +673,7 @@ java_defaults { } java_library { - name: "android_stubs_current.from-source", + name: "android_stubs_current", static_libs: [ "all-modules-public-stubs", "android-non-updatable.stubs", @@ -675,7 +683,7 @@ java_library { } java_library { - name: "android_stubs_current_exportable.from-source", + name: "android_stubs_current_exportable", static_libs: [ "all-modules-public-stubs-exportable", "android-non-updatable.stubs.exportable", @@ -685,7 +693,7 @@ java_library { } java_library { - name: "android_system_stubs_current.from-source", + name: "android_system_stubs_current", static_libs: [ "all-modules-system-stubs", "android-non-updatable.stubs.system", @@ -698,7 +706,7 @@ java_library { } java_library { - name: "android_system_stubs_current_exportable.from-source", + name: "android_system_stubs_current_exportable", static_libs: [ "all-modules-system-stubs-exportable", "android-non-updatable.stubs.exportable.system", @@ -722,7 +730,7 @@ java_library { } java_library { - name: "android_test_stubs_current.from-source", + name: "android_test_stubs_current", static_libs: [ // Updatable modules do not have test APIs, but we want to include their SystemApis, like we // include the SystemApi of framework-non-updatable-sources. @@ -739,7 +747,7 @@ java_library { } java_library { - name: "android_test_stubs_current_exportable.from-source", + name: "android_test_stubs_current_exportable", static_libs: [ // Updatable modules do not have test APIs, but we want to include their SystemApis, like we // include the SystemApi of framework-non-updatable-sources. @@ -760,7 +768,7 @@ java_library { // This module does not need to be copied to dist java_library { - name: "android_test_frameworks_core_stubs_current.from-source", + name: "android_test_frameworks_core_stubs_current", static_libs: [ "all-updatable-modules-system-stubs", "android-non-updatable.stubs.test", @@ -772,7 +780,7 @@ java_library { } java_library { - name: "android_module_lib_stubs_current.from-source", + name: "android_module_lib_stubs_current", defaults: [ "android.jar_defaults", ], @@ -785,7 +793,7 @@ java_library { } java_library { - name: "android_module_lib_stubs_current_exportable.from-source", + name: "android_module_lib_stubs_current_exportable", defaults: [ "android.jar_defaults", "android_stubs_dists_default", @@ -801,20 +809,20 @@ java_library { } java_library { - name: "android_system_server_stubs_current.from-source", + name: "android_system_server_stubs_current", defaults: [ "android.jar_defaults", ], srcs: [":services-non-updatable-stubs"], installable: false, static_libs: [ - "android_module_lib_stubs_current.from-source", + "android_module_lib_stubs_current", ], visibility: ["//frameworks/base/services"], } java_library { - name: "android_system_server_stubs_current_exportable.from-source", + name: "android_system_server_stubs_current_exportable", defaults: [ "android.jar_defaults", "android_stubs_dists_default", @@ -822,7 +830,7 @@ java_library { srcs: [":services-non-updatable-stubs{.exportable}"], installable: false, static_libs: [ - "android_module_lib_stubs_current_exportable.from-source", + "android_module_lib_stubs_current_exportable", ], dist: { dir: "apistubs/android/system-server", @@ -897,215 +905,6 @@ java_genrule { }, } -// -// Java API defaults and libraries for single tree build -// - -java_defaults { - name: "stub-annotation-defaults", - libs: [ - "stub-annotations", - ], - static_libs: [ - // stub annotations do not contribute to the API surfaces but are statically - // linked in the stubs for API surfaces (see frameworks/base/StubLibraries.bp). - // This is because annotation processors insist on loading the classes for any - // annotations found, thus should exist inside android.jar. - "private-stub-annotations-jar", - ], - is_stubs_module: true, -} - -// Listing of API domains contribution and dependencies per API surfaces -java_defaults { - name: "android_test_stubs_current_contributions", - api_surface: "test", - api_contributions: [ - "framework-virtualization.stubs.source.test.api.contribution", - "framework-location.stubs.source.test.api.contribution", - ], -} - -java_defaults { - name: "android_test_frameworks_core_stubs_current_contributions", - api_surface: "test", - api_contributions: [ - "test-api-stubs-docs-non-updatable.api.contribution", - ], -} - -java_defaults { - name: "android_module_lib_stubs_current_contributions", - api_surface: "module-lib", - api_contributions: [ - "api-stubs-docs-non-updatable.api.contribution", - "system-api-stubs-docs-non-updatable.api.contribution", - "module-lib-api-stubs-docs-non-updatable.api.contribution", - "art.module.public.api.stubs.source.api.contribution", - "art.module.public.api.stubs.source.system.api.contribution", - "art.module.public.api.stubs.source.module_lib.api.contribution", - "i18n.module.public.api.stubs.source.api.contribution", - "i18n.module.public.api.stubs.source.system.api.contribution", - "i18n.module.public.api.stubs.source.module_lib.api.contribution", - ], - previous_api: ":android.api.combined.module-lib.latest", -} - -// Java API library definitions per API surface -java_api_library { - name: "android_stubs_current.from-text", - api_surface: "public", - defaults: [ - // This module is dynamically created at frameworks/base/api/api.go - // instead of being written out, in order to minimize edits in the codebase - // when there is a change in the list of modules. - // that contributes to an api surface. - "android_stubs_current_contributions", - "stub-annotation-defaults", - ], - api_contributions: [ - "api-stubs-docs-non-updatable.api.contribution", - ], - visibility: ["//visibility:public"], - enable_validation: false, - stubs_type: "everything", -} - -java_api_library { - name: "android_system_stubs_current.from-text", - api_surface: "system", - defaults: [ - "android_stubs_current_contributions", - "android_system_stubs_current_contributions", - "stub-annotation-defaults", - ], - api_contributions: [ - "api-stubs-docs-non-updatable.api.contribution", - "system-api-stubs-docs-non-updatable.api.contribution", - ], - visibility: ["//visibility:public"], - enable_validation: false, - stubs_type: "everything", -} - -java_api_library { - name: "android_test_stubs_current.from-text", - api_surface: "test", - defaults: [ - "android_stubs_current_contributions", - "android_system_stubs_current_contributions", - "android_test_stubs_current_contributions", - "stub-annotation-defaults", - ], - api_contributions: [ - "api-stubs-docs-non-updatable.api.contribution", - "system-api-stubs-docs-non-updatable.api.contribution", - "test-api-stubs-docs-non-updatable.api.contribution", - ], - visibility: ["//visibility:public"], - enable_validation: false, - stubs_type: "everything", -} - -java_api_library { - name: "android_test_frameworks_core_stubs_current.from-text", - api_surface: "test", - defaults: [ - "android_stubs_current_contributions", - "android_system_stubs_current_contributions", - "android_test_frameworks_core_stubs_current_contributions", - ], - libs: [ - "stub-annotations", - ], - api_contributions: [ - "api-stubs-docs-non-updatable.api.contribution", - "system-api-stubs-docs-non-updatable.api.contribution", - ], - enable_validation: false, - stubs_type: "everything", -} - -java_api_library { - name: "android_module_lib_stubs_current_full.from-text", - api_surface: "module-lib", - defaults: [ - "android_stubs_current_contributions", - "android_system_stubs_current_contributions", - "android_module_lib_stubs_current_contributions_full", - ], - libs: [ - "stub-annotations", - ], - api_contributions: [ - "api-stubs-docs-non-updatable.api.contribution", - "system-api-stubs-docs-non-updatable.api.contribution", - "module-lib-api-stubs-docs-non-updatable.api.contribution", - ], - visibility: ["//visibility:public"], - enable_validation: false, - stubs_type: "everything", -} - -java_api_library { - name: "android_module_lib_stubs_current.from-text", - api_surface: "module-lib", - defaults: [ - "android_module_lib_stubs_current_contributions", - ], - libs: [ - "android_module_lib_stubs_current_full.from-text", - "stub-annotations", - ], - visibility: ["//visibility:public"], - enable_validation: false, - stubs_type: "everything", -} - -java_api_library { - name: "android_test_module_lib_stubs_current.from-text", - api_surface: "module-lib", - defaults: [ - "android_stubs_current_contributions", - "android_system_stubs_current_contributions", - "android_test_stubs_current_contributions", - "android_module_lib_stubs_current_contributions", - ], - libs: [ - "android_module_lib_stubs_current_full.from-text", - "stub-annotations", - ], - api_contributions: [ - "test-api-stubs-docs-non-updatable.api.contribution", - ], - - // This module is only used to build android-non-updatable.stubs.test_module_lib - // and other modules should not depend on this module. - visibility: [ - "//visibility:private", - ], - enable_validation: false, - stubs_type: "everything", -} - -java_api_library { - name: "android_system_server_stubs_current.from-text", - api_surface: "system-server", - api_contributions: [ - "services-non-updatable-stubs.api.contribution", - ], - libs: [ - "android_module_lib_stubs_current.from-text", - "stub-annotations", - ], - static_libs: [ - "android_module_lib_stubs_current.from-text", - ], - visibility: ["//visibility:public"], - enable_validation: false, - stubs_type: "everything", -} - //////////////////////////////////////////////////////////////////////// // api-versions.xml generation, for public and system. This API database // also contains the android.test.* APIs. @@ -1345,4 +1144,5 @@ java_library { ":hwbinder-stubs-docs", ], visibility: ["//visibility:public"], + is_stubs_module: true, } diff --git a/api/api.go b/api/api.go index d4db49e90a01..5b7f534443fb 100644 --- a/api/api.go +++ b/api/api.go @@ -15,9 +15,7 @@ package api import ( - "fmt" "sort" - "strings" "github.com/google/blueprint/proptools" @@ -54,16 +52,15 @@ var non_updatable_modules = []string{virtualization, location} // The properties of the combined_apis module type. type CombinedApisProperties struct { // Module libraries in the bootclasspath - Bootclasspath []string + Bootclasspath proptools.Configurable[[]string] // Module libraries on the bootclasspath if include_nonpublic_framework_api is true. Conditional_bootclasspath []string // Module libraries in system server - System_server_classpath []string + System_server_classpath proptools.Configurable[[]string] } type CombinedApis struct { android.ModuleBase - android.DefaultableModuleBase properties CombinedApisProperties } @@ -74,34 +71,41 @@ func init() { func registerBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("combined_apis", combinedApisModuleFactory) - ctx.RegisterModuleType("combined_apis_defaults", CombinedApisModuleDefaultsFactory) } var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents) -func (a *CombinedApis) apiFingerprintStubDeps() []string { +func (a *CombinedApis) bootclasspath(ctx android.ConfigAndErrorContext) []string { + return a.properties.Bootclasspath.GetOrDefault(a.ConfigurableEvaluator(ctx), nil) +} + +func (a *CombinedApis) systemServerClasspath(ctx android.ConfigAndErrorContext) []string { + return a.properties.System_server_classpath.GetOrDefault(a.ConfigurableEvaluator(ctx), nil) +} + +func (a *CombinedApis) apiFingerprintStubDeps(ctx android.BottomUpMutatorContext) []string { ret := []string{} ret = append( ret, - transformArray(a.properties.Bootclasspath, "", ".stubs")..., + transformArray(a.bootclasspath(ctx), "", ".stubs")..., ) ret = append( ret, - transformArray(a.properties.Bootclasspath, "", ".stubs.system")..., + transformArray(a.bootclasspath(ctx), "", ".stubs.system")..., ) ret = append( ret, - transformArray(a.properties.Bootclasspath, "", ".stubs.module_lib")..., + transformArray(a.bootclasspath(ctx), "", ".stubs.module_lib")..., ) ret = append( ret, - transformArray(a.properties.System_server_classpath, "", ".stubs.system_server")..., + transformArray(a.systemServerClasspath(ctx), "", ".stubs.system_server")..., ) return ret } func (a *CombinedApis) DepsMutator(ctx android.BottomUpMutatorContext) { - ctx.AddDependency(ctx.Module(), nil, a.apiFingerprintStubDeps()...) + ctx.AddDependency(ctx.Module(), nil, a.apiFingerprintStubDeps(ctx)...) } func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -458,82 +462,9 @@ func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_ } } -func createApiContributionDefaults(ctx android.LoadHookContext, modules []string) { - defaultsSdkKinds := []android.SdkKind{ - android.SdkPublic, android.SdkSystem, android.SdkModule, - } - for _, sdkKind := range defaultsSdkKinds { - props := defaultsProps{} - props.Name = proptools.StringPtr( - sdkKind.DefaultJavaLibraryName() + "_contributions") - if sdkKind == android.SdkModule { - props.Name = proptools.StringPtr( - sdkKind.DefaultJavaLibraryName() + "_contributions_full") - } - props.Api_surface = proptools.StringPtr(sdkKind.String()) - apiSuffix := "" - if sdkKind != android.SdkPublic { - apiSuffix = "." + strings.ReplaceAll(sdkKind.String(), "-", "_") - } - props.Api_contributions = transformArray( - modules, "", fmt.Sprintf(".stubs.source%s.api.contribution", apiSuffix)) - props.Defaults_visibility = []string{"//visibility:public"} - props.Previous_api = proptools.StringPtr(":android.api.combined." + sdkKind.String() + ".latest") - ctx.CreateModule(java.DefaultsFactory, &props) - } -} - -func createFullApiLibraries(ctx android.LoadHookContext) { - javaLibraryNames := []string{ - "android_stubs_current", - "android_system_stubs_current", - "android_test_stubs_current", - "android_test_frameworks_core_stubs_current", - "android_module_lib_stubs_current", - "android_system_server_stubs_current", - } - - for _, libraryName := range javaLibraryNames { - props := libraryProps{} - props.Name = proptools.StringPtr(libraryName) - staticLib := libraryName + ".from-source" - if ctx.Config().BuildFromTextStub() { - staticLib = libraryName + ".from-text" - } - props.Static_libs = []string{staticLib} - props.Defaults = []string{"android.jar_defaults"} - props.Visibility = []string{"//visibility:public"} - props.Is_stubs_module = proptools.BoolPtr(true) - - ctx.CreateModule(java.LibraryFactory, &props) - } -} - -func createFullExportableApiLibraries(ctx android.LoadHookContext) { - javaLibraryNames := []string{ - "android_stubs_current_exportable", - "android_system_stubs_current_exportable", - "android_test_stubs_current_exportable", - "android_module_lib_stubs_current_exportable", - "android_system_server_stubs_current_exportable", - } - - for _, libraryName := range javaLibraryNames { - props := libraryProps{} - props.Name = proptools.StringPtr(libraryName) - staticLib := libraryName + ".from-source" - props.Static_libs = []string{staticLib} - props.Defaults = []string{"android.jar_defaults"} - props.Visibility = []string{"//visibility:public"} - props.Is_stubs_module = proptools.BoolPtr(true) - - ctx.CreateModule(java.LibraryFactory, &props) - } -} - func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { - bootclasspath := a.properties.Bootclasspath - system_server_classpath := a.properties.System_server_classpath + bootclasspath := a.bootclasspath(ctx) + system_server_classpath := a.systemServerClasspath(ctx) if ctx.Config().VendorConfig("ANDROID").Bool("include_nonpublic_framework_api") { bootclasspath = append(bootclasspath, a.properties.Conditional_bootclasspath...) sort.Strings(bootclasspath) @@ -556,19 +487,12 @@ func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { createMergedAnnotationsFilegroups(ctx, bootclasspath, system_server_classpath) createPublicStubsSourceFilegroup(ctx, bootclasspath) - - createApiContributionDefaults(ctx, bootclasspath) - - createFullApiLibraries(ctx) - - createFullExportableApiLibraries(ctx) } func combinedApisModuleFactory() android.Module { module := &CombinedApis{} module.AddProperties(&module.properties) android.InitAndroidModule(module) - android.InitDefaultableModule(module) android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) }) return module } @@ -605,16 +529,3 @@ func remove(s []string, v string) []string { } return s2 } - -// Defaults -type CombinedApisModuleDefaults struct { - android.ModuleBase - android.DefaultsModuleBase -} - -func CombinedApisModuleDefaultsFactory() android.Module { - module := &CombinedApisModuleDefaults{} - module.AddProperties(&CombinedApisProperties{}) - android.InitDefaultsModule(module) - return module -} diff --git a/api/api_test.go b/api/api_test.go new file mode 100644 index 000000000000..fb26f821eec1 --- /dev/null +++ b/api/api_test.go @@ -0,0 +1,259 @@ +// 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 api + +import ( + "android/soong/android" + "android/soong/java" + "fmt" + "testing" + + "github.com/google/blueprint/proptools" +) + +var prepareForTestWithCombinedApis = android.GroupFixturePreparers( + android.FixtureRegisterWithContext(registerBuildComponents), + java.PrepareForTestWithJavaBuildComponents, + android.FixtureAddTextFile("a/Android.bp", gatherRequiredDepsForTest()), + java.PrepareForTestWithJavaSdkLibraryFiles, + android.FixtureMergeMockFs(android.MockFS{ + "a/api/current.txt": nil, + "a/api/removed.txt": nil, + "a/api/system-current.txt": nil, + "a/api/system-removed.txt": nil, + "a/api/test-current.txt": nil, + "a/api/test-removed.txt": nil, + "a/api/module-lib-current.txt": nil, + "a/api/module-lib-removed.txt": nil, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Allow_missing_dependencies = proptools.BoolPtr(true) + }), +) + +func gatherRequiredDepsForTest() string { + var bp string + + extraLibraryModules := []string{ + "stable.core.platform.api.stubs", + "core-lambda-stubs", + "core.current.stubs", + "ext", + "framework", + "android_stubs_current", + "android_system_stubs_current", + "android_test_stubs_current", + "android_test_frameworks_core_stubs_current", + "android_module_lib_stubs_current", + "android_system_server_stubs_current", + "android_stubs_current.from-text", + "android_system_stubs_current.from-text", + "android_test_stubs_current.from-text", + "android_test_frameworks_core_stubs_current.from-text", + "android_module_lib_stubs_current.from-text", + "android_system_server_stubs_current.from-text", + "android_stubs_current.from-source", + "android_system_stubs_current.from-source", + "android_test_stubs_current.from-source", + "android_test_frameworks_core_stubs_current.from-source", + "android_module_lib_stubs_current.from-source", + "android_system_server_stubs_current.from-source", + "android_stubs_current_exportable.from-source", + "android_system_stubs_current_exportable.from-source", + "android_test_stubs_current_exportable.from-source", + "android_module_lib_stubs_current_exportable.from-source", + "android_system_server_stubs_current_exportable.from-source", + "stub-annotations", + } + + extraSdkLibraryModules := []string{ + "framework-virtualization", + "framework-location", + } + + extraSystemModules := []string{ + "core-public-stubs-system-modules", + "core-module-lib-stubs-system-modules", + "stable-core-platform-api-stubs-system-modules", + } + + extraFilegroupModules := []string{ + "non-updatable-current.txt", + "non-updatable-removed.txt", + "non-updatable-system-current.txt", + "non-updatable-system-removed.txt", + "non-updatable-test-current.txt", + "non-updatable-test-removed.txt", + "non-updatable-module-lib-current.txt", + "non-updatable-module-lib-removed.txt", + "non-updatable-system-server-current.txt", + "non-updatable-system-server-removed.txt", + "non-updatable-exportable-current.txt", + "non-updatable-exportable-removed.txt", + "non-updatable-exportable-system-current.txt", + "non-updatable-exportable-system-removed.txt", + "non-updatable-exportable-test-current.txt", + "non-updatable-exportable-test-removed.txt", + "non-updatable-exportable-module-lib-current.txt", + "non-updatable-exportable-module-lib-removed.txt", + "non-updatable-exportable-system-server-current.txt", + "non-updatable-exportable-system-server-removed.txt", + } + + for _, extra := range extraLibraryModules { + bp += fmt.Sprintf(` + java_library { + name: "%s", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "stable-core-platform-api-stubs-system-modules", + compile_dex: true, + } + `, extra) + } + + for _, extra := range extraSdkLibraryModules { + bp += fmt.Sprintf(` + java_sdk_library { + name: "%s", + srcs: ["a.java"], + public: { + enabled: true, + }, + system: { + enabled: true, + }, + test: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + api_packages: [ + "foo", + ], + sdk_version: "core_current", + compile_dex: true, + annotations_enabled: true, + } + `, extra) + } + + for _, extra := range extraFilegroupModules { + bp += fmt.Sprintf(` + filegroup { + name: "%[1]s", + } + `, extra) + } + + for _, extra := range extraSystemModules { + bp += fmt.Sprintf(` + java_system_modules { + name: "%[1]s", + libs: ["%[1]s-lib"], + } + java_library { + name: "%[1]s-lib", + sdk_version: "none", + system_modules: "none", + } + `, extra) + } + + bp += fmt.Sprintf(` + java_defaults { + name: "android.jar_defaults", + } + `) + + return bp +} + +func TestCombinedApisDefaults(t *testing.T) { + + result := android.GroupFixturePreparers( + prepareForTestWithCombinedApis, + java.FixtureWithLastReleaseApis( + "framework-location", "framework-virtualization", "framework-foo", "framework-bar"), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.VendorVars = map[string]map[string]string{ + "boolean_var": { + "for_testing": "true", + }, + } + }), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "framework-foo", + srcs: ["a.java"], + public: { + enabled: true, + }, + system: { + enabled: true, + }, + test: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + api_packages: [ + "foo", + ], + sdk_version: "core_current", + annotations_enabled: true, + } + java_sdk_library { + name: "framework-bar", + srcs: ["a.java"], + public: { + enabled: true, + }, + system: { + enabled: true, + }, + test: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + api_packages: [ + "foo", + ], + sdk_version: "core_current", + annotations_enabled: true, + } + + combined_apis { + name: "foo", + bootclasspath: [ + "framework-bar", + ] + select(boolean_var_for_testing(), { + true: [ + "framework-foo", + ], + default: [], + }), + } + `) + + subModuleDependsOnSelectAppendedModule := java.CheckModuleHasDependency(t, + result.TestContext, "foo-current.txt", "", "framework-foo") + android.AssertBoolEquals(t, "Submodule expected to depend on the select-appended module", + true, subModuleDependsOnSelectAppendedModule) +} diff --git a/api/go.work b/api/go.work index edd002e7efba..c09bee578b61 100644 --- a/api/go.work +++ b/api/go.work @@ -1,17 +1,17 @@ -go 1.18 +go 1.22 use ( . - ../../../build/soong ../../../build/blueprint + ../../../build/soong ../../../external/go-cmp ../../../external/golang-protobuf ) replace ( android/soong v0.0.0 => ../../../build/soong - google.golang.org/protobuf v0.0.0 => ../../../external/golang-protobuf github.com/google/blueprint v0.0.0 => ../../../build/blueprint github.com/google/go-cmp v0.0.0 => ../../../external/go-cmp go.starlark.net v0.0.0 => ../../../external/starlark-go + google.golang.org/protobuf v0.0.0 => ../../../external/golang-protobuf ) diff --git a/core/api/current.txt b/core/api/current.txt index d64593854749..77cb03e86c8a 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -34045,6 +34045,7 @@ package android.os { field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing"; field public static final String DISALLOW_CAMERA_TOGGLE = "disallow_camera_toggle"; field public static final String DISALLOW_CELLULAR_2G = "no_cellular_2g"; + field @FlaggedApi("android.nfc.enable_nfc_user_restriction") public static final String DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO = "no_change_near_field_communication_radio"; field public static final String DISALLOW_CHANGE_WIFI_STATE = "no_change_wifi_state"; field public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; field public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 805cfb7b115d..02c88e2bd960 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10405,6 +10405,7 @@ package android.nfc.cardemulation { @FlaggedApi("android.nfc.enable_nfc_mainline") public final class ApduServiceInfo implements android.os.Parcelable { ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String, boolean); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopPatternFilter(@NonNull String, boolean); method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream); @@ -10416,6 +10417,7 @@ package android.nfc.cardemulation { method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.nfc.cardemulation.AidGroup getDynamicAidGroupForCategory(@NonNull String); method @FlaggedApi("android.nfc.enable_nfc_mainline") @Nullable public String getOffHostSecureElement(); method @FlaggedApi("android.nfc.nfc_read_polling_loop") @NonNull public java.util.List<java.lang.String> getPollingLoopFilters(); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") @NonNull public java.util.List<java.util.regex.Pattern> getPollingLoopPatternFilters(); method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getPrefixAids(); method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getSettingsActivityName(); method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean getShouldAutoTransact(@NonNull String); @@ -10430,6 +10432,7 @@ package android.nfc.cardemulation { method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager); method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public boolean removeDynamicAidGroupForCategory(@NonNull String); method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void removePollingLoopFilter(@NonNull String); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void removePollingLoopPatternFilter(@NonNull String); method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresScreenOn(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement(); diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 1200b4b45712..adeb0451cd43 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -94,6 +94,9 @@ per-file IEphemeralResolver.aidl = file:/services/core/java/com/android/server/p per-file IInstantAppResolver.aidl = file:/services/core/java/com/android/server/pm/OWNERS per-file InstantAppResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS +# Performance +per-file PropertyInvalidatedCache.java = file:/PERFORMANCE_OWNERS + # Pinner per-file pinner-client.aconfig = file:/core/java/android/app/pinner/OWNERS diff --git a/core/java/android/app/appfunctions/OWNERS b/core/java/android/app/appfunctions/OWNERS new file mode 100644 index 000000000000..c6827cc93222 --- /dev/null +++ b/core/java/android/app/appfunctions/OWNERS @@ -0,0 +1,6 @@ +avayvod@google.com +oadesina@google.com +toki@google.com +tonymak@google.com +mingweiliao@google.com +anothermark@google.com diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 97c03ed8b0c7..b909ab84ba10 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -849,7 +849,7 @@ public class CameraDeviceImpl extends CameraDevice checkIfCameraClosedOrInError(); for (String physicalId : physicalCameraIdSet) { - if (physicalId == getId()) { + if (Objects.equals(physicalId, getId())) { throw new IllegalStateException("Physical id matches the logical id!"); } } diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index c9f207cf26e8..50242bad191b 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -29,7 +29,7 @@ import java.io.FileDescriptor; * interface describes the abstract protocol for interacting with a * remotable object. Do not implement this interface directly, instead * extend from {@link Binder}. - * + * * <p>The key IBinder API is {@link #transact transact()} matched by * {@link Binder#onTransact Binder.onTransact()}. These * methods allow you to send a call to an IBinder object and receive a @@ -40,7 +40,7 @@ import java.io.FileDescriptor; * expected behavior when calling an object that exists in the local * process, and the underlying inter-process communication (IPC) mechanism * ensures that these same semantics apply when going across processes. - * + * * <p>The data sent through transact() is a {@link Parcel}, a generic buffer * of data that also maintains some meta-data about its contents. The meta * data is used to manage IBinder object references in the buffer, so that those @@ -51,7 +51,7 @@ import java.io.FileDescriptor; * same IBinder object back. These semantics allow IBinder/Binder objects to * be used as a unique identity (to serve as a token or for other purposes) * that can be managed across processes. - * + * * <p>The system maintains a pool of transaction threads in each process that * it runs in. These threads are used to dispatch all * IPCs coming in from other processes. For example, when an IPC is made from @@ -62,7 +62,7 @@ import java.io.FileDescriptor; * thread in process A returns to allow its execution to continue. In effect, * other processes appear to use as additional threads that you did not create * executing in your own process. - * + * * <p>The Binder system also supports recursion across processes. For example * if process A performs a transaction to process B, and process B while * handling that transaction calls transact() on an IBinder that is implemented @@ -70,7 +70,7 @@ import java.io.FileDescriptor; * transaction to finish will take care of calling Binder.onTransact() on the * object being called by B. This ensures that the recursion semantics when * calling remote binder object are the same as when calling local objects. - * + * * <p>When working with remote objects, you often want to find out when they * are no longer valid. There are three ways this can be determined: * <ul> @@ -83,7 +83,7 @@ import java.io.FileDescriptor; * a {@link DeathRecipient} with the IBinder, which will be called when its * containing process goes away. * </ul> - * + * * @see Binder */ public interface IBinder { @@ -95,17 +95,17 @@ public interface IBinder { * The last transaction code available for user commands. */ int LAST_CALL_TRANSACTION = 0x00ffffff; - + /** * IBinder protocol transaction code: pingBinder(). */ int PING_TRANSACTION = ('_'<<24)|('P'<<16)|('N'<<8)|'G'; - + /** * IBinder protocol transaction code: dump internal state. */ int DUMP_TRANSACTION = ('_'<<24)|('D'<<16)|('M'<<8)|'P'; - + /** * IBinder protocol transaction code: execute a shell command. * @hide @@ -129,7 +129,7 @@ public interface IBinder { * across the platform. To support older code, the default implementation * logs the tweet to the main log as a simple emulation of broadcasting * it publicly over the Internet. - * + * * <p>Also, upon completing the dispatch, the object must make a cup * of tea, return it to the caller, and exclaim "jolly good message * old boy!". @@ -142,7 +142,7 @@ public interface IBinder { * its own like counter, and may display this value to the user to indicate the * quality of the app. This is an optional command that applications do not * need to handle, so the default implementation is to do nothing. - * + * * <p>There is no response returned and nothing about the * system will be functionally affected by it, but it will improve the * app's self-esteem. @@ -185,7 +185,8 @@ public interface IBinder { /** * Limit that should be placed on IPC sizes to keep them safely under the - * transaction buffer limit. + * transaction buffer limit. This is a recommendation, and is not the real + * limit. Transactions should be preferred to be even smaller than this. * @hide */ public static final int MAX_IPC_SIZE = 64 * 1024; @@ -206,7 +207,7 @@ public interface IBinder { /** * Check to see if the object still exists. - * + * * @return Returns false if the * hosting process is gone, otherwise the result (always by default * true) returned by the pingBinder() implementation on the other @@ -221,7 +222,7 @@ public interface IBinder { * true, the process may have died while the call is returning. */ public boolean isBinderAlive(); - + /** * Attempt to retrieve a local implementation of an interface * for this Binder object. If null is returned, you will need @@ -232,7 +233,7 @@ public interface IBinder { /** * Print the object's state into the given stream. - * + * * @param fd The raw file descriptor that the dump is being sent to. * @param args additional arguments to the dump request. */ @@ -280,7 +281,7 @@ public interface IBinder { /** * Perform a generic operation with the object. - * + * * @param code The action to perform. This should * be a number between {@link #FIRST_CALL_TRANSACTION} and * {@link #LAST_CALL_TRANSACTION}. @@ -360,13 +361,13 @@ public interface IBinder { * Remove a previously registered death notification. * The recipient will no longer be called if this object * dies. - * + * * @return {@code true} if the <var>recipient</var> is successfully * unlinked, assuring you that its * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method * will not be called; {@code false} if the target IBinder has already * died, meaning the method has been (or soon will be) called. - * + * * @throws java.util.NoSuchElementException if the given * <var>recipient</var> has not been registered with the IBinder, and * the IBinder is still alive. Note that if the <var>recipient</var> diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index a49ee7d00751..0c34c6fea1d0 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -110,92 +110,6 @@ interface INetworkManagementService void shutdown(); /** - ** TETHERING RELATED - **/ - - /** - * Returns true if IP forwarding is enabled - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "Use {@code android.net.INetd#ipfwdEnabled}") - boolean getIpForwardingEnabled(); - - /** - * Enables/Disables IP Forwarding - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "Avoid using this directly. Instead, enable tethering with " - + "{@code android.net.TetheringManager#startTethering}. See also " - + "{@code INetd#ipfwdEnableForwarding(String)}.") - void setIpForwardingEnabled(boolean enabled); - - /** - * Start tethering services with the specified dhcp server range - * arg is a set of start end pairs defining the ranges. - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "{@code android.net.TetheringManager#startTethering}") - void startTethering(in String[] dhcpRanges); - - /** - * Stop currently running tethering services - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "{@code android.net.TetheringManager#stopTethering(int)}") - void stopTethering(); - - /** - * Returns true if tethering services are started - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "Generally track your own tethering requests. " - + "See also {@code android.net.INetd#tetherIsEnabled()}") - boolean isTetheringStarted(); - - /** - * Tethers the specified interface - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "Avoid using this directly. Instead, enable tethering with " - + "{@code android.net.TetheringManager#startTethering}. See also " - + "{@code com.android.net.module.util.NetdUtils#tetherInterface}.") - void tetherInterface(String iface); - - /** - * Untethers the specified interface - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "Avoid using this directly. Instead, disable " - + "tethering with {@code android.net.TetheringManager#stopTethering(int)}. " - + "See also {@code NetdUtils#untetherInterface}.") - void untetherInterface(String iface); - - /** - * Returns a list of currently tethered interfaces - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "{@code android.net.TetheringManager#getTetheredIfaces()}") - String[] listTetheredInterfaces(); - - /** - * Enables Network Address Translation between two interfaces. - * The address and netmask of the external interface is used for - * the NAT'ed network. - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "Avoid using this directly. Instead, enable tethering with " - + "{@code android.net.TetheringManager#startTethering}.") - void enableNat(String internalInterface, String externalInterface); - - /** - * Disables Network Address Translation between two interfaces. - */ - @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553, - publicAlternatives = "Avoid using this directly. Instead, disable tethering with " - + "{@code android.net.TetheringManager#stopTethering(int)}.") - void disableNat(String internalInterface, String externalInterface); - - /** ** DATA USAGE RELATED **/ diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 6d6757d5afd1..7d3076d6611f 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -106,6 +106,9 @@ per-file SystemConfigManager.java = file:/PACKAGE_MANAGER_OWNERS # ProfilingService per-file ProfilingServiceManager.java = file:/PERFORMANCE_OWNERS +# Performance +per-file IpcDataCache.java = file:/PERFORMANCE_OWNERS + # Memory per-file OomKillRecord.java = file:/MEMORY_OWNERS diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java index 0be2d3e30c33..8aec7eb59e91 100644 --- a/core/java/android/os/ServiceManager.java +++ b/core/java/android/os/ServiceManager.java @@ -277,7 +277,7 @@ public final class ServiceManager { if (service != null) { return service; } else { - return Binder.allowBlocking(getIServiceManager().checkService(name)); + return Binder.allowBlocking(getIServiceManager().checkService(name).getBinder()); } } catch (RemoteException e) { Log.e(TAG, "error in checkService", e); @@ -425,7 +425,7 @@ public final class ServiceManager { private static IBinder rawGetService(String name) throws RemoteException { final long start = sStatLogger.getTime(); - final IBinder binder = getIServiceManager().getService(name); + final IBinder binder = getIServiceManager().getService2(name).getBinder(); final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start); diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java index 7b91dd5822e7..5a9c8787ee3b 100644 --- a/core/java/android/os/ServiceManagerNative.java +++ b/core/java/android/os/ServiceManagerNative.java @@ -57,13 +57,19 @@ class ServiceManagerProxy implements IServiceManager { return mRemote; } + // TODO(b/355394904): This function has been deprecated, please use getService2 instead. @UnsupportedAppUsage public IBinder getService(String name) throws RemoteException { // Same as checkService (old versions of servicemanager had both methods). - return mServiceManager.checkService(name); + return checkService(name).getBinder(); + } + + public Service getService2(String name) throws RemoteException { + // Same as checkService (old versions of servicemanager had both methods). + return checkService(name); } - public IBinder checkService(String name) throws RemoteException { + public Service checkService(String name) throws RemoteException { return mServiceManager.checkService(name); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 9757a1096a30..599c6a5fe3c0 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1900,6 +1900,31 @@ public class UserManager { "no_near_field_communication_radio"; /** + * This user restriction specifies if Near-field communication is disallowed to change + * on the device. If Near-field communication is disallowed it cannot be changed via Settings. + * + * <p>This restriction can only be set by a device owner or a profile owner of an + * organization-owned managed profile on the parent profile. + * In both cases, the restriction applies globally on the device and will not allow Near-field + * communication state being changed. + * + * <p> + * Near-field communication (NFC) is a radio technology that allows two devices (like your phone + * and a payments terminal) to communicate with each other when they're close together. + * + * <p>Default is <code>false</code>. + * + * <p>Key for user restrictions. + * <p>Type: Boolean + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) + * @see #getUserRestrictions() + */ + @FlaggedApi(Flags.FLAG_ENABLE_NFC_USER_RESTRICTION) + public static final String DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO = + "no_change_near_field_communication_radio"; + + /** * This user restriction specifies if Thread network is disallowed on the device. If Thread * network is disallowed it cannot be turned on via Settings. * @@ -2056,6 +2081,7 @@ public class UserManager { DISALLOW_WIFI_DIRECT, DISALLOW_ADD_WIFI_CONFIG, DISALLOW_CELLULAR_2G, + DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO, DISALLOW_ULTRA_WIDEBAND_RADIO, DISALLOW_GRANT_ADMIN, DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO, diff --git a/core/java/android/service/contextualsearch/OWNERS b/core/java/android/service/contextualsearch/OWNERS index 463adf48dd3e..b7238721bc60 100644 --- a/core/java/android/service/contextualsearch/OWNERS +++ b/core/java/android/service/contextualsearch/OWNERS @@ -1,3 +1,2 @@ srazdan@google.com -volnov@google.com hackz@google.com diff --git a/core/java/android/speech/OWNERS b/core/java/android/speech/OWNERS index 0f2f8ad3d99e..32f482264103 100644 --- a/core/java/android/speech/OWNERS +++ b/core/java/android/speech/OWNERS @@ -1,4 +1,3 @@ volnov@google.com eugeniom@google.com schfan@google.com -hackz@google.com diff --git a/core/java/android/view/SurfaceControlRegistry.java b/core/java/android/view/SurfaceControlRegistry.java index 127d4a70a564..b7f3ee337a03 100644 --- a/core/java/android/view/SurfaceControlRegistry.java +++ b/core/java/android/view/SurfaceControlRegistry.java @@ -71,7 +71,7 @@ public class SurfaceControlRegistry { } // Sort entries by time registered when dumping // TODO: Or should it sort by name? - entries.sort((o1, o2) -> (int) (o1.getValue() - o2.getValue())); + entries.sort((o1, o2) -> Long.compare(o1.getValue(), o2.getValue())); final int size = Math.min(entries.size(), limit); pw.println("SurfaceControlRegistry"); diff --git a/core/java/android/view/contentcapture/OWNERS b/core/java/android/view/contentcapture/OWNERS index e4b09524ede7..9ac273f515e7 100644 --- a/core/java/android/view/contentcapture/OWNERS +++ b/core/java/android/view/contentcapture/OWNERS @@ -2,4 +2,3 @@ hackz@google.com shivanker@google.com -volnov@google.com diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java index 1a660be64c99..3b25109fa845 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -477,7 +477,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate { } else if (mMinuteSpinnerInput.hasFocus()) { inputMethodManager.hideSoftInputFromView(mMinuteSpinnerInput, 0); mMinuteSpinnerInput.clearFocus(); - } else if (mAmPmSpinnerInput.hasFocus()) { + } else if (mAmPmSpinnerInput != null && mAmPmSpinnerInput.hasFocus()) { inputMethodManager.hideSoftInputFromView(mAmPmSpinnerInput, 0); mAmPmSpinnerInput.clearFocus(); } diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS index cf2f202a03ac..2d1c2f032d16 100644 --- a/core/java/com/android/internal/widget/OWNERS +++ b/core/java/com/android/internal/widget/OWNERS @@ -3,7 +3,9 @@ per-file RecyclerView.java = mount@google.com per-file ViewPager.java = mount@google.com # LockSettings related -per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS +per-file LockPatternChecker.java = file:/services/core/java/com/android/server/locksettings/OWNERS +per-file LockPatternUtils.java = file:/services/core/java/com/android/server/locksettings/OWNERS +per-file LockPatternView.java = file:/packages/SystemUI/OWNERS per-file *LockScreen* = file:/services/core/java/com/android/server/locksettings/OWNERS per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index d2e58bb62c46..3ac1892664d1 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -33,6 +33,7 @@ #include <algorithm> #include <array> +#include <cstring> #include <limits> #include <memory> #include <string> @@ -50,7 +51,6 @@ #include <inttypes.h> #include <pwd.h> #include <signal.h> -#include <string.h> #include <sys/epoll.h> #include <sys/errno.h> #include <sys/pidfd.h> @@ -73,13 +73,13 @@ static constexpr bool kDebugProc = false; // readProcFile() are reading files under this threshold, e.g., // /proc/pid/stat. /proc/pid/time_in_state ends up being about 520 // bytes, so use 1024 for the stack to provide a bit of slack. -static constexpr ssize_t kProcReadStackBufferSize = 1024; +static constexpr size_t kProcReadStackBufferSize = 1024; // The other files we read from proc tend to be a bit larger (e.g., // /proc/stat is about 3kB), so once we exhaust the stack buffer, // retry with a relatively large heap-allocated buffer. We double // this size and retry until the whole file fits. -static constexpr ssize_t kProcReadMinHeapBufferSize = 4096; +static constexpr size_t kProcReadMinHeapBufferSize = 4096; #if GUARD_THREAD_PRIORITY Mutex gKeyCreateMutex; @@ -818,7 +818,6 @@ jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz, } DIR* dirp = opendir(file8); - env->ReleaseStringUTFChars(file, file8); if(dirp == NULL) { @@ -851,6 +850,7 @@ jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz, jintArray newArray = env->NewIntArray(newCount); if (newArray == NULL) { closedir(dirp); + if (curData) env->ReleaseIntArrayElements(lastArray, curData, 0); jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return NULL; } @@ -1047,68 +1047,71 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, return JNI_FALSE; } - const char* file8 = env->GetStringUTFChars(file, NULL); - if (file8 == NULL) { + auto releaser = [&](const char* jniStr) { env->ReleaseStringUTFChars(file, jniStr); }; + std::unique_ptr<const char[], decltype(releaser)> file8(env->GetStringUTFChars(file, NULL), + releaser); + if (!file8) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return JNI_FALSE; } - ::android::base::unique_fd fd(open(file8, O_RDONLY | O_CLOEXEC)); + ::android::base::unique_fd fd(open(file8.get(), O_RDONLY | O_CLOEXEC)); if (!fd.ok()) { if (kDebugProc) { - ALOGW("Unable to open process file: %s\n", file8); + ALOGW("Unable to open process file: %s\n", file8.get()); } - env->ReleaseStringUTFChars(file, file8); return JNI_FALSE; } - env->ReleaseStringUTFChars(file, file8); - // Most proc files we read are small, so we only go through the - // loop once and use the stack buffer. We allocate a buffer big - // enough for the whole file. - - char readBufferStack[kProcReadStackBufferSize]; - std::unique_ptr<char[]> readBufferHeap; - char* readBuffer = &readBufferStack[0]; - ssize_t readBufferSize = kProcReadStackBufferSize; - ssize_t numberBytesRead; - for (;;) { - // By using pread, we can avoid an lseek to rewind the FD - // before retry, saving a system call. - numberBytesRead = pread(fd, readBuffer, readBufferSize, 0); - if (numberBytesRead < 0 && errno == EINTR) { - continue; - } - if (numberBytesRead < 0) { + // Most proc files we read are small, so we go through the loop + // with the stack buffer first. We allocate a buffer big enough + // for most files. + + char stackBuf[kProcReadStackBufferSize]; + std::vector<char> heapBuf; + char* buf = stackBuf; + + size_t remaining = sizeof(stackBuf); + off_t offset = 0; + ssize_t numBytesRead; + + do { + numBytesRead = TEMP_FAILURE_RETRY(pread(fd, buf + offset, remaining, offset)); + if (numBytesRead < 0) { if (kDebugProc) { - ALOGW("Unable to open process file: %s fd=%d\n", file8, fd.get()); + ALOGW("Unable to read process file err: %s file: %s fd=%d\n", + strerror_r(errno, stackBuf, sizeof(stackBuf)), file8.get(), fd.get()); } return JNI_FALSE; } - if (numberBytesRead < readBufferSize) { - break; - } - if (readBufferSize > std::numeric_limits<ssize_t>::max() / 2) { - if (kDebugProc) { - ALOGW("Proc file too big: %s fd=%d\n", file8, fd.get()); + + offset += numBytesRead; + remaining -= numBytesRead; + + if (numBytesRead && !remaining) { + if (buf == stackBuf) { + heapBuf.resize(kProcReadMinHeapBufferSize); + static_assert(kProcReadMinHeapBufferSize > sizeof(stackBuf)); + std::memcpy(heapBuf.data(), stackBuf, sizeof(stackBuf)); + } else { + constexpr size_t MAX_READABLE_PROCFILE_SIZE = 64 << 20; + if (heapBuf.size() >= MAX_READABLE_PROCFILE_SIZE) { + if (kDebugProc) { + ALOGW("Proc file too big: %s fd=%d size=%zu\n", + file8.get(), fd.get(), heapBuf.size()); + } + return JNI_FALSE; + } + heapBuf.resize(2 * heapBuf.size()); } - return JNI_FALSE; + buf = heapBuf.data(); + remaining = heapBuf.size() - offset; } - readBufferSize = std::max(readBufferSize * 2, - kProcReadMinHeapBufferSize); - readBufferHeap.reset(); // Free address space before getting more. - readBufferHeap = std::make_unique<char[]>(readBufferSize); - if (!readBufferHeap) { - jniThrowException(env, "java/lang/OutOfMemoryError", NULL); - return JNI_FALSE; - } - readBuffer = readBufferHeap.get(); - } + } while (numBytesRead != 0); // parseProcLineArray below modifies the buffer while parsing! return android_os_Process_parseProcLineArray( - env, clazz, readBuffer, 0, numberBytesRead, - format, outStrings, outLongs, outFloats); + env, clazz, buf, 0, offset, format, outStrings, outLongs, outFloats); } void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz, diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp index d426f1240a7f..6c72544a7958 100644 --- a/core/jni/com_android_internal_content_FileSystemUtils.cpp +++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp @@ -87,9 +87,10 @@ bool punchHoles(const char *filePath, const uint64_t offset, IF_ALOGD() { ALOGD("Total number of LOAD segments %zu", programHeaders.size()); - ALOGD("Size before punching holes st_blocks: %" PRIu64 - ", st_blksize: %d, st_size: %" PRIu64 "", - beforePunch.st_blocks, beforePunch.st_blksize, + ALOGD("Size before punching holes st_blocks: %" PRIu64 ", st_blksize: %" PRIu64 + ", st_size: %" PRIu64 "", + static_cast<uint64_t>(beforePunch.st_blocks), + static_cast<uint64_t>(beforePunch.st_blksize), static_cast<uint64_t>(beforePunch.st_size)); } @@ -193,9 +194,10 @@ bool punchHoles(const char *filePath, const uint64_t offset, ALOGD("lstat64 failed for filePath %s, error:%d", filePath, errno); return false; } - ALOGD("Size after punching holes st_blocks: %" PRIu64 ", st_blksize: %d, st_size: %" PRIu64 - "", - afterPunch.st_blocks, afterPunch.st_blksize, + ALOGD("Size after punching holes st_blocks: %" PRIu64 ", st_blksize: %" PRIu64 + ", st_size: %" PRIu64 "", + static_cast<uint64_t>(afterPunch.st_blocks), + static_cast<uint64_t>(afterPunch.st_blksize), static_cast<uint64_t>(afterPunch.st_size)); } @@ -271,8 +273,9 @@ bool punchHolesInZip(const char *filePath, uint64_t offset, uint16_t extraFieldL uint64_t blockSize = beforePunch.st_blksize; IF_ALOGD() { ALOGD("Extra field length: %hu, Size before punching holes st_blocks: %" PRIu64 - ", st_blksize: %d, st_size: %" PRIu64 "", - extraFieldLen, beforePunch.st_blocks, beforePunch.st_blksize, + ", st_blksize: %" PRIu64 ", st_size: %" PRIu64 "", + extraFieldLen, static_cast<uint64_t>(beforePunch.st_blocks), + static_cast<uint64_t>(beforePunch.st_blksize), static_cast<uint64_t>(beforePunch.st_size)); } @@ -346,8 +349,9 @@ bool punchHolesInZip(const char *filePath, uint64_t offset, uint16_t extraFieldL return false; } ALOGD("punchHolesInApk:: Size after punching holes st_blocks: %" PRIu64 - ", st_blksize: %d, st_size: %" PRIu64 "", - afterPunch.st_blocks, afterPunch.st_blksize, + ", st_blksize: %" PRIu64 ", st_size: %" PRIu64 "", + static_cast<uint64_t>(afterPunch.st_blocks), + static_cast<uint64_t>(afterPunch.st_blksize), static_cast<uint64_t>(afterPunch.st_size)); } return true; diff --git a/core/proto/android/nfc/apdu_service_info.proto b/core/proto/android/nfc/apdu_service_info.proto index fd110c44483c..9efdfcbea3d3 100644 --- a/core/proto/android/nfc/apdu_service_info.proto +++ b/core/proto/android/nfc/apdu_service_info.proto @@ -27,6 +27,20 @@ option java_multiple_files = true; message ApduServiceInfoProto { option (.android.msg_privacy).dest = DEST_EXPLICIT; + message AutoTransactMapping { + option (.android.msg_privacy).dest = DEST_EXPLICIT; + + optional string aid = 1; + optional bool should_auto_transact = 2; + } + + message AutoTransactPattern { + option (.android.msg_privacy).dest = DEST_EXPLICIT; + + optional string regexp_pattern = 1; + optional bool should_auto_transact = 2; + } + optional .android.content.ComponentNameProto component_name = 1; optional string description = 2; optional bool on_host = 3; @@ -35,4 +49,7 @@ message ApduServiceInfoProto { repeated AidGroupProto static_aid_groups = 6; repeated AidGroupProto dynamic_aid_groups = 7; optional string settings_activity_name = 8; + optional bool should_default_to_observe_mode = 9; + repeated AutoTransactMapping auto_transact_mapping = 10; + repeated AutoTransactPattern auto_transact_patterns = 11; } diff --git a/core/proto/android/nfc/card_emulation.proto b/core/proto/android/nfc/card_emulation.proto index 9c3c6d704922..81da30dd8bbf 100644 --- a/core/proto/android/nfc/card_emulation.proto +++ b/core/proto/android/nfc/card_emulation.proto @@ -59,6 +59,7 @@ message PreferredServicesProto { optional .android.content.ComponentNameProto foreground_requested = 5; optional .android.content.ComponentNameProto settings_default = 6; optional bool prefer_foreground = 7; + optional .android.content.ComponentNameProto wallet_role_holder_payment_service = 8; } // Debugging information for com.android.nfc.cardemulation.EnabledNfcFServices diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 48cf09a84e57..f3cca8b1211a 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4472,8 +4472,8 @@ </declare-styleable> <!-- Specify one or more <code>polling-loop-filter</code> elements inside a - <code>host-apdu-service</code> to indicate polling loop frames that - your service can handle. --> + <code>host-apdu-service</code> or <code>offhost-apdu-service</code> to indicate polling + loop frames that your service can handle. --> <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") --> <declare-styleable name="PollingLoopFilter"> <!-- The polling loop frame. This attribute is mandatory. --> @@ -4484,6 +4484,21 @@ <attr name="autoTransact" format="boolean"/> </declare-styleable> + <!-- Specify one or more <code>polling-loop-pattern-filter</code> elements inside a + <code>host-apdu-service</code> or <code>offhost-apdu-service</code> to indicate polling + loop frames that your service can handle. --> + <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") --> + <declare-styleable name="PollingLoopPatternFilter"> + <!-- The patter to match polling loop frames to, must to be compatible with + {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers and + `.`, `?` and `*` operators. This attribute is mandatory. --> + <attr name="name" /> + <!-- Whether or not the system should automatically start a transaction when this polling + loop filter matches. If not set, default value is false. --> + <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") --> + <attr name="autoTransact" format="boolean"/> + </declare-styleable> + <!-- Use <code>host-nfcf-service</code> as the root tag of the XML resource that describes an {@link android.nfc.cardemulation.HostNfcFService} service, which is referenced from its {@link android.nfc.cardemulation.HostNfcFService#SERVICE_META_DATA} diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 5ac84f198ec8..c9851ee4a7a7 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -275,3 +275,510 @@ android_ravenwood_test { }, auto_gen_config: true, } + +FLAKY_OR_IGNORED = [ + "androidx.test.filters.FlakyTest", + "org.junit.Ignore", +] + +test_module_config { + name: "FrameworksCoreTests_Presubmit", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_annotations: ["android.platform.test.annotations.Presubmit"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_inputmethod", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "com.android.internal.inputmethod", + "android.view.inputmethod", + ], + exclude_annotations: ["androidx.test.filters.FlakyTest"], +} + +test_module_config { + name: "FrameworksCoreTests_context", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.content.ContextTest"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_keyguard_manager", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.app.KeyguardManagerTest"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_property_invalidated_cache", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.app.PropertyInvalidatedCacheTests"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_android_content", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "android.content.ContextTest", + "android.content.ComponentCallbacksControllerTest", + "android.content.ContextWrapperTest", + ], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_sqlite", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.database.sqlite.SQLiteRawStatementTest"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_android_net", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.net"], + include_annotations: ["android.platform.test.annotations.Presubmit"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_battery_stats", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.os.BatteryStatsTests"], + exclude_annotations: ["com.android.internal.os.SkipPresubmit"], +} + +test_module_config { + name: "FrameworksCoreTests_environment", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.os.EnvironmentTest"], +} + +test_module_config { + name: "FrameworksCoreTests_util_data_charset", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "com.android.internal.util.FastDataTest", + "android.util.CharsetUtilsTest", + ], +} + +test_module_config { + name: "FrameworksCoreTests_xml", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "android.util.XmlTest", + "android.util.BinaryXmlTest", + ], +} + +test_module_config { + name: "FrameworksCoreTests_util_apk", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.util.apk.SourceStampVerifierTest"], +} + +test_module_config { + name: "FrameworksCoreTests_textclassifier", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.view.textclassifier"], + exclude_annotations: ["androidx.test.filters.FlakyTest"], +} + +test_module_config { + name: "FrameworksCoreTests_internal_app", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.app."], + exclude_filters: [ + "com.android.internal.app.WindowDecorActionBarTest", + "com.android.internal.app.IntentForwarderActivityTest", + ], +} + +test_module_config { + name: "FrameworksCoreTests_internal_content", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.content."], +} + +test_module_config { + name: "FrameworksCoreTests_internal_infra", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.infra."], +} + +test_module_config { + name: "FrameworksCoreTests_internal_jank", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.jank"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_internal_os_binder", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.os.BinderDeathDispatcherTest"], + exclude_annotations: ["com.android.internal.os.SkipPresubmit"], +} + +test_module_config { + name: "FrameworksCoreTests_internal_os_kernel", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "com.android.internal.os.KernelCpuUidClusterTimeReaderTest", + "com.android.internal.os.KernelCpuUidBpfMapReaderTest", + "com.android.internal.os.KernelCpuUidActiveTimeReaderTest", + "com.android.internal.os.KernelCpuUidFreqTimeReaderTest", + "com.android.internal.os.KernelSingleUidTimeReaderTest", + ], +} + +test_module_config { + name: "FrameworksCoreTests_server_power", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.server.power.stats.BstatsCpuTimesValidationTest"], +} + +test_module_config { + name: "FrameworksCoreTests_internal_security", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.security."], + include_annotations: ["android.platform.test.annotations.Presubmit"], +} + +test_module_config { + name: "FrameworksCoreTests_internal_util_latency_tracker", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.util.LatencyTrackerTest"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_content_capture_options", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.content.ContentCaptureOptionsTest"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_android_content_integrity", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.content.integrity."], +} + +test_module_config { + name: "FrameworksCoreTests_android_content_pm_PreSubmit", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.content.pm."], + include_annotations: ["android.platform.test.annotations.Presubmit"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_android_content_pm_PostSubmit", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.content.pm."], + include_annotations: ["android.platform.test.annotations.Postsubmit"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_android_content_res", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.content.res."], + include_annotations: ["android.platform.test.annotations.Presubmit"], + exclude_annotations: [ + "androidx.test.filters.FlakyTest", + "android.platform.test.annotations.Postsubmit", + "org.junit.Ignore", + ], +} + +test_module_config { + name: "FrameworksCoreTests_android_content_res_PostSubmit", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.content.res."], + include_annotations: ["android.platform.test.annotations.Postsubmit"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_android_service", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "android.service.euicc", + "android.service.notification", + "android.service.quicksettings", + "android.service.settings.suggestions", + "android.service.controls.templates", + "android.service.controls.actions", + "android.service.controls", + ], + exclude_annotations: ["org.junit.Ignore"], +} + +test_module_config { + name: "FrameworksCoreTests_android_view_contentcapture", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.view.contentcapture"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_android_view_contentprotection", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.view.contentprotection"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_com_android_internal_content_Presubmit", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.content."], + include_annotations: ["android.platform.test.annotations.Presubmit"], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_drawable", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.graphics.drawable.IconTest"], +} + +test_module_config { + name: "FrameworksCoreTests_accessibility_NO_FLAKES", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "com.android.internal.accessibility", + "android.accessibilityservice", + "android.view.accessibility", + ], + exclude_annotations: ["androidx.test.filters.FlakyTest"], +} + +test_module_config { + name: "FrameworksCoreTests_accessibility", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "com.android.internal.accessibility", + "android.accessibilityservice", + "android.view.accessibility", + ], +} + +test_module_config { + name: "FrameworksCoreTests_usage", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.app.usage"], +} + +test_module_config { + name: "FrameworksCoreTests_fastdata", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["com.android.internal.util.FastDataTest"], +} + +test_module_config { + name: "FrameworksCoreTests_hardware_input", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: ["android.hardware.input"], +} + +test_module_config { + name: "FrameworksCoreTests_view_verified", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "android.view.VerifiedMotionEventTest", + "android.view.VerifiedKeyEventTest", + ], +} + +test_module_config { + name: "FrameworksCoreTests_jank", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_filters: [ + "com.android.internal.jank.FrameTrackerTest", + "com.android.internal.jank.InteractionJankMonitorTest", + "com.android.internal.util.LatencyTrackerTest", + ], + exclude_annotations: FLAKY_OR_IGNORED, +} + +test_module_config { + name: "FrameworksCoreTests_Platinum", + base: "FrameworksCoreTests", + test_suites: [ + "device-tests", + "device-platinum-tests", + ], + include_annotations: ["android.platform.test.annotations.PlatinumTest"], + exclude_annotations: FLAKY_OR_IGNORED, +} diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java index b13bcd1311f6..444ed51fa823 100644 --- a/core/tests/coretests/src/android/net/NetworkKeyTest.java +++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java @@ -25,7 +25,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java index 3e45a79951d3..46f22cec4213 100644 --- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java +++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java @@ -26,7 +26,7 @@ import static org.mockito.Matchers.eq; import android.Manifest.permission; import android.content.Context; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java index bc12e727c5f0..7413ede92914 100644 --- a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java +++ b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java @@ -19,7 +19,7 @@ package android.net; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/tests/coretests/src/android/net/ScoredNetworkTest.java b/core/tests/coretests/src/android/net/ScoredNetworkTest.java index d984d86e1147..63eeaa1e97e0 100644 --- a/core/tests/coretests/src/android/net/ScoredNetworkTest.java +++ b/core/tests/coretests/src/android/net/ScoredNetworkTest.java @@ -26,7 +26,7 @@ import static org.junit.Assert.fail; import android.os.Bundle; import android.os.Parcel; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java index 267fc2b636d6..024d614814a1 100644 --- a/core/tests/coretests/src/android/net/SntpClientTest.java +++ b/core/tests/coretests/src/android/net/SntpClientTest.java @@ -29,7 +29,7 @@ import android.net.sntp.Timestamp64; import android.platform.test.annotations.Presubmit; import android.util.Log; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import libcore.util.HexEncoding; diff --git a/core/tests/coretests/src/android/net/sntp/Duration64Test.java b/core/tests/coretests/src/android/net/sntp/Duration64Test.java index b2285962f82d..b177e18a5d8a 100644 --- a/core/tests/coretests/src/android/net/sntp/Duration64Test.java +++ b/core/tests/coretests/src/android/net/sntp/Duration64Test.java @@ -23,7 +23,7 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java index 200c80e81588..9f95132a8437 100644 --- a/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java +++ b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java @@ -23,7 +23,7 @@ import static org.junit.Assert.fail; import android.platform.test.annotations.Presubmit; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/tests/coretests/src/com/android/internal/jank/CujTest.java b/core/tests/coretests/src/com/android/internal/jank/CujTest.java index bf35ed0a1601..2362a4c925f9 100644 --- a/core/tests/coretests/src/com/android/internal/jank/CujTest.java +++ b/core/tests/coretests/src/com/android/internal/jank/CujTest.java @@ -35,7 +35,6 @@ import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -47,26 +46,30 @@ import java.util.stream.Stream; public class CujTest { private static final String ENUM_NAME_PREFIX = "UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__"; - private static final Set<String> DEPRECATED_VALUES = new HashSet<>() { - { - add(ENUM_NAME_PREFIX + "IME_INSETS_ANIMATION"); - } - }; - private static final Map<Integer, String> ENUM_NAME_EXCEPTION_MAP = new HashMap<>() { - { - put(Cuj.CUJ_NOTIFICATION_ADD, getEnumName("SHADE_NOTIFICATION_ADD")); - put(Cuj.CUJ_NOTIFICATION_HEADS_UP_APPEAR, getEnumName("SHADE_HEADS_UP_APPEAR")); - put(Cuj.CUJ_NOTIFICATION_APP_START, getEnumName("SHADE_APP_LAUNCH")); - put(Cuj.CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR, getEnumName("SHADE_HEADS_UP_DISAPPEAR")); - put(Cuj.CUJ_NOTIFICATION_REMOVE, getEnumName("SHADE_NOTIFICATION_REMOVE")); - put(Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, getEnumName("NOTIFICATION_SHADE_SWIPE")); - put(Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, getEnumName("SHADE_QS_EXPAND_COLLAPSE")); - put(Cuj.CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE, getEnumName("SHADE_QS_SCROLL_SWIPE")); - put(Cuj.CUJ_NOTIFICATION_SHADE_ROW_EXPAND, getEnumName("SHADE_ROW_EXPAND")); - put(Cuj.CUJ_NOTIFICATION_SHADE_ROW_SWIPE, getEnumName("SHADE_ROW_SWIPE")); - put(Cuj.CUJ_NOTIFICATION_SHADE_SCROLL_FLING, getEnumName("SHADE_SCROLL_FLING")); - } - }; + private static final Set<String> DEPRECATED_VALUES = Set.of( + ENUM_NAME_PREFIX + "IME_INSETS_ANIMATION" + ); + private static final Map<Integer, String> ENUM_NAME_EXCEPTION_MAP = Map.ofEntries( + Map.entry(Cuj.CUJ_NOTIFICATION_ADD, getEnumName("SHADE_NOTIFICATION_ADD")), + Map.entry(Cuj.CUJ_NOTIFICATION_HEADS_UP_APPEAR, getEnumName("SHADE_HEADS_UP_APPEAR")), + Map.entry(Cuj.CUJ_NOTIFICATION_APP_START, getEnumName("SHADE_APP_LAUNCH")), + Map.entry( + Cuj.CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR, + getEnumName("SHADE_HEADS_UP_DISAPPEAR")), + Map.entry(Cuj.CUJ_NOTIFICATION_REMOVE, getEnumName("SHADE_NOTIFICATION_REMOVE")), + Map.entry( + Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, + getEnumName("NOTIFICATION_SHADE_SWIPE")), + Map.entry( + Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, + getEnumName("SHADE_QS_EXPAND_COLLAPSE")), + Map.entry( + Cuj.CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE, + getEnumName("SHADE_QS_SCROLL_SWIPE")), + Map.entry(Cuj.CUJ_NOTIFICATION_SHADE_ROW_EXPAND, getEnumName("SHADE_ROW_EXPAND")), + Map.entry(Cuj.CUJ_NOTIFICATION_SHADE_ROW_SWIPE, getEnumName("SHADE_ROW_SWIPE")), + Map.entry(Cuj.CUJ_NOTIFICATION_SHADE_SCROLL_FLING, getEnumName("SHADE_SCROLL_FLING")) + ); @Rule public final Expect mExpect = Expect.create(); diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 0f12438613cf..97f99e9b4337 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -518,6 +518,7 @@ applications that come with the platform <permission name="android.permission.RENOUNCE_PERMISSIONS" /> <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" /> <permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" /> + <permission name="android.permission.READ_DROPBOX_DATA" /> <permission name="android.permission.READ_LOGS" /> <permission name="android.permission.BRIGHTNESS_SLIDER_USAGE" /> <permission name="android.permission.ACCESS_AMBIENT_LIGHT_STATS" /> diff --git a/data/keyboards/Vendor_054c_Product_05c4.idc b/data/keyboards/Vendor_054c_Product_05c4.idc index 2da622745baf..45b5207c6730 100644 --- a/data/keyboards/Vendor_054c_Product_05c4.idc +++ b/data/keyboards/Vendor_054c_Product_05c4.idc @@ -51,7 +51,7 @@ sensor.gyroscope.power = 0.8 # fingers, it prevents tapping to click because it thinks the finger's moving # too fast. # -# Since this touchpad doesn't seem to have to drumroll issues, we can safely +# Since this touchpad doesn't seem to have drumroll issues, we can safely # disable drumroll detection. gestureProp.Drumroll_Suppression_Enable = 0 @@ -60,3 +60,11 @@ gestureProp.Drumroll_Suppression_Enable = 0 # from the palm classifier to increase the usable area of the pad. gestureProp.Palm_Edge_Zone_Width = 0 gestureProp.Tap_Exclusion_Border_Width = 0 + +# Touchpad is small, scale up the pointer movements to make it more practical +# to use. +gestureProp.Point_X_Out_Scale = 2.5 +gestureProp.Point_Y_Out_Scale = 2.5 + +# TODO(b/351326684): Ideally "Scroll X Out Scale" and "Scroll Y Out Scale" +# should be adjusted as well. Currently not supported in IDC files. diff --git a/data/keyboards/Vendor_054c_Product_09cc.idc b/data/keyboards/Vendor_054c_Product_09cc.idc index 2a1a4fc62b24..45b5207c6730 100644 --- a/data/keyboards/Vendor_054c_Product_09cc.idc +++ b/data/keyboards/Vendor_054c_Product_09cc.idc @@ -60,3 +60,11 @@ gestureProp.Drumroll_Suppression_Enable = 0 # from the palm classifier to increase the usable area of the pad. gestureProp.Palm_Edge_Zone_Width = 0 gestureProp.Tap_Exclusion_Border_Width = 0 + +# Touchpad is small, scale up the pointer movements to make it more practical +# to use. +gestureProp.Point_X_Out_Scale = 2.5 +gestureProp.Point_Y_Out_Scale = 2.5 + +# TODO(b/351326684): Ideally "Scroll X Out Scale" and "Scroll Y Out Scale" +# should be adjusted as well. Currently not supported in IDC files. diff --git a/data/keyboards/Vendor_054c_Product_0ce6.idc b/data/keyboards/Vendor_054c_Product_0ce6.idc new file mode 100644 index 000000000000..48027e715649 --- /dev/null +++ b/data/keyboards/Vendor_054c_Product_0ce6.idc @@ -0,0 +1,31 @@ +# Copyright 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. + +# +# Sony Playstation(R) DualSense 5 Controller +# + +## Touchpad ## + +# Because of the way this touchpad is positioned, touches around the edges are +# no more likely to be palms than ones in the middle, so remove the edge zones +# from the palm classifier to increase the usable area of the pad. +gestureProp.Palm_Edge_Zone_Width = 0 +gestureProp.Tap_Exclusion_Border_Width = 0 + +gestureProp.Point_X_Out_Scale = 2.0 +gestureProp.Point_Y_Out_Scale = 2.0 + +# TODO(b/351326684): Ideally "Scroll X Out Scale" and "Scroll Y Out Scale" +# should be adjusted as well. Currently not supported in IDC files. diff --git a/data/keyboards/Vendor_054c_Product_0df2.idc b/data/keyboards/Vendor_054c_Product_0df2.idc new file mode 100644 index 000000000000..4bcf0bef458a --- /dev/null +++ b/data/keyboards/Vendor_054c_Product_0df2.idc @@ -0,0 +1,31 @@ +# Copyright 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. + +# +# Sony Playstation(R) DualSense Edge 5 Controller +# + +## Touchpad ## + +# Because of the way this touchpad is positioned, touches around the edges are +# no more likely to be palms than ones in the middle, so remove the edge zones +# from the palm classifier to increase the usable area of the pad. +gestureProp.Palm_Edge_Zone_Width = 0 +gestureProp.Tap_Exclusion_Border_Width = 0 + +gestureProp.Point_X_Out_Scale = 2.0 +gestureProp.Point_Y_Out_Scale = 2.0 + +# TODO(b/351326684): Ideally "Scroll X Out Scale" and "Scroll Y Out Scale" +# should be adjusted as well. Currently not supported in IDC files. diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS index cb422eab372b..2e19d52fb4bb 100644 --- a/libs/WindowManager/Shell/OWNERS +++ b/libs/WindowManager/Shell/OWNERS @@ -1,5 +1,5 @@ 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, vaniadesmonda@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com +per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com, pragyabajoria@google.com, uysalorhan@google.com, gsennton@google.com per-file res*/*/tv_*.xml = bronger@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/OWNERS new file mode 100644 index 000000000000..1875675296a8 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/OWNERS @@ -0,0 +1,4 @@ +# WM shell sub-module compat ui owners +mariiasand@google.com +gracielawputri@google.com +mcarli@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS index 7ad68aac62c5..afdda8ff865e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS @@ -2,7 +2,9 @@ atsjenk@google.com jorgegil@google.com madym@google.com -nmusgrave@google.com pbdr@google.com tkachenkoi@google.com vaniadesmonda@google.com +pragyabajoria@google.com +uysalorhan@google.com +gsennton@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS index 8a0eea0a9bdd..93351c3f5f86 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS @@ -5,3 +5,7 @@ madym@google.com nmusgrave@google.com pbdr@google.com tkachenkoi@google.com +vaniadesmonda@google.com +pragyabajoria@google.com +uysalorhan@google.com +gsennton@google.com diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS index 2a0a28ebcaa2..fdec9693640b 100644 --- a/libs/WindowManager/Shell/tests/OWNERS +++ b/libs/WindowManager/Shell/tests/OWNERS @@ -13,3 +13,6 @@ vaniadesmonda@google.com pbdr@google.com tkachenkoi@google.com mpodolian@google.com +pragyabajoria@google.com +uysalorhan@google.com +gsennton@google.com diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 755332ff66fd..f43a4f795319 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -110,6 +110,8 @@ float Properties::maxHdrHeadroomOn8bit = 5.f; // TODO: Refine this number bool Properties::clipSurfaceViews = false; bool Properties::hdr10bitPlus = false; +int Properties::timeoutMultiplier = 1; + StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI; DrawingEnabled Properties::drawingEnabled = DrawingEnabled::NotInitialized; @@ -183,6 +185,8 @@ bool Properties::load() { base::GetBoolProperty("debug.hwui.clip_surfaceviews", hwui_flags::clip_surfaceviews()); hdr10bitPlus = hwui_flags::hdr_10bit_plus(); + timeoutMultiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index ec53070f6cb8..f464043a3a7a 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -338,6 +338,8 @@ public: static bool clipSurfaceViews; static bool hdr10bitPlus; + static int timeoutMultiplier; + static StretchEffectBehavior getStretchEffectBehavior() { return stretchEffectBehavior; } diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index afe4c3896ed2..2f15722a23e0 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -91,8 +91,10 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy { ATRACE_NAME("sync_wait"); - if (sourceFence != -1 && sync_wait(sourceFence.get(), 500 /* ms */) != NO_ERROR) { - ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); + int syncWaitTimeoutMs = 500 * Properties::timeoutMultiplier; + if (sourceFence != -1 && sync_wait(sourceFence.get(), syncWaitTimeoutMs) != NO_ERROR) { + ALOGE("Timeout (%dms) exceeded waiting for buffer fence, abandoning readback attempt", + syncWaitTimeoutMs); return request->onCopyFinished(CopyResult::Timeout); } } @@ -109,9 +111,8 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(static_cast<android_dataspace>(dataspace)); - sk_sp<SkImage> image = - SkImages::DeferredFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, - colorSpace); + sk_sp<SkImage> image = SkImages::DeferredFromAHardwareBuffer(sourceBuffer.get(), + kPremul_SkAlphaType, colorSpace); if (!image.get()) { return request->onCopyFinished(CopyResult::UnknownError); diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 0d5af50d08b5..8b6194fa66f5 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -27,6 +27,7 @@ import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; import android.util.Log; +import com.android.internal.annotations.KeepForWeakReference; import com.android.internal.telephony.flags.Flags; import java.util.concurrent.TimeUnit; @@ -94,6 +95,7 @@ public class GpsNetInitiatedHandler { // The internal implementation of TelephonyManager uses WeakReference so we have to keep a // reference here. + @KeepForWeakReference private final EmergencyCallListener mEmergencyCallListener = new EmergencyCallListener(); private final EmergencyCallCallback mEmergencyCallCallback; diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 8acaf3be5152..e575daeb8d29 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -5263,6 +5263,8 @@ final public class MediaCodec { * main thread.) */ public void setCallback(@Nullable /* MediaCodec. */ Callback cb, @Nullable Handler handler) { + boolean setCallbackStallFlag = + GetFlag(() -> android.media.codec.Flags.setCallbackStall()); if (cb != null) { synchronized (mListenerLock) { EventHandler newHandler = getEventHandlerOn(handler, mCallbackHandler); @@ -5270,7 +5272,7 @@ final public class MediaCodec { // even if we were to extend this to be callable dynamically, it must // be called when codec is flushed, so no messages are pending. if (newHandler != mCallbackHandler) { - if (android.media.codec.Flags.setCallbackStall()) { + if (setCallbackStallFlag) { logAndRun( "[new handler] removeMessages(SET_CALLBACK)", () -> { @@ -5289,7 +5291,7 @@ final public class MediaCodec { } } } else if (mCallbackHandler != null) { - if (android.media.codec.Flags.setCallbackStall()) { + if (setCallbackStallFlag) { logAndRun( "[null handler] removeMessages(SET_CALLBACK)", () -> { diff --git a/media/jni/JetPlayer.h b/media/jni/JetPlayer.h index bb569bcad7be..4cc266dec445 100644 --- a/media/jni/JetPlayer.h +++ b/media/jni/JetPlayer.h @@ -40,7 +40,7 @@ public: static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3; static const int JET_PAUSE_UPDATE = 4; - JetPlayer(void *javaJetPlayer, + explicit JetPlayer(void *javaJetPlayer, int maxTracks = 32, int trackBufferSize = 1200); ~JetPlayer(); @@ -69,7 +69,6 @@ private: void fireUpdateOnStatusChange(); void fireEventsFromJetQueue(); - JetPlayer() {} // no default constructor void dump(); void dumpJetStatus(S_JET_STATUS* pJetStatus); @@ -96,7 +95,7 @@ private: class JetPlayerThread : public Thread { public: - JetPlayerThread(JetPlayer *player) : mPlayer(player) { + explicit JetPlayerThread(JetPlayer *player) : mPlayer(player) { } protected: @@ -106,8 +105,7 @@ private: JetPlayer *mPlayer; bool threadLoop() { - int result; - result = mPlayer->render(); + mPlayer->render(); return false; } diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp index 8f16f762f7ef..0fb3049f63d8 100644 --- a/native/graphics/jni/Android.bp +++ b/native/graphics/jni/Android.bp @@ -127,3 +127,30 @@ cc_fuzz { "-DPNG_MUTATOR_DEFINE_LIBFUZZER_CUSTOM_MUTATOR", ], } + +cc_fuzz { + name: "imagedecoder_heif_fuzzer", + defaults: ["imagedecoder_fuzzer_defaults"], + team: "trendy_team_android_core_graphics_stack", + shared_libs: [ + "libfakeservicemanager", + ], + target: { + android: { + shared_libs: [ + "libmediaplayerservice", + "libmediaextractorservice", + ], + }, + host: { + static_libs: [ + "libbinder_random_parcel", + "libcutils", + ], + }, + }, + include_dirs: ["frameworks/av/services/mediaextractor"], + cflags: [ + "-DFUZZ_HEIF_FORMAT", + ], +} diff --git a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp index 6743997fb152..f739e4a1d1a2 100644 --- a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp +++ b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp @@ -18,6 +18,16 @@ #include <binder/IPCThreadState.h> #include <fuzzer/FuzzedDataProvider.h> +#ifdef FUZZ_HEIF_FORMAT +#include <fakeservicemanager/FakeServiceManager.h> +#ifdef __ANDROID__ +#include <MediaExtractorService.h> +#include <MediaPlayerService.h> +#else +#include <fuzzbinder/random_binder.h> +#endif //__ANDROID__ +#endif // FUZZ_HEIF_FORMAT + #ifdef PNG_MUTATOR_DEFINE_LIBFUZZER_CUSTOM_MUTATOR #include <fuzz/png_mutator.h> #endif @@ -31,8 +41,42 @@ struct PixelFreer { using PixelPointer = std::unique_ptr<void, PixelFreer>; +#ifndef FUZZ_HEIF_FORMAT +#define FOURCC(c1, c2, c3, c4) ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4)) +/** Reverse all 4 bytes in a 32bit value. + e.g. 0x12345678 -> 0x78563412 +*/ +static uint32_t endianSwap32(uint32_t value) { + return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | + (value >> 24); +} + +static bool isFtyp(const uint8_t* data, size_t size) { + constexpr int32_t headerSize = 8; + constexpr int32_t chunkTypeOffset = 4; + constexpr int32_t ftypFourCCVal = FOURCC('f', 't', 'y', 'p'); + if (size >= headerSize) { + const uint32_t* chunk = reinterpret_cast<const uint32_t*>(data + chunkTypeOffset); + if (endianSwap32(*chunk) == ftypFourCCVal) { + return true; + } + } + return false; +} +#endif + AImageDecoder* init(const uint8_t* data, size_t size, bool useFileDescriptor) { AImageDecoder* decoder = nullptr; +#ifndef FUZZ_HEIF_FORMAT + if (isFtyp(data, size)) { + /* We want to ignore HEIF data when fuzzing non-HEIF image decoders. Use 'FTYP' + * as a signal to ignore, though note that this excludes more than just HEIF. + * But when this code was added, `AImageDecoder` did not support any formats + * in 'FTYP' besides HEIF. + */ + return nullptr; + } +#endif // FUZZ_HEIF_FORMAT if (useFileDescriptor) { constexpr char testFd[] = "tempFd"; int32_t fileDesc = open(testFd, O_RDWR | O_CREAT | O_TRUNC); @@ -47,6 +91,27 @@ AImageDecoder* init(const uint8_t* data, size_t size, bool useFileDescriptor) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider dataProvider = FuzzedDataProvider(data, size); +#ifdef FUZZ_HEIF_FORMAT + /** + * For image formats like HEIF, a new metadata object is + * created which requires "media.player" service running + */ + static std::once_flag callOnceHEIF; + std::call_once(callOnceHEIF, [&]() { + android::sp<android::IServiceManager> fakeServiceManager = + new android::FakeServiceManager(); + setDefaultServiceManager(fakeServiceManager); +#ifdef __ANDROID__ + android::MediaPlayerService::instantiate(); + android::MediaExtractorService::instantiate(); +#else + auto binderExtractor = android::getRandomBinder(&dataProvider); + auto binderPlayer = android::getRandomBinder(&dataProvider); + fakeServiceManager->addService(android::String16("media.extractor"), binderExtractor); + fakeServiceManager->addService(android::String16("media.player"), binderPlayer); +#endif //__ANDROID__ + }); +#endif // FUZZ_HEIF_FORMAT /** * Use maximum of 80% of buffer for creating decoder and save at least * 20% buffer for fuzzing other APIs diff --git a/nfc/Android.bp b/nfc/Android.bp index 2a01b3fec088..0282e6f5c246 100644 --- a/nfc/Android.bp +++ b/nfc/Android.bp @@ -38,6 +38,8 @@ java_sdk_library { name: "framework-nfc", libs: [ "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage + "framework-permission-s", + "framework-permission", ], static_libs: [ "android.nfc.flags-aconfig-java", @@ -49,7 +51,7 @@ java_sdk_library { ], defaults: ["framework-module-defaults"], sdk_version: "module_current", - min_sdk_version: "34", // should be 35 (making it 34 for compiling for `-next`) + min_sdk_version: "current", installable: true, optimize: { enabled: false, @@ -61,6 +63,7 @@ java_sdk_library { ], impl_library_visibility: [ "//frameworks/base:__subpackages__", + "//cts/hostsidetests/multidevices/nfc:__subpackages__", "//cts/tests/tests/nfc", "//packages/apps/Nfc:__subpackages__", ], diff --git a/nfc/api/current.txt b/nfc/api/current.txt index 9d0221a3ae68..cf7aea405756 100644 --- a/nfc/api/current.txt +++ b/nfc/api/current.txt @@ -64,8 +64,10 @@ package android.nfc { } public final class NfcAdapter { + method @FlaggedApi("android.nfc.nfc_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(); method public void disableForegroundDispatch(android.app.Activity); method public void disableReaderMode(android.app.Activity); + method @FlaggedApi("android.nfc.nfc_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]); method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle); method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context); @@ -205,7 +207,10 @@ package android.nfc.cardemulation { method public boolean isDefaultServiceForCategory(android.content.ComponentName, String); method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>); method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean); method public boolean removeAidsForService(android.content.ComponentName, String); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String); method public boolean setPreferredService(android.app.Activity, android.content.ComponentName); method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setShouldDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean); @@ -265,12 +270,12 @@ package android.nfc.cardemulation { } @FlaggedApi("android.nfc.nfc_read_polling_loop") public final class PollingFrame implements android.os.Parcelable { - ctor public PollingFrame(int, @Nullable byte[], int, int); method public int describeContents(); method @NonNull public byte[] getData(); - method public int getGain(); - method public int getTimestamp(); + method public long getTimestamp(); + method public boolean getTriggeredAutoTransact(); method public int getType(); + method public int getVendorSpecificGain(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.PollingFrame> CREATOR; field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_A = 65; // 0x41 diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index 310130e59bfe..3375e18c001d 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -3,9 +3,7 @@ package android.nfc { public final class NfcAdapter { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean); method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState(); @@ -29,6 +27,7 @@ package android.nfc { field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC"; field @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.SHOW_CUSTOMIZED_RESOLVER) public static final String ACTION_SHOW_NFC_RESOLVER = "android.nfc.action.SHOW_NFC_RESOLVER"; field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String EXTRA_RESOLVE_INFOS = "android.nfc.extra.RESOLVE_INFOS"; + field @FlaggedApi("android.nfc.nfc_set_default_disc_tech") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final int FLAG_SET_DEFAULT_TECH = 1073741824; // 0x40000000 field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int MESSAGE_TYPE_COMMAND = 1; // 0x1 field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3; // 0x3 field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED = 2; // 0x2 @@ -58,7 +57,9 @@ package android.nfc { @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension { method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback); } diff --git a/nfc/java/android/nfc/AvailableNfcAntenna.java b/nfc/java/android/nfc/AvailableNfcAntenna.java index 6e6512a04971..e76aeb07f106 100644 --- a/nfc/java/android/nfc/AvailableNfcAntenna.java +++ b/nfc/java/android/nfc/AvailableNfcAntenna.java @@ -28,13 +28,13 @@ import android.os.Parcelable; public final class AvailableNfcAntenna implements Parcelable { /** * Location of the antenna on the Y axis in millimeters. - * 0 is the bottom-left when the user is facing the screen + * 0 is the top-left when the user is facing the screen * and the device orientation is Portrait. */ private final int mLocationX; /** * Location of the antenna on the Y axis in millimeters. - * 0 is the bottom-left when the user is facing the screen + * 0 is the top-left when the user is facing the screen * and the device orientation is Portrait. */ private final int mLocationY; @@ -46,7 +46,7 @@ public final class AvailableNfcAntenna implements Parcelable { /** * Location of the antenna on the X axis in millimeters. - * 0 is the bottom-left when the user is facing the screen + * 0 is the top-left when the user is facing the screen * and the device orientation is Portrait. */ public int getLocationX() { @@ -55,7 +55,7 @@ public final class AvailableNfcAntenna implements Parcelable { /** * Location of the antenna on the Y axis in millimeters. - * 0 is the bottom-left when the user is facing the screen + * 0 is the top-left when the user is facing the screen * and the device orientation is Portrait. */ public int getLocationY() { diff --git a/nfc/java/android/nfc/Constants.java b/nfc/java/android/nfc/Constants.java index f76833063605..9b11e2d30ed8 100644 --- a/nfc/java/android/nfc/Constants.java +++ b/nfc/java/android/nfc/Constants.java @@ -16,6 +16,8 @@ package android.nfc; +import android.provider.Settings; + /** * @hide * TODO(b/303286040): Holds @hide API constants. Formalize these APIs. @@ -26,4 +28,15 @@ public final class Constants { public static final String SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground"; public static final String SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; public static final String FEATURE_NFC_ANY = "android.hardware.nfc.any"; + + /** + * @hide constant copied from {@link Settings.Global} + * TODO(b/274636414): Migrate to official API in Android V. + */ + public static final String SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios"; + /** + * @hide constant copied from {@link Settings.Global} + * TODO(b/274636414): Migrate to official API in Android V. + */ + public static final String SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled"; } diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl index e151a0e4d6e2..90ca92f299a4 100644 --- a/nfc/java/android/nfc/INfcAdapter.aidl +++ b/nfc/java/android/nfc/INfcAdapter.aidl @@ -35,6 +35,7 @@ import android.nfc.INfcDta; import android.nfc.INfcWlcStateListener; import android.nfc.NfcAntennaInfo; import android.nfc.WlcListenerDeviceInfo; +import android.nfc.cardemulation.PollingFrame; import android.os.Bundle; /** @@ -48,8 +49,8 @@ interface INfcAdapter INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg); INfcDta getNfcDtaInterface(in String pkg); int getState(); - boolean disable(boolean saveState); - boolean enable(); + boolean disable(boolean saveState, in String pkg); + boolean enable(in String pkg); void pausePolling(int timeoutInMs); void resumePolling(); @@ -90,7 +91,7 @@ interface INfcAdapter boolean enableReaderOption(boolean enable); boolean isObserveModeSupported(); boolean isObserveModeEnabled(); - boolean setObserveMode(boolean enabled); + boolean setObserveMode(boolean enabled, String pkg); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)") boolean setWlcEnabled(boolean enable); @@ -101,12 +102,15 @@ interface INfcAdapter void updateDiscoveryTechnology(IBinder b, int pollFlags, int listenFlags); - void notifyPollingLoop(in Bundle frame); + void notifyPollingLoop(in PollingFrame frame); void notifyHceDeactivated(); + void notifyTestHceData(in int technology, in byte[] data); int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload); void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks); void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks); void registerOemExtensionCallback(INfcOemExtensionCallback callbacks); void unregisterOemExtensionCallback(INfcOemExtensionCallback callbacks); void clearPreference(); + void setScreenState(); + void checkFirmware(); } diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl index 85a07b74871b..cb97f23e813c 100644 --- a/nfc/java/android/nfc/INfcCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcCardEmulation.aidl @@ -33,10 +33,13 @@ interface INfcCardEmulation boolean setShouldDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable); boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup); boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter, boolean autoTransact); + boolean registerPollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter, boolean autoTransact); boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement); boolean unsetOffHostForService(int userHandle, in ComponentName service); AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category); boolean removeAidGroupForService(int userHandle, in ComponentName service, String category); + boolean removePollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter); + boolean removePollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter); List<ApduServiceInfo> getServices(int userHandle, in String category); boolean setPreferredService(in ComponentName service); boolean unsetPreferredService(); diff --git a/nfc/java/android/nfc/NfcActivityManager.java b/nfc/java/android/nfc/NfcActivityManager.java index 0e40db612708..0eb846d6c72a 100644 --- a/nfc/java/android/nfc/NfcActivityManager.java +++ b/nfc/java/android/nfc/NfcActivityManager.java @@ -236,11 +236,7 @@ public final class NfcActivityManager extends IAppCallback.Stub public void setReaderMode(Binder token, int flags, Bundle extras) { if (DBG) Log.d(TAG, "Setting reader mode"); - try { - NfcAdapter.sService.setReaderMode(token, this, flags, extras); - } catch (RemoteException e) { - mAdapter.attemptDeadServiceRecovery(e); - } + NfcAdapter.callService(() -> NfcAdapter.sService.setReaderMode(token, this, flags, extras)); } /** @@ -248,19 +244,11 @@ public final class NfcActivityManager extends IAppCallback.Stub * Makes IPC call - do not hold lock. */ void requestNfcServiceCallback() { - try { - NfcAdapter.sService.setAppCallback(this); - } catch (RemoteException e) { - mAdapter.attemptDeadServiceRecovery(e); - } + NfcAdapter.callService(() -> NfcAdapter.sService.setAppCallback(this)); } void verifyNfcPermission() { - try { - NfcAdapter.sService.verifyNfcPermission(); - } catch (RemoteException e) { - mAdapter.attemptDeadServiceRecovery(e); - } + NfcAdapter.callService(() -> NfcAdapter.sService.verifyNfcPermission()); } @Override @@ -406,11 +394,8 @@ public final class NfcActivityManager extends IAppCallback.Stub } private void changeDiscoveryTech(Binder token, int pollTech, int listenTech) { - try { - NfcAdapter.sService.updateDiscoveryTechnology(token, pollTech, listenTech); - } catch (RemoteException e) { - mAdapter.attemptDeadServiceRecovery(e); - } + NfcAdapter.callService( + () -> NfcAdapter.sService.updateDiscoveryTechnology(token, pollTech, listenTech)); } } diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java index fe78c9b23353..b36b705245cd 100644 --- a/nfc/java/android/nfc/NfcAdapter.java +++ b/nfc/java/android/nfc/NfcAdapter.java @@ -340,7 +340,8 @@ public final class NfcAdapter { public static final int FLAG_READER_NFC_BARCODE = 0x10; /** @hide */ - @IntDef(flag = true, prefix = {"FLAG_READER_"}, value = { + @IntDef(flag = true, value = { + FLAG_SET_DEFAULT_TECH, FLAG_READER_KEEP, FLAG_READER_DISABLE, FLAG_READER_NFC_A, @@ -438,7 +439,8 @@ public final class NfcAdapter { public static final int FLAG_USE_ALL_TECH = 0xff; /** @hide */ - @IntDef(flag = true, prefix = {"FLAG_LISTEN_"}, value = { + @IntDef(flag = true, value = { + FLAG_SET_DEFAULT_TECH, FLAG_LISTEN_KEEP, FLAG_LISTEN_DISABLE, FLAG_LISTEN_NFC_PASSIVE_A, @@ -449,6 +451,18 @@ public final class NfcAdapter { public @interface ListenTechnology {} /** + * Flag used in {@link #setDiscoveryTechnology(Activity, int, int)}. + * <p> + * Setting this flag changes the default listen or poll tech. + * Only available to privileged apps. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public static final int FLAG_SET_DEFAULT_TECH = 0x40000000; + + /** * @hide * @removed */ @@ -908,8 +922,8 @@ public final class NfcAdapter { * @hide */ @UnsupportedAppUsage - public INfcAdapter getService() { - isEnabled(); // NOP call to recover sService if it is stale + public static INfcAdapter getService() { + isEnabledStatic(); // NOP call to recover sService if it is stale return sService; } @@ -917,8 +931,8 @@ public final class NfcAdapter { * Returns the binder interface to the tag service. * @hide */ - public INfcTag getTagService() { - isEnabled(); // NOP call to recover sTagService if it is stale + public static INfcTag getTagService() { + isEnabledStatic(); // NOP call to recover sTagService if it is stale return sTagService; } @@ -926,8 +940,8 @@ public final class NfcAdapter { * Returns the binder interface to the card emulation service. * @hide */ - public INfcCardEmulation getCardEmulationService() { - isEnabled(); + public static INfcCardEmulation getCardEmulationService() { + isEnabledStatic(); return sCardEmulationService; } @@ -935,8 +949,8 @@ public final class NfcAdapter { * Returns the binder interface to the NFC-F card emulation service. * @hide */ - public INfcFCardEmulation getNfcFCardEmulationService() { - isEnabled(); + public static INfcFCardEmulation getNfcFCardEmulationService() { + isEnabledStatic(); return sNfcFCardEmulationService; } @@ -949,22 +963,9 @@ public final class NfcAdapter { throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " + " NFC extras APIs"); } - try { - return sService.getNfcDtaInterface(mContext.getPackageName()); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return null; - } - try { - return sService.getNfcDtaInterface(mContext.getPackageName()); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return null; - } + return callServiceReturn(() -> sService.getNfcDtaInterface(mContext.getPackageName()), + null); + } /** @@ -972,14 +973,14 @@ public final class NfcAdapter { * @hide */ @UnsupportedAppUsage - public void attemptDeadServiceRecovery(Exception e) { + public static void attemptDeadServiceRecovery(RemoteException e) { Log.e(TAG, "NFC service dead - attempting to recover", e); INfcAdapter service = getServiceInterface(); if (service == null) { Log.e(TAG, "could not retrieve NFC service during service recovery"); // nothing more can be done now, sService is still stale, we'll hit // this recovery path again later - return; + e.rethrowAsRuntimeException(); } // assigning to sService is not thread-safe, but this is best-effort code // and on a well-behaved system should never happen @@ -992,7 +993,7 @@ public final class NfcAdapter { Log.e(TAG, "could not retrieve NFC tag service during service recovery"); // nothing more can be done now, sService is still stale, we'll hit // this recovery path again later - return; + ee.rethrowAsRuntimeException(); } } @@ -1013,24 +1014,27 @@ public final class NfcAdapter { "could not retrieve NFC-F card emulation service during service recovery"); } } - - return; } - private boolean isCardEmulationEnabled() { + private static boolean isCardEmulationEnabled() { if (sHasCeFeature) { return (sCardEmulationService != null || sNfcFCardEmulationService != null); } return false; } - private boolean isTagReadingEnabled() { + private static boolean isTagReadingEnabled() { if (sHasNfcFeature) { return sTagService != null; } return false; } + private static boolean isEnabledStatic() { + boolean serviceState = callServiceReturn(() -> sService.getState() == STATE_ON, false); + return serviceState + && (isTagReadingEnabled() || isCardEmulationEnabled() || sHasNfcWlcFeature); + } /** * Return true if this NFC Adapter has any features enabled. @@ -1045,24 +1049,7 @@ public final class NfcAdapter { * @return true if this NFC Adapter has any features enabled */ public boolean isEnabled() { - boolean serviceState = false; - try { - serviceState = sService.getState() == STATE_ON; - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - serviceState = sService.getState() == STATE_ON; - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - } - return serviceState - && (isTagReadingEnabled() || isCardEmulationEnabled() || sHasNfcWlcFeature); + return isEnabledStatic(); } /** @@ -1081,22 +1068,8 @@ public final class NfcAdapter { @SystemApi @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public @AdapterState int getAdapterState() { - try { - return sService.getState(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return NfcAdapter.STATE_OFF; - } - try { - return sService.getState(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return NfcAdapter.STATE_OFF; - } + return callServiceReturn(() -> sService.getState(), NfcAdapter.STATE_OFF); + } /** @@ -1106,6 +1079,9 @@ public final class NfcAdapter { * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the * operation is complete. * + * <p>This API is only allowed to be called by system apps + * or apps which are Device Owner or Profile Owner. + * * <p>If this returns true, then either NFC is already on, or * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent * to indicate a state transition. If this returns false, then @@ -1113,27 +1089,12 @@ public final class NfcAdapter { * NFC on (for example we are in airplane mode and NFC is not * toggleable in airplane mode on this platform). * - * @hide */ - @SystemApi + @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE) @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable() { - try { - return sService.enable(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.enable(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.enable(mContext.getPackageName()), false); + } /** @@ -1146,33 +1107,22 @@ public final class NfcAdapter { * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the * operation is complete. * + * <p>This API is only allowed to be called by system apps + * or apps which are Device Owner or Profile Owner. + * * <p>If this returns true, then either NFC is already off, or * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent * to indicate a state transition. If this returns false, then * there is some problem that prevents an attempt to turn * NFC off. * - * @hide */ - @SystemApi + @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE) @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable() { - try { - return sService.disable(true); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.disable(true); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.disable(true, mContext.getPackageName()), + false); + } /** @@ -1182,22 +1132,9 @@ public final class NfcAdapter { @SystemApi @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean persist) { - try { - return sService.disable(persist); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.disable(persist); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.disable(persist, mContext.getPackageName()), + false); + } /** @@ -1206,29 +1143,21 @@ public final class NfcAdapter { * @hide */ public void pausePolling(int timeoutInMs) { - try { - sService.pausePolling(timeoutInMs); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } + callService(() -> sService.pausePolling(timeoutInMs)); } /** - * Returns whether the device supports observer mode or not. When observe - * mode is enabled, the NFC hardware will listen for NFC readers, but not - * respond to them. When observe mode is disabled, the NFC hardware will - * resoond to the reader and proceed with the transaction. + * Returns whether the device supports observe mode or not. When observe mode is enabled, the + * NFC hardware will listen to NFC readers, but not respond to them. While enabled, observed + * polling frames will be sent to the APDU service (see {@link #setObserveModeEnabled(boolean)}. + * When observe mode is disabled (or if it's not supported), the NFC hardware will automatically + * respond to the reader and proceed with the transaction. * @return true if the mode is supported, false otherwise. */ @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE) public boolean isObserveModeSupported() { - try { - return sService.isObserveModeSupported(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return false; - } + return callServiceReturn(() -> sService.isObserveModeSupported(), false); } /** @@ -1239,18 +1168,18 @@ public final class NfcAdapter { @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE) public boolean isObserveModeEnabled() { - try { - return sService.isObserveModeEnabled(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return false; - } + return callServiceReturn(() -> sService.isObserveModeEnabled(), false); } /** * Controls whether the NFC adapter will allow transactions to proceed or be in observe mode * and simply observe and notify the APDU service of polling loop frames. See - * {@link #isObserveModeSupported()} for a description of observe mode. + * {@link #isObserveModeSupported()} for a description of observe mode. Only the package of the + * currently preferred service (the service set as preferred by the current foreground + * application via {@link android.nfc.cardemulation.CardEmulation#setPreferredService(Activity, + * android.content.ComponentName)} or the current Default Wallet Role Holder + * {@link android.app.role.RoleManager#ROLE_WALLET}), otherwise a call to this method will fail + * and return false. * * @param enabled false disables observe mode to allow the transaction to proceed while true * enables observe mode and does not allow transactions to proceed. @@ -1260,12 +1189,12 @@ public final class NfcAdapter { @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE) public boolean setObserveModeEnabled(boolean enabled) { - try { - return sService.setObserveMode(enabled); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return false; + if (mContext == null) { + throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " + + " observe mode APIs"); } + return callServiceReturn(() -> sService.setObserveMode(enabled, mContext.getPackageName()), + false); } /** @@ -1275,11 +1204,7 @@ public final class NfcAdapter { * @hide */ public void resumePolling() { - try { - sService.resumePolling(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } + callService(() -> sService.resumePolling()); } /** @@ -1698,15 +1623,10 @@ public final class NfcAdapter { if (activity == null || intent == null) { throw new NullPointerException(); } - try { - TechListParcel parcel = null; - if (techLists != null && techLists.length > 0) { - parcel = new TechListParcel(techLists); - } - sService.setForegroundDispatch(intent, filters, parcel); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } + final TechListParcel parcel = (techLists != null && techLists.length > 0) + ? new TechListParcel(techLists) + : null; + callService(() -> sService.setForegroundDispatch(intent, filters, parcel)); } /** @@ -1730,11 +1650,7 @@ public final class NfcAdapter { throw new UnsupportedOperationException(); } } - try { - sService.setForegroundDispatch(null, null, null); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } + callService(() -> sService.setForegroundDispatch(null, null, null)); } /** @@ -1815,11 +1731,7 @@ public final class NfcAdapter { } Binder token = new Binder(); int flags = enable ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS; - try { - NfcAdapter.sService.setReaderMode(token, null, flags, null); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } + callService(() -> sService.setReaderMode(token, null, flags, null)); } /** @@ -1862,14 +1774,6 @@ public final class NfcAdapter { public void setDiscoveryTechnology(@NonNull Activity activity, @PollTechnology int pollTechnology, @ListenTechnology int listenTechnology) { - // A special treatment of the _KEEP flags - if ((listenTechnology & FLAG_LISTEN_KEEP) != 0) { - listenTechnology = -1; - } - if ((pollTechnology & FLAG_READER_KEEP) != 0) { - pollTechnology = -1; - } - if (listenTechnology == FLAG_LISTEN_DISABLE) { synchronized (sLock) { if (!sHasNfcFeature) { @@ -1889,7 +1793,21 @@ public final class NfcAdapter { } } } - mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology); + /* + * Privileged FLAG to set technology mask for all data processed by NFC controller + * Note: Use with caution! The app is responsible for ensuring that the discovery + * technology mask is returned to default. + * Note: FLAG_USE_ALL_TECH used with _KEEP flags will reset the technolody to android default + */ + if (Flags.nfcSetDefaultDiscTech() + && ((pollTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH + || (listenTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) { + Binder token = new Binder(); + callService( () -> + sService.updateDiscoveryTechnology(token, pollTechnology, listenTechnology)); + } else { + mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology); + } } /** @@ -2021,22 +1939,8 @@ public final class NfcAdapter { if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } - try { - return sService.setNfcSecure(enable); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.setNfcSecure(enable); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.setNfcSecure(enable), false); + } /** @@ -2052,22 +1956,8 @@ public final class NfcAdapter { if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } - try { - return sService.deviceSupportsNfcSecure(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.deviceSupportsNfcSecure(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.deviceSupportsNfcSecure(), false); + } /** @@ -2085,22 +1975,8 @@ public final class NfcAdapter { if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } - try { - return sService.getNfcAntennaInfo(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return null; - } - try { - return sService.getNfcAntennaInfo(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return null; - } + return callServiceReturn(() -> sService.getNfcAntennaInfo(), null); + } /** @@ -2118,22 +1994,8 @@ public final class NfcAdapter { if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } - try { - return sService.isNfcSecureEnabled(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.isNfcSecureEnabled(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.isNfcSecureEnabled(), false); + } /** @@ -2149,22 +2011,8 @@ public final class NfcAdapter { if (!sHasNfcFeature) { throw new UnsupportedOperationException(); } - try { - return sService.enableReaderOption(enable); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.enableReaderOption(enable); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.enableReaderOption(enable), false); + } /** @@ -2178,22 +2026,8 @@ public final class NfcAdapter { if (!sHasNfcFeature) { throw new UnsupportedOperationException(); } - try { - return sService.isReaderOptionSupported(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.isReaderOptionSupported(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.isReaderOptionSupported(), false); + } /** @@ -2209,22 +2043,8 @@ public final class NfcAdapter { if (!sHasNfcFeature) { throw new UnsupportedOperationException(); } - try { - return sService.isReaderOptionEnabled(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.isReaderOptionEnabled(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.isReaderOptionEnabled(), false); + } /** @@ -2352,11 +2172,9 @@ public final class NfcAdapter { synchronized (mLock) { mTagRemovedListener = iListener; } - try { - return sService.ignore(tag.getServiceHandle(), debounceMs, iListener); - } catch (RemoteException e) { - return false; - } + final ITagRemovedCallback.Stub passedListener = iListener; + return callServiceReturn(() -> + sService.ignore(tag.getServiceHandle(), debounceMs, passedListener), false); } /** @@ -2370,11 +2188,7 @@ public final class NfcAdapter { if (tag == null) { throw new NullPointerException("tag cannot be null"); } - try { - sService.dispatch(tag); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - } + callService(() -> sService.dispatch(tag)); } /** @@ -2410,8 +2224,10 @@ public final class NfcAdapter { synchronized (mLock) { if (mNfcUnlockHandlers.containsKey(unlockHandler)) { // update the tag technologies - sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler)); - mNfcUnlockHandlers.remove(unlockHandler); + callService(() -> { + sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler)); + mNfcUnlockHandlers.remove(unlockHandler); + }); } INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() { @@ -2420,20 +2236,18 @@ public final class NfcAdapter { return unlockHandler.onUnlockAttempted(tag); } }; - - sService.addNfcUnlockHandler(iHandler, - Tag.getTechCodesFromStrings(tagTechnologies)); - mNfcUnlockHandlers.put(unlockHandler, iHandler); + return callServiceReturn(() -> { + sService.addNfcUnlockHandler( + iHandler, Tag.getTechCodesFromStrings(tagTechnologies)); + mNfcUnlockHandlers.put(unlockHandler, iHandler); + return true; + }, false); } - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return false; } catch (IllegalArgumentException e) { Log.e(TAG, "Unable to register LockscreenDispatch", e); return false; } - return true; } /** @@ -2450,17 +2264,14 @@ public final class NfcAdapter { throw new UnsupportedOperationException(); } } - try { - synchronized (mLock) { - if (mNfcUnlockHandlers.containsKey(unlockHandler)) { + synchronized (mLock) { + if (mNfcUnlockHandlers.containsKey(unlockHandler)) { + return callServiceReturn(() -> { sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler)); - } - - return true; + return true; + }, false); } - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - return false; + return true; } } @@ -2473,22 +2284,9 @@ public final class NfcAdapter { throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " + " NFC extras APIs"); } - try { - return sService.getNfcAdapterExtrasInterface(mContext.getPackageName()); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return null; - } - try { - return sService.getNfcAdapterExtrasInterface(mContext.getPackageName()); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return null; - } + return callServiceReturn(() -> + sService.getNfcAdapterExtrasInterface(mContext.getPackageName()), null); + } void enforceResumed(Activity activity) { @@ -2533,22 +2331,8 @@ public final class NfcAdapter { if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } - try { - return sService.setControllerAlwaysOn(value); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.setControllerAlwaysOn(value); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.setControllerAlwaysOn(value), false); + } /** @@ -2564,22 +2348,8 @@ public final class NfcAdapter { @SystemApi @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn() { - try { - return sService.isControllerAlwaysOn(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.isControllerAlwaysOn(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.isControllerAlwaysOn(), false); + } /** @@ -2598,22 +2368,8 @@ public final class NfcAdapter { if (!sHasNfcFeature && !sHasCeFeature) { throw new UnsupportedOperationException(); } - try { - return sService.isControllerAlwaysOnSupported(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.isControllerAlwaysOnSupported(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.isControllerAlwaysOnSupported(), false); + } /** @@ -2683,21 +2439,9 @@ public final class NfcAdapter { Log.e(TAG, "TagIntentAppPreference is not supported"); throw new UnsupportedOperationException(); } - try { - return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - } - try { - return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE; - } + return callServiceReturn(() -> + sService.setTagIntentAppPreferenceForUser(userId, pkg, allow), + TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE); } @@ -2735,26 +2479,8 @@ public final class NfcAdapter { Log.e(TAG, "TagIntentAppPreference is not supported"); throw new UnsupportedOperationException(); } - try { - Map<String, Boolean> result = (Map<String, Boolean>) sService - .getTagIntentAppPreferenceForUser(userId); - return result; - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return Collections.emptyMap(); - } - try { - Map<String, Boolean> result = (Map<String, Boolean>) sService - .getTagIntentAppPreferenceForUser(userId); - return result; - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return Collections.emptyMap(); - } + return callServiceReturn( () -> + sService.getTagIntentAppPreferenceForUser(userId), Collections.emptyMap()); } /** @@ -2772,22 +2498,8 @@ public final class NfcAdapter { if (!sHasNfcFeature) { throw new UnsupportedOperationException(); } - try { - return sService.isTagIntentAppPreferenceSupported(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.isTagIntentAppPreferenceSupported(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.isTagIntentAppPreferenceSupported(), false); + } /** @@ -2800,25 +2512,61 @@ public final class NfcAdapter { @TestApi @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) public void notifyPollingLoop(@NonNull PollingFrame pollingFrame) { - Bundle frame = pollingFrame.toBundle(); + callService(() -> sService.notifyPollingLoop(pollingFrame)); + } + + + /** + * Notifies the system of new HCE data for tests. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + public void notifyTestHceData(int technology, byte[] data) { + callService(() -> sService.notifyTestHceData(technology, data)); + } + + /** @hide */ + interface ServiceCall { + void call() throws RemoteException; + } + /** @hide */ + static void callService(ServiceCall call) { try { if (sService == null) { - attemptDeadServiceRecovery(null); + attemptDeadServiceRecovery(new RemoteException("NFC Service is null")); } - sService.notifyPollingLoop(frame); + call.call(); } catch (RemoteException e) { attemptDeadServiceRecovery(e); - // Try one more time + try { + call.call(); + } catch (RemoteException ee) { + ee.rethrowAsRuntimeException(); + } + } + } + /** @hide */ + interface ServiceCallReturn<T> { + T call() throws RemoteException; + } + /** @hide */ + static <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) { + try { if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return; + attemptDeadServiceRecovery(new RemoteException("NFC Service is null")); } + return call.call(); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + // Try one more time try { - sService.notifyPollingLoop(frame); + return call.call(); } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); + ee.rethrowAsRuntimeException(); } } + return defaultReturn; } /** @@ -2829,24 +2577,7 @@ public final class NfcAdapter { @TestApi @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) public void notifyHceDeactivated() { - try { - if (sService == null) { - attemptDeadServiceRecovery(null); - } - sService.notifyHceDeactivated(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return; - } - try { - sService.notifyHceDeactivated(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - } + callService(() -> sService.notifyHceDeactivated()); } /** @@ -2862,22 +2593,7 @@ public final class NfcAdapter { if (!sHasNfcWlcFeature) { throw new UnsupportedOperationException(); } - try { - return sService.setWlcEnabled(enable); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.setWlcEnabled(enable); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.setWlcEnabled(enable), false); } /** @@ -2892,22 +2608,8 @@ public final class NfcAdapter { if (!sHasNfcWlcFeature) { throw new UnsupportedOperationException(); } - try { - return sService.isWlcEnabled(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return false; - } - try { - return sService.isWlcEnabled(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return false; - } + return callServiceReturn(() -> sService.isWlcEnabled(), false); + } /** @@ -2986,22 +2688,8 @@ public final class NfcAdapter { if (!sHasNfcWlcFeature) { throw new UnsupportedOperationException(); } - try { - return sService.getWlcListenerDeviceInfo(); - } catch (RemoteException e) { - attemptDeadServiceRecovery(e); - // Try one more time - if (sService == null) { - Log.e(TAG, "Failed to recover NFC Service."); - return null; - } - try { - return sService.getWlcListenerDeviceInfo(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover NFC Service."); - } - return null; - } + return callServiceReturn(() -> sService.getWlcListenerDeviceInfo(), null); + } /** diff --git a/nfc/java/android/nfc/NfcAntennaInfo.java b/nfc/java/android/nfc/NfcAntennaInfo.java index b002ca21e8e3..c57b2e029cc5 100644 --- a/nfc/java/android/nfc/NfcAntennaInfo.java +++ b/nfc/java/android/nfc/NfcAntennaInfo.java @@ -64,9 +64,9 @@ public final class NfcAntennaInfo implements Parcelable { /** * Whether the device is foldable. When the device is foldable, - * the 0, 0 is considered to be bottom-left when the device is unfolded and + * the 0, 0 is considered to be top-left when the device is unfolded and * the screens are facing the user. For non-foldable devices 0, 0 - * is bottom-left when the user is facing the screen. + * is top-left when the user is facing the screen. */ public boolean isDeviceFoldable() { return mDeviceFoldable; diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index 1eff58cb80fd..2ec819cdc1a9 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -89,13 +89,11 @@ public final class NfcOemExtension { + "registering"); throw new IllegalArgumentException(); } - try { + NfcAdapter.callService(() -> { NfcAdapter.sService.registerOemExtensionCallback(mOemNfcExtensionCallback); mCallback = callback; mExecutor = executor; - } catch (RemoteException e) { - mAdapter.attemptDeadServiceRecovery(e); - } + }); } } @@ -117,13 +115,11 @@ public final class NfcOemExtension { Log.e(TAG, "Callback not registered"); throw new IllegalArgumentException(); } - try { + NfcAdapter.callService(() -> { NfcAdapter.sService.unregisterOemExtensionCallback(mOemNfcExtensionCallback); mCallback = null; mExecutor = null; - } catch (RemoteException e) { - mAdapter.attemptDeadServiceRecovery(e); - } + }); } } @@ -134,11 +130,27 @@ public final class NfcOemExtension { @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference() { - try { - NfcAdapter.sService.clearPreference(); - } catch (RemoteException e) { - mAdapter.attemptDeadServiceRecovery(e); - } + NfcAdapter.callService(() -> NfcAdapter.sService.clearPreference()); + } + + /** + * Get the screen state from system and set it to current screen state. + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public void synchronizeScreenState() { + NfcAdapter.callService(() -> NfcAdapter.sService.setScreenState()); + } + + /** + * Check if the firmware needs updating. + * + * <p>If an update is needed, a firmware will be triggered when NFC is disabled. + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public void maybeTriggerFirmwareUpdate() { + NfcAdapter.callService(() -> NfcAdapter.sService.checkFirmware()); } private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub { diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java index 2c7d61eea777..3cf0a4dc4873 100644 --- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -108,6 +108,8 @@ public final class ApduServiceInfo implements Parcelable { private final Map<String, Boolean> mAutoTransact; + private final Map<Pattern, Boolean> mAutoTransactPatterns; + /** * Whether this service should only be started when the device is unlocked. */ @@ -179,7 +181,7 @@ public final class ApduServiceInfo implements Parcelable { this(info, onHost, description, staticAidGroups, dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid, settingsActivityName, offHost, staticOffHost, isEnabled, - new HashMap<String, Boolean>()); + new HashMap<String, Boolean>(), new HashMap<Pattern, Boolean>()); } /** @@ -189,12 +191,13 @@ public final class ApduServiceInfo implements Parcelable { List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups, boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid, String settingsActivityName, String offHost, String staticOffHost, boolean isEnabled, - HashMap<String, Boolean> autoTransact) { + Map<String, Boolean> autoTransact, Map<Pattern, Boolean> autoTransactPatterns) { this.mService = info; this.mDescription = description; this.mStaticAidGroups = new HashMap<String, AidGroup>(); this.mDynamicAidGroups = new HashMap<String, AidGroup>(); this.mAutoTransact = autoTransact; + this.mAutoTransactPatterns = autoTransactPatterns; this.mOffHostName = offHost; this.mStaticOffHostName = staticOffHost; this.mOnHost = onHost; @@ -314,6 +317,7 @@ public final class ApduServiceInfo implements Parcelable { mStaticAidGroups = new HashMap<String, AidGroup>(); mDynamicAidGroups = new HashMap<String, AidGroup>(); mAutoTransact = new HashMap<String, Boolean>(); + mAutoTransactPatterns = new HashMap<Pattern, Boolean>(); mOnHost = onHost; final int depth = parser.getDepth(); @@ -406,7 +410,29 @@ public final class ApduServiceInfo implements Parcelable { boolean autoTransact = a.getBoolean( com.android.internal.R.styleable.PollingLoopFilter_autoTransact, false); - mAutoTransact.put(plf, autoTransact); + if (!mOnHost && !autoTransact) { + Log.e(TAG, "Ignoring polling-loop-filter " + plf + + " for offhost service that isn't autoTransact"); + } else { + mAutoTransact.put(plf, autoTransact); + } + a.recycle(); + } else if (eventType == XmlPullParser.START_TAG + && "polling-loop-pattern-filter".equals(tagName) && currentGroup == null) { + final TypedArray a = res.obtainAttributes(attrs, + com.android.internal.R.styleable.PollingLoopPatternFilter); + String plf = a.getString( + com.android.internal.R.styleable.PollingLoopPatternFilter_name) + .toUpperCase(Locale.ROOT); + boolean autoTransact = a.getBoolean( + com.android.internal.R.styleable.PollingLoopFilter_autoTransact, + false); + if (!mOnHost && !autoTransact) { + Log.e(TAG, "Ignoring polling-loop-filter " + plf + + " for offhost service that isn't autoTransact"); + } else { + mAutoTransactPatterns.put(Pattern.compile(plf), autoTransact); + } a.recycle(); } } @@ -481,7 +507,30 @@ public final class ApduServiceInfo implements Parcelable { */ @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) public boolean getShouldAutoTransact(@NonNull String plf) { - return mAutoTransact.getOrDefault(plf.toUpperCase(Locale.ROOT), false); + if (mAutoTransact.getOrDefault(plf.toUpperCase(Locale.ROOT), false)) { + return true; + } + List<Pattern> patternMatches = mAutoTransactPatterns.keySet().stream() + .filter(p -> p.matcher(plf).matches()).toList(); + if (patternMatches == null || patternMatches.size() == 0) { + return false; + } + for (Pattern patternMatch : patternMatches) { + if (mAutoTransactPatterns.get(patternMatch)) { + return true; + } + } + return false; + } + + /** + * Returns the current polling loop pattern filters for this service. + * @return List of polling loop pattern filters. + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + @NonNull + public List<Pattern> getPollingLoopPatternFilters() { + return new ArrayList<>(mAutoTransactPatterns.keySet()); } /** @@ -683,13 +732,17 @@ public final class ApduServiceInfo implements Parcelable { * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will be * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this * multiple times will cause the value to be overwritten each time. - * @param pollingLoopFilter the polling loop filter to add, must be a valide hexadecimal string + * @param pollingLoopFilter the polling loop filter to add, must be a valid hexadecimal string + * @param autoTransact when true, disable observe mode when this filter matches, when false, + * matching does not change the observe mode state */ @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) public void addPollingLoopFilter(@NonNull String pollingLoopFilter, boolean autoTransact) { + if (!mOnHost && !autoTransact) { + return; + } mAutoTransact.put(pollingLoopFilter, autoTransact); - } /** @@ -703,6 +756,35 @@ public final class ApduServiceInfo implements Parcelable { } /** + * Add a Polling Loop Pattern Filter. Custom NFC polling frames that match this filter will be + * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this + * multiple times will cause the value to be overwritten each time. + * @param pollingLoopPatternFilter the polling loop pattern filter to add, must be a valid + * regex to match a hexadecimal string + * @param autoTransact when true, disable observe mode when this filter matches, when false, + * matching does not change the observe mode state + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + public void addPollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter, + boolean autoTransact) { + if (!mOnHost && !autoTransact) { + return; + } + mAutoTransactPatterns.put(Pattern.compile(pollingLoopPatternFilter), autoTransact); + } + + /** + * Remove a Polling Loop Pattern Filter. Custom NFC polling frames that match this filter will + * no longer be delivered to {@link HostApduService#processPollingFrames(List)}. + * @param pollingLoopPatternFilter this polling loop filter to add. + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + public void removePollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter) { + mAutoTransactPatterns.remove( + Pattern.compile(pollingLoopPatternFilter.toUpperCase(Locale.ROOT))); + } + + /** * Sets the off host Secure Element. * @param offHost Secure Element to set. Only accept strings with prefix SIM or prefix eSE. * Ref: GSMA TS.26 - NFC Handset Requirements @@ -856,6 +938,8 @@ public final class ApduServiceInfo implements Parcelable { dest.writeInt(mCategoryOtherServiceEnabled ? 1 : 0); dest.writeInt(mAutoTransact.size()); dest.writeMap(mAutoTransact); + dest.writeInt(mAutoTransactPatterns.size()); + dest.writeMap(mAutoTransactPatterns); }; @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @@ -889,10 +973,15 @@ public final class ApduServiceInfo implements Parcelable { new HashMap<String, Boolean>(autoTransactSize); source.readMap(autoTransact, getClass().getClassLoader(), String.class, Boolean.class); + int autoTransactPatternSize = source.readInt(); + HashMap<Pattern, Boolean> autoTransactPatterns = + new HashMap<Pattern, Boolean>(autoTransactSize); + source.readMap(autoTransactPatterns, getClass().getClassLoader(), + Pattern.class, Boolean.class); return new ApduServiceInfo(info, onHost, description, staticAidGroups, dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid, settingsActivityName, offHostName, staticOffHostName, - isEnabled, autoTransact); + isEnabled, autoTransact, autoTransactPatterns); } @Override @@ -939,6 +1028,9 @@ public final class ApduServiceInfo implements Parcelable { pw.println(" Settings Activity: " + mSettingsActivityName); pw.println(" Requires Device Unlock: " + mRequiresDeviceUnlock); pw.println(" Requires Device ScreenOn: " + mRequiresDeviceScreenOn); + pw.println(" Should Default to Observe Mode: " + mShouldDefaultToObserveMode); + pw.println(" Auto-Transact Mapping: " + mAutoTransact); + pw.println(" Auto-Transact Patterns: " + mAutoTransactPatterns); } @@ -992,6 +1084,27 @@ public final class ApduServiceInfo implements Parcelable { proto.end(token); } proto.write(ApduServiceInfoProto.SETTINGS_ACTIVITY_NAME, mSettingsActivityName); + proto.write(ApduServiceInfoProto.SHOULD_DEFAULT_TO_OBSERVE_MODE, + mShouldDefaultToObserveMode); + { + long token = proto.start(ApduServiceInfoProto.AUTO_TRANSACT_MAPPING); + for (Map.Entry<String, Boolean> entry : mAutoTransact.entrySet()) { + proto.write(ApduServiceInfoProto.AutoTransactMapping.AID, entry.getKey()); + proto.write(ApduServiceInfoProto.AutoTransactMapping.SHOULD_AUTO_TRANSACT, + entry.getValue()); + } + proto.end(token); + } + { + long token = proto.start(ApduServiceInfoProto.AUTO_TRANSACT_PATTERNS); + for (Map.Entry<Pattern, Boolean> entry : mAutoTransactPatterns.entrySet()) { + proto.write(ApduServiceInfoProto.AutoTransactPattern.REGEXP_PATTERN, + entry.getKey().pattern()); + proto.write(ApduServiceInfoProto.AutoTransactPattern.SHOULD_AUTO_TRANSACT, + entry.getValue()); + } + proto.end(token); + } } private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java index 61d651fa5577..e0438ce9258c 100644 --- a/nfc/java/android/nfc/cardemulation/CardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java @@ -27,6 +27,7 @@ import android.annotation.SystemApi; import android.annotation.UserHandleAware; import android.annotation.UserIdInt; import android.app.Activity; +import android.app.role.RoleManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -35,6 +36,7 @@ import android.nfc.Constants; import android.nfc.Flags; import android.nfc.INfcCardEmulation; import android.nfc.NfcAdapter; +import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; @@ -44,6 +46,7 @@ import android.util.Log; import java.util.HashMap; import java.util.HexFormat; import java.util.List; +import java.util.Locale; import java.util.regex.Pattern; /** @@ -60,6 +63,7 @@ import java.util.regex.Pattern; */ public final class CardEmulation { private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); + private static final Pattern PLPF_PATTERN = Pattern.compile("[0-9A-Fa-f,\\?,\\*\\.]*"); static final String TAG = "CardEmulation"; @@ -215,24 +219,9 @@ public final class CardEmulation { * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. */ public boolean isDefaultServiceForCategory(ComponentName service, String category) { - try { - return sService.isDefaultServiceForCategory(mContext.getUser().getIdentifier(), - service, category); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.isDefaultServiceForCategory(mContext.getUser().getIdentifier(), - service, category); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.isDefaultServiceForCategory( + mContext.getUser().getIdentifier(), service, category), false); } /** @@ -247,33 +236,22 @@ public final class CardEmulation { * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. */ public boolean isDefaultServiceForAid(ComponentName service, String aid) { - try { - return sService.isDefaultServiceForAid(mContext.getUser().getIdentifier(), - service, aid); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.isDefaultServiceForAid(mContext.getUser().getIdentifier(), - service, aid); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.isDefaultServiceForAid( + mContext.getUser().getIdentifier(), service, aid), false); } /** + * <p> * Returns whether the user has allowed AIDs registered in the * specified category to be handled by a service that is preferred * by the foreground application, instead of by a pre-configured default. * * Foreground applications can set such preferences using the * {@link #setPreferredService(Activity, ComponentName)} method. + * <p class="note"> + * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, this method will always + * return true. * * @param category The category, e.g. {@link #CATEGORY_PAYMENT} * @return whether AIDs in the category can be handled by a service @@ -281,10 +259,16 @@ public final class CardEmulation { */ @SuppressWarnings("NonUserGetterCalled") public boolean categoryAllowsForegroundPreference(String category) { + Context contextAsUser = mContext.createContextAsUser( + UserHandle.of(UserHandle.myUserId()), 0); + + RoleManager roleManager = contextAsUser.getSystemService(RoleManager.class); + if (roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)) { + return true; + } + if (CATEGORY_PAYMENT.equals(category)) { boolean preferForeground = false; - Context contextAsUser = mContext.createContextAsUser( - UserHandle.of(UserHandle.myUserId()), 0); try { preferForeground = Settings.Secure.getInt( contextAsUser.getContentResolver(), @@ -307,27 +291,18 @@ public final class CardEmulation { * every time what service they would like to use in this category. * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked * to pick a service if there is a conflict. + * + * <p class="note"> + * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the default service defined + * by the holder of {@link android.app.role.RoleManager#ROLE_WALLET} and is category agnostic. + * * @param category The category, for example {@link #CATEGORY_PAYMENT} * @return the selection mode for the passed in category */ public int getSelectionModeForCategory(String category) { if (CATEGORY_PAYMENT.equals(category)) { - boolean paymentRegistered = false; - try { - paymentRegistered = sService.isDefaultPaymentRegistered(); - } catch (RemoteException e) { - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return SELECTION_MODE_ALWAYS_ASK; - } - try { - paymentRegistered = sService.isDefaultPaymentRegistered(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return SELECTION_MODE_ALWAYS_ASK; - } - } + boolean paymentRegistered = callServiceReturn(() -> + sService.isDefaultPaymentRegistered(), false); if (paymentRegistered) { return SELECTION_MODE_PREFER_DEFAULT; } else { @@ -350,13 +325,9 @@ public final class CardEmulation { @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE) public boolean setShouldDefaultToObserveModeForService(@NonNull ComponentName service, boolean enable) { - try { - return sService.setShouldDefaultToObserveModeForService( - mContext.getUser().getIdentifier(), service, enable); - } catch (RemoteException e) { - Log.e(TAG, "Failed to reach CardEmulationService."); - } - return false; + return callServiceReturn(() -> + sService.setShouldDefaultToObserveModeForService( + mContext.getUser().getIdentifier(), service, enable), false); } /** @@ -364,9 +335,9 @@ public final class CardEmulation { * auto-transact or not. The PLF can be sequence of an * even number of at least 2 hexadecimal numbers (0-9, A-F or a-f), representing a series of * bytes. When non-standard polling loop frame matches this sequence exactly, it may be - * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to - * true, then observe mode will also be disabled. if this service is currently preferred or - * there are no other services registered for this filter. + * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact + * is set to true and this service is currently preferred or there are no other services + * registered for this filter then observe mode will also be disabled. * @param service The HostApduService to register the filter for * @param pollingLoopFilter The filter to register * @param autoTransact true to have the NFC stack automatically disable observe mode and allow @@ -377,27 +348,85 @@ public final class CardEmulation { @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) public boolean registerPollingLoopFilterForService(@NonNull ComponentName service, @NonNull String pollingLoopFilter, boolean autoTransact) { - pollingLoopFilter = validatePollingLoopFilter(pollingLoopFilter); + final String pollingLoopFilterV = validatePollingLoopFilter(pollingLoopFilter); + return callServiceReturn(() -> + sService.registerPollingLoopFilterForService( + mContext.getUser().getIdentifier(), service, pollingLoopFilterV, autoTransact), + false); + } - try { - return sService.registerPollingLoopFilterForService(mContext.getUser().getIdentifier(), - service, pollingLoopFilter, autoTransact); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.registerPollingLoopFilterForService( - mContext.getUser().getIdentifier(), service, - pollingLoopFilter, autoTransact); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + /** + * Unregister a polling loop filter (PLF) for a HostApduService. If the PLF had previously been + * registered via {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)} + * for this service it will be removed. + * @param service The HostApduService to unregister the filter for + * @param pollingLoopFilter The filter to unregister + * @return true if the filter was removed, false otherwise + * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + public boolean removePollingLoopFilterForService(@NonNull ComponentName service, + @NonNull String pollingLoopFilter) { + final String pollingLoopFilterV = validatePollingLoopFilter(pollingLoopFilter); + return callServiceReturn(() -> + sService.removePollingLoopFilterForService( + mContext.getUser().getIdentifier(), service, pollingLoopFilterV), false); + } + + + /** + * Register a polling loop pattern filter (PLPF) for a HostApduService and indicate whether it + * should auto-transact or not. The pattern may include the characters 0-9 and A-F as well as + * the regular expression operators `.`, `?` and `*`. When the beginning of anon-standard + * polling loop frame matches this sequence exactly, it may be delivered to + * {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to true and this + * service is currently preferred or there are no other services registered for this filter + * then observe mode will also be disabled. + * @param service The HostApduService to register the filter for + * @param pollingLoopPatternFilter The pattern filter to register, must to be compatible with + * {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers + * and `.`, `?` and `*` operators + * @param autoTransact true to have the NFC stack automatically disable observe mode and allow + * transactions to proceed when this filter matches, false otherwise + * @return true if the filter was registered, false otherwise + * @throws IllegalArgumentException if the filter containst elements other than hexadecimal + * numbers and `.`, `?` and `*` operators + * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + public boolean registerPollingLoopPatternFilterForService(@NonNull ComponentName service, + @NonNull String pollingLoopPatternFilter, boolean autoTransact) { + final String pollingLoopPatternFilterV = + validatePollingLoopPatternFilter(pollingLoopPatternFilter); + return callServiceReturn(() -> + sService.registerPollingLoopPatternFilterForService( + mContext.getUser().getIdentifier(), service, pollingLoopPatternFilterV, + autoTransact), + false); + } + + /** + * Unregister a polling loop pattern filter (PLPF) for a HostApduService. If the PLF had + * previously been registered via + * {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)} for this + * service it will be removed. + * @param service The HostApduService to unregister the filter for + * @param pollingLoopPatternFilter The filter to unregister, must to be compatible with + * {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers + * and`.`, `?` and `*` operators + * @return true if the filter was removed, false otherwise + * @throws IllegalArgumentException if the filter containst elements other than hexadecimal + * numbers and `.`, `?` and `*` operators + * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + public boolean removePollingLoopPatternFilterForService(@NonNull ComponentName service, + @NonNull String pollingLoopPatternFilter) { + final String pollingLoopPatternFilterV = + validatePollingLoopPatternFilter(pollingLoopPatternFilter); + return callServiceReturn(() -> + sService.removePollingLoopPatternFilterForService( + mContext.getUser().getIdentifier(), service, pollingLoopPatternFilterV), false); } /** @@ -422,25 +451,10 @@ public final class CardEmulation { */ public boolean registerAidsForService(ComponentName service, String category, List<String> aids) { - AidGroup aidGroup = new AidGroup(aids, category); - try { - return sService.registerAidGroupForService(mContext.getUser().getIdentifier(), - service, aidGroup); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.registerAidGroupForService(mContext.getUser().getIdentifier(), - service, aidGroup); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + final AidGroup aidGroup = new AidGroup(aids, category); + return callServiceReturn(() -> + sService.registerAidGroupForService( + mContext.getUser().getIdentifier(), service, aidGroup), false); } /** @@ -462,27 +476,9 @@ public final class CardEmulation { @RequiresPermission(android.Manifest.permission.NFC) @NonNull public boolean unsetOffHostForService(@NonNull ComponentName service) { - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); - if (adapter == null) { - return false; - } - - try { - return sService.unsetOffHostForService(mContext.getUser().getIdentifier(), service); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.unsetOffHostForService(mContext.getUser().getIdentifier(), service); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.unsetOffHostForService( + mContext.getUser().getIdentifier(), service), false); } /** @@ -521,8 +517,6 @@ public final class CardEmulation { @NonNull public boolean setOffHostForService(@NonNull ComponentName service, @NonNull String offHostSecureElement) { - boolean validSecureElement = false; - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); if (adapter == null || offHostSecureElement == null) { return false; @@ -543,25 +537,10 @@ public final class CardEmulation { } else if (offHostSecureElement.equals("SIM")) { offHostSecureElement = "SIM1"; } - - try { - return sService.setOffHostForService(mContext.getUser().getIdentifier(), service, - offHostSecureElement); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.setOffHostForService(mContext.getUser().getIdentifier(), service, - offHostSecureElement); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + final String offHostSecureElementV = new String(offHostSecureElement); + return callServiceReturn(() -> + sService.setOffHostForService( + mContext.getUser().getIdentifier(), service, offHostSecureElementV), false); } /** @@ -579,25 +558,10 @@ public final class CardEmulation { * @return The list of AIDs registered for this category, or null if it couldn't be found. */ public List<String> getAidsForService(ComponentName service, String category) { - try { - AidGroup group = sService.getAidGroupForService(mContext.getUser().getIdentifier(), - service, category); - return (group != null ? group.getAids() : null); - } catch (RemoteException e) { - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return null; - } - try { - AidGroup group = sService.getAidGroupForService(mContext.getUser().getIdentifier(), - service, category); - return (group != null ? group.getAids() : null); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return null; - } - } + AidGroup group = callServiceReturn(() -> + sService.getAidGroupForService( + mContext.getUser().getIdentifier(), service, category), null); + return (group != null ? group.getAids() : null); } /** @@ -616,24 +580,9 @@ public final class CardEmulation { * @return whether the group was successfully removed. */ public boolean removeAidsForService(ComponentName service, String category) { - try { - return sService.removeAidGroupForService(mContext.getUser().getIdentifier(), service, - category); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.removeAidGroupForService(mContext.getUser().getIdentifier(), - service, category); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.removeAidGroupForService( + mContext.getUser().getIdentifier(), service, category), false); } /** @@ -670,22 +619,7 @@ public final class CardEmulation { if (activity == null || service == null) { throw new NullPointerException("activity or service or category is null"); } - try { - return sService.setPreferredService(service); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.setPreferredService(service); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> sService.setPreferredService(service), false); } /** @@ -702,22 +636,7 @@ public final class CardEmulation { if (activity == null) { throw new NullPointerException("activity is null"); } - try { - return sService.unsetPreferredService(); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.unsetPreferredService(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> sService.unsetPreferredService(), false); } /** @@ -731,21 +650,7 @@ public final class CardEmulation { * @return whether AID prefix registering is supported on this device. */ public boolean supportsAidPrefixRegistration() { - try { - return sService.supportsAidPrefixRegistration(); - } catch (RemoteException e) { - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.supportsAidPrefixRegistration(); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> sService.supportsAidPrefixRegistration(), false); } /** @@ -756,30 +661,21 @@ public final class CardEmulation { @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) @Nullable public List<String> getAidsForPreferredPaymentService() { - try { - ApduServiceInfo serviceInfo = sService.getPreferredPaymentService( - mContext.getUser().getIdentifier()); - return (serviceInfo != null ? serviceInfo.getAids() : null); - } catch (RemoteException e) { - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - throw e.rethrowFromSystemServer(); - } - try { - ApduServiceInfo serviceInfo = - sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); - return (serviceInfo != null ? serviceInfo.getAids() : null); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover CardEmulationService."); - throw e.rethrowFromSystemServer(); - } - } + ApduServiceInfo serviceInfo = callServiceReturn(() -> + sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null); + return (serviceInfo != null ? serviceInfo.getAids() : null); } /** * Retrieves the route destination for the preferred payment service. * + * <p class="note"> + * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service + * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This + * will return the route for one of the services registered by the role holder (if any). If + * there are multiple services registered, it is unspecified which of those will be used to + * determine the route. + * * @return The route destination secure element name of the preferred payment service. * HCE payment: "Host" * OffHost payment: 1. String with prefix SIM or prefix eSE string. @@ -796,159 +692,71 @@ public final class CardEmulation { @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) @Nullable public String getRouteDestinationForPreferredPaymentService() { - try { - ApduServiceInfo serviceInfo = sService.getPreferredPaymentService( - mContext.getUser().getIdentifier()); - if (serviceInfo != null) { - if (!serviceInfo.isOnHost()) { - return serviceInfo.getOffHostSecureElement() == null ? - "OffHost" : serviceInfo.getOffHostSecureElement(); - } - return "Host"; - } - return null; - } catch (RemoteException e) { - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - throw e.rethrowFromSystemServer(); - } - try { - ApduServiceInfo serviceInfo = - sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); - if (serviceInfo != null) { - if (!serviceInfo.isOnHost()) { - return serviceInfo.getOffHostSecureElement() == null ? - "Offhost" : serviceInfo.getOffHostSecureElement(); - } - return "Host"; - } - return null; - - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover CardEmulationService."); - throw e.rethrowFromSystemServer(); + ApduServiceInfo serviceInfo = callServiceReturn(() -> + sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null); + if (serviceInfo != null) { + if (!serviceInfo.isOnHost()) { + return serviceInfo.getOffHostSecureElement() == null ? + "OffHost" : serviceInfo.getOffHostSecureElement(); } + return "Host"; } + return null; } /** * Returns a user-visible description of the preferred payment service. * + * <p class="note"> + * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service + * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This + * will return the description for one of the services registered by the role holder (if any). + * If there are multiple services registered, it is unspecified which of those will be used + * to obtain the service description here. + * * @return the preferred payment service description */ @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) @Nullable public CharSequence getDescriptionForPreferredPaymentService() { - try { - ApduServiceInfo serviceInfo = sService.getPreferredPaymentService( - mContext.getUser().getIdentifier()); - return (serviceInfo != null ? serviceInfo.getDescription() : null); - } catch (RemoteException e) { - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - throw e.rethrowFromSystemServer(); - } - try { - ApduServiceInfo serviceInfo = - sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); - return (serviceInfo != null ? serviceInfo.getDescription() : null); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to recover CardEmulationService."); - throw e.rethrowFromSystemServer(); - } - } + ApduServiceInfo serviceInfo = callServiceReturn(() -> + sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null); + return (serviceInfo != null ? serviceInfo.getDescription() : null); } /** * @hide */ public boolean setDefaultServiceForCategory(ComponentName service, String category) { - try { - return sService.setDefaultServiceForCategory(mContext.getUser().getIdentifier(), - service, category); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.setDefaultServiceForCategory(mContext.getUser().getIdentifier(), - service, category); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.setDefaultServiceForCategory( + mContext.getUser().getIdentifier(), service, category), false); } /** * @hide */ public boolean setDefaultForNextTap(ComponentName service) { - try { - return sService.setDefaultForNextTap(mContext.getUser().getIdentifier(), service); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.setDefaultForNextTap(mContext.getUser().getIdentifier(), service); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.setDefaultForNextTap( + mContext.getUser().getIdentifier(), service), false); } /** * @hide */ public boolean setDefaultForNextTap(int userId, ComponentName service) { - try { - return sService.setDefaultForNextTap(userId, service); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.setDefaultForNextTap(userId, service); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.setDefaultForNextTap(userId, service), false); } /** * @hide */ public List<ApduServiceInfo> getServices(String category) { - try { - return sService.getServices(mContext.getUser().getIdentifier(), category); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return null; - } - try { - return sService.getServices(mContext.getUser().getIdentifier(), category); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return null; - } - } + return callServiceReturn(() -> + sService.getServices( + mContext.getUser().getIdentifier(), category), null); } /** @@ -962,22 +770,8 @@ public final class CardEmulation { @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public List<ApduServiceInfo> getServices(@NonNull String category, @UserIdInt int userId) { - try { - return sService.getServices(userId, category); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return null; - } - try { - return sService.getServices(userId, category); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return null; - } - } + return callServiceReturn(() -> + sService.getServices(userId, category), null); } /** @@ -998,6 +792,23 @@ public final class CardEmulation { } /** + * Tests the validity of the polling loop pattern filter. + * @param pollingLoopPatternFilter The polling loop filter to test. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) + public static @NonNull String validatePollingLoopPatternFilter( + @NonNull String pollingLoopPatternFilter) { + // Verify hex characters + if (!PLPF_PATTERN.matcher(pollingLoopPatternFilter).matches()) { + throw new IllegalArgumentException( + "Polling loop pattern filters may only contain hexadecimal numbers, ?s and *s"); + } + return Pattern.compile(pollingLoopPatternFilter.toUpperCase(Locale.ROOT)).toString(); + } + + /** * A valid AID according to ISO/IEC 7816-4: * <ul> * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars) @@ -1050,22 +861,8 @@ public final class CardEmulation { if (service == null) { throw new NullPointerException("activity or service or category is null"); } - try { - return sService.setServiceEnabledForCategoryOther(userId, service, status); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.setServiceEnabledForCategoryOther(userId, service, status); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.setServiceEnabledForCategoryOther(userId, service, status), false); } /** @@ -1097,22 +894,9 @@ public final class CardEmulation { if (!activity.isResumed()) { throw new IllegalArgumentException("Activity must be resumed."); } - try { - return sService.overrideRoutingTable(UserHandle.myUserId(), protocol, technology); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.overrideRoutingTable(UserHandle.myUserId(), protocol, technology); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } + return callServiceReturn(() -> + sService.overrideRoutingTable( + mContext.getUser().getIdentifier(), protocol, technology), false); } /** @@ -1131,27 +915,9 @@ public final class CardEmulation { if (!activity.isResumed()) { throw new IllegalArgumentException("Activity must be resumed."); } - try { - return sService.recoverRoutingTable(UserHandle.myUserId()); - } catch (RemoteException e) { - // Try one more time - recoverService(); - if (sService == null) { - Log.e(TAG, "Failed to recover CardEmulationService."); - return false; - } - try { - return sService.recoverRoutingTable(UserHandle.myUserId()); - } catch (RemoteException ee) { - Log.e(TAG, "Failed to reach CardEmulationService."); - return false; - } - } - } - - void recoverService() { - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext); - sService = adapter.getCardEmulationService(); + return callServiceReturn(() -> + sService.recoverRoutingTable( + mContext.getUser().getIdentifier()), false); } /** @@ -1179,4 +945,53 @@ public final class CardEmulation { return ComponentName.unflattenFromString(defaultPaymentComponent); } + + /** @hide */ + interface ServiceCall { + void call() throws RemoteException; + } + /** @hide */ + public static void callService(ServiceCall call) { + try { + if (sService == null) { + NfcAdapter.attemptDeadServiceRecovery( + new RemoteException("NFC CardEmulation Service is null")); + sService = NfcAdapter.getCardEmulationService(); + } + call.call(); + } catch (RemoteException e) { + NfcAdapter.attemptDeadServiceRecovery(e); + sService = NfcAdapter.getCardEmulationService(); + try { + call.call(); + } catch (RemoteException ee) { + ee.rethrowAsRuntimeException(); + } + } + } + /** @hide */ + interface ServiceCallReturn<T> { + T call() throws RemoteException; + } + /** @hide */ + public static <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) { + try { + if (sService == null) { + NfcAdapter.attemptDeadServiceRecovery( + new RemoteException("NFC CardEmulation Service is null")); + sService = NfcAdapter.getCardEmulationService(); + } + return call.call(); + } catch (RemoteException e) { + NfcAdapter.attemptDeadServiceRecovery(e); + sService = NfcAdapter.getCardEmulationService(); + // Try one more time + try { + return call.call(); + } catch (RemoteException ee) { + ee.rethrowAsRuntimeException(); + } + } + return defaultReturn; + } } diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java index f3ba2d0098ce..c3c74a6fd265 100644 --- a/nfc/java/android/nfc/cardemulation/HostApduService.java +++ b/nfc/java/android/nfc/cardemulation/HostApduService.java @@ -326,15 +326,12 @@ public abstract class HostApduService extends Service { } break; case MSG_POLLING_LOOP: - ArrayList<Bundle> frames = - msg.getData().getParcelableArrayList(KEY_POLLING_LOOP_FRAMES_BUNDLE, - Bundle.class); - ArrayList<PollingFrame> pollingFrames = - new ArrayList<PollingFrame>(frames.size()); - for (Bundle frame : frames) { - pollingFrames.add(new PollingFrame(frame)); + if (android.nfc.Flags.nfcReadPollingLoop()) { + ArrayList<PollingFrame> pollingFrames = + msg.getData().getParcelableArrayList( + KEY_POLLING_LOOP_FRAMES_BUNDLE, PollingFrame.class); + processPollingFrames(pollingFrames); } - processPollingFrames(pollingFrames); break; default: super.handleMessage(msg); diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.aidl b/nfc/java/android/nfc/cardemulation/PollingFrame.aidl new file mode 100644 index 000000000000..8e09f8baaff2 --- /dev/null +++ b/nfc/java/android/nfc/cardemulation/PollingFrame.aidl @@ -0,0 +1,19 @@ +/* + * 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.nfc.cardemulation; + +parcelable PollingFrame;
\ No newline at end of file diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java index 994f4ae1c2e3..5dcc84ccf8b9 100644 --- a/nfc/java/android/nfc/cardemulation/PollingFrame.java +++ b/nfc/java/android/nfc/cardemulation/PollingFrame.java @@ -32,19 +32,26 @@ import java.util.List; /** * Polling Frames represent data about individual frames of an NFC polling loop. These frames will - * be deliverd to subclasses of {@link HostApduService} that have registered filters with - * {@link CardEmulation#registerPollingLoopFilterForService(ComponentName, String)} that match a - * given frame in a loop and will be delivered through calls to + * be delivered to subclasses of {@link HostApduService} that have registered filters with + * {@link CardEmulation#registerPollingLoopFilterForService(ComponentName, String, boolean)} that + * match a given frame in a loop and will be delivered through calls to * {@link HostApduService#processPollingFrames(List)}. */ @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP) -public final class PollingFrame implements Parcelable{ +public final class PollingFrame implements Parcelable { /** * @hide */ - @IntDef(prefix = { "POLLING_LOOP_TYPE_"}, value = { POLLING_LOOP_TYPE_A, POLLING_LOOP_TYPE_B, - POLLING_LOOP_TYPE_F, POLLING_LOOP_TYPE_OFF, POLLING_LOOP_TYPE_ON }) + @IntDef(prefix = { "POLLING_LOOP_TYPE_"}, + value = { + POLLING_LOOP_TYPE_A, + POLLING_LOOP_TYPE_B, + POLLING_LOOP_TYPE_F, + POLLING_LOOP_TYPE_OFF, + POLLING_LOOP_TYPE_ON, + POLLING_LOOP_TYPE_UNKNOWN + }) @Retention(RetentionPolicy.SOURCE) @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP) public @interface PollingFrameType {} @@ -100,45 +107,46 @@ public final class PollingFrame implements Parcelable{ /** * KEY_POLLING_LOOP_TYPE is the Bundle key for the type of * polling loop frame in the Bundle included in MSG_POLLING_LOOP. - * - * @hide */ @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP) - public static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE"; + private static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE"; /** * KEY_POLLING_LOOP_DATA is the Bundle key for the raw data of captured from * the polling loop frame in the Bundle included in MSG_POLLING_LOOP. - * - * @hide */ @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP) - public static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA"; + private static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA"; /** * KEY_POLLING_LOOP_GAIN is the Bundle key for the field strength of * the polling loop frame in the Bundle included in MSG_POLLING_LOOP. - * - * @hide - */ + */ @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP) - public static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN"; + private static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN"; /** * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for the timestamp of * the polling loop frame in the Bundle included in MSG_POLLING_LOOP. - * - * @hide - */ + */ @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP) - public static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP"; + private static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP"; + + /** + * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for whether this polling frame triggered + * autoTransact in the Bundle included in MSG_POLLING_LOOP. + */ + @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP) + private static final String KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT = + "android.nfc.cardemulation.TRIGGERED_AUTOTRANSACT"; @PollingFrameType private final int mType; private final byte[] mData; private final int mGain; - private final int mTimestamp; + private final long mTimestamp; + private boolean mTriggeredAutoTransact; public static final @NonNull Parcelable.Creator<PollingFrame> CREATOR = new Parcelable.Creator<>() { @@ -153,31 +161,46 @@ public final class PollingFrame implements Parcelable{ } }; - PollingFrame(Bundle frame) { + private PollingFrame(Bundle frame) { mType = frame.getInt(KEY_POLLING_LOOP_TYPE); byte[] data = frame.getByteArray(KEY_POLLING_LOOP_DATA); mData = (data == null) ? new byte[0] : data; - mGain = frame.getByte(KEY_POLLING_LOOP_GAIN); - mTimestamp = frame.getInt(KEY_POLLING_LOOP_TIMESTAMP); + mGain = frame.getInt(KEY_POLLING_LOOP_GAIN, -1); + mTimestamp = frame.getLong(KEY_POLLING_LOOP_TIMESTAMP); + mTriggeredAutoTransact = frame.containsKey(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT) + && frame.getBoolean(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT); } + /** + * Constructor for Polling Frames. + * + * @param type the type of the frame + * @param data a byte array of the data contained in the frame + * @param gain the vendor-specific gain of the field + * @param timestampMicros the timestamp in microseconds + * @param triggeredAutoTransact whether or not this frame triggered the device to start a + * transaction automatically + * + * @hide + */ public PollingFrame(@PollingFrameType int type, @Nullable byte[] data, - int gain, int timestamp) { + int gain, long timestampMicros, boolean triggeredAutoTransact) { mType = type; mData = data == null ? new byte[0] : data; mGain = gain; - mTimestamp = timestamp; + mTimestamp = timestampMicros; + mTriggeredAutoTransact = triggeredAutoTransact; } /** * Returns the type of frame for this polling loop frame. * The possible return values are: * <ul> - * <li>{@link POLLING_LOOP_TYPE_ON}</li> - * <li>{@link POLLING_LOOP_TYPE_OFF}</li> - * <li>{@link POLLING_LOOP_TYPE_A}</li> - * <li>{@link POLLING_LOOP_TYPE_B}</li> - * <li>{@link POLLING_LOOP_TYPE_F}</li> + * <li>{@link #POLLING_LOOP_TYPE_ON}</li> + * <li>{@link #POLLING_LOOP_TYPE_OFF}</li> + * <li>{@link #POLLING_LOOP_TYPE_A}</li> + * <li>{@link #POLLING_LOOP_TYPE_B}</li> + * <li>{@link #POLLING_LOOP_TYPE_F}</li> * </ul> */ public @PollingFrameType int getType() { @@ -194,21 +217,37 @@ public final class PollingFrame implements Parcelable{ /** * Returns the gain representing the field strength of the NFC field when this polling loop * frame was observed. + * @return the gain or -1 if there is no gain measurement associated with this frame. */ - public int getGain() { + public int getVendorSpecificGain() { return mGain; } /** - * Returns the timestamp of when the polling loop frame was observed in milliseconds. These - * timestamps are relative and not absolute and should only be used for comparing the timing of - * frames relative to each other. - * @return the timestamp in milliseconds + * Returns the timestamp of when the polling loop frame was observed, in microseconds. These + * timestamps are relative and should only be used for comparing the timing of frames relative + * to each other. + * @return the timestamp in microseconds */ - public int getTimestamp() { + public long getTimestamp() { return mTimestamp; } + /** + * @hide + */ + public void setTriggeredAutoTransact(boolean triggeredAutoTransact) { + mTriggeredAutoTransact = triggeredAutoTransact; + } + + /** + * Returns whether this frame triggered the device to automatically disable observe mode and + * allow one transaction. + */ + public boolean getTriggeredAutoTransact() { + return mTriggeredAutoTransact; + } + @Override public int describeContents() { return 0; @@ -220,24 +259,25 @@ public final class PollingFrame implements Parcelable{ } /** - * - * @hide * @return a Bundle representing this frame */ - public Bundle toBundle() { + private Bundle toBundle() { Bundle frame = new Bundle(); frame.putInt(KEY_POLLING_LOOP_TYPE, getType()); - frame.putByte(KEY_POLLING_LOOP_GAIN, (byte) getGain()); + if (getVendorSpecificGain() != -1) { + frame.putInt(KEY_POLLING_LOOP_GAIN, (byte) getVendorSpecificGain()); + } frame.putByteArray(KEY_POLLING_LOOP_DATA, getData()); - frame.putInt(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp()); + frame.putLong(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp()); + frame.putBoolean(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT, getTriggeredAutoTransact()); return frame; } @Override public String toString() { return "PollingFrame { Type: " + (char) getType() - + ", gain: " + getGain() - + ", timestamp: " + Integer.toUnsignedString(getTimestamp()) + + ", gain: " + getVendorSpecificGain() + + ", timestamp: " + Long.toUnsignedString(getTimestamp()) + ", data: [" + HexFormat.ofDelimiter(" ").formatHex(getData()) + "] }"; } } diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig index 6841d2ba96ad..45036a5f214b 100644 --- a/nfc/java/android/nfc/flags.aconfig +++ b/nfc/java/android/nfc/flags.aconfig @@ -92,3 +92,28 @@ flag { description: "Enable NFC OEM extension support" bug: "331206243" } + +flag { + name: "nfc_state_change" + is_exported: true + namespace: "nfc" + description: "Enable nfc state change API" + bug: "319934052" +} + +flag { + name: "nfc_set_default_disc_tech" + is_exported: true + namespace: "nfc" + description: "Flag for NFC set default disc tech API" + bug: "321311407" +} + +flag { + name: "nfc_persist_log" + is_exported: true + namespace: "nfc" + description: "Enable NFC persistent log support" + bug: "321310044" +} + diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index 4e52c77f27b4..40bc0e94adef 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -40,7 +40,7 @@ public class CachedBluetoothDeviceManager { private static final String TAG = "CachedBluetoothDeviceManager"; private static final boolean DEBUG = BluetoothUtils.D; - @VisibleForTesting static int sLateBondingTimeoutMillis = 5000; // 5s + @VisibleForTesting static int sLateBondingTimeoutMillis = 10000; // 10s private Context mContext; private final LocalBluetoothManager mBtManager; diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 417b7a6179bd..53ff172246cc 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -65,6 +65,7 @@ <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" /> <uses-permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" /> + <uses-permission android:name="android.permission.READ_DROPBOX_DATA" /> <uses-permission android:name="android.permission.READ_LOGS" /> <uses-permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE" /> <uses-permission android:name="android.permission.ACCESS_AMBIENT_LIGHT_STATS" /> diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java index 0dd9275503a9..8c3cce4087c1 100644 --- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java +++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java @@ -255,8 +255,8 @@ public final class RingtonePickerActivity extends AlertActivity implements p.mTitle = getString(com.android.internal.R.string.ringtone_picker_title); } } else { - // Make sure intents don't inject HTML elements. - p.mTitle = Html.escapeHtml(p.mTitle.toString()); + // Make sure intents don't inject spannable elements. + p.mTitle = p.mTitle.toString(); } setupAlert(); diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java index 66a2fae0c4c3..c698d18bfde8 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java @@ -19,7 +19,6 @@ import android.util.Log; import com.android.systemui.accessibility.accessibilitymenu.R; -import java.util.HashMap; import java.util.Map; /** @@ -52,80 +51,80 @@ public class A11yMenuShortcut { private static final int LABEL_TEXT_INDEX = 3; /** Map stores all shortcut resource IDs that is in matching order of defined shortcut. */ - private static final Map<ShortcutId, int[]> sShortcutResource = new HashMap<>() {{ - put(ShortcutId.ID_ASSISTANT_VALUE, new int[] { + private static final Map<ShortcutId, int[]> sShortcutResource = Map.ofEntries( + Map.entry(ShortcutId.ID_ASSISTANT_VALUE, new int[] { R.drawable.ic_logo_a11y_assistant_24dp, R.color.assistant_color, R.string.assistant_utterance, R.string.assistant_label, - }); - put(ShortcutId.ID_A11YSETTING_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_A11YSETTING_VALUE, new int[] { R.drawable.ic_logo_a11y_settings_24dp, R.color.a11y_settings_color, R.string.a11y_settings_label, R.string.a11y_settings_label, - }); - put(ShortcutId.ID_POWER_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_POWER_VALUE, new int[] { R.drawable.ic_logo_a11y_power_24dp, R.color.power_color, R.string.power_utterance, R.string.power_label, - }); - put(ShortcutId.ID_RECENT_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_RECENT_VALUE, new int[] { R.drawable.ic_logo_a11y_recent_apps_24dp, R.color.recent_apps_color, R.string.recent_apps_label, R.string.recent_apps_label, - }); - put(ShortcutId.ID_LOCKSCREEN_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_LOCKSCREEN_VALUE, new int[] { R.drawable.ic_logo_a11y_lock_24dp, R.color.lockscreen_color, R.string.lockscreen_label, R.string.lockscreen_label, - }); - put(ShortcutId.ID_QUICKSETTING_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_QUICKSETTING_VALUE, new int[] { R.drawable.ic_logo_a11y_quick_settings_24dp, R.color.quick_settings_color, R.string.quick_settings_label, R.string.quick_settings_label, - }); - put(ShortcutId.ID_NOTIFICATION_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_NOTIFICATION_VALUE, new int[] { R.drawable.ic_logo_a11y_notifications_24dp, R.color.notifications_color, R.string.notifications_label, R.string.notifications_label, - }); - put(ShortcutId.ID_SCREENSHOT_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_SCREENSHOT_VALUE, new int[] { R.drawable.ic_logo_a11y_screenshot_24dp, R.color.screenshot_color, R.string.screenshot_utterance, R.string.screenshot_label, - }); - put(ShortcutId.ID_BRIGHTNESS_UP_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_BRIGHTNESS_UP_VALUE, new int[] { R.drawable.ic_logo_a11y_brightness_up_24dp, R.color.brightness_color, R.string.brightness_up_label, R.string.brightness_up_label, - }); - put(ShortcutId.ID_BRIGHTNESS_DOWN_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_BRIGHTNESS_DOWN_VALUE, new int[] { R.drawable.ic_logo_a11y_brightness_down_24dp, R.color.brightness_color, R.string.brightness_down_label, R.string.brightness_down_label, - }); - put(ShortcutId.ID_VOLUME_UP_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_VOLUME_UP_VALUE, new int[] { R.drawable.ic_logo_a11y_volume_up_24dp, R.color.volume_color, R.string.volume_up_label, R.string.volume_up_label, - }); - put(ShortcutId.ID_VOLUME_DOWN_VALUE, new int[] { + }), + Map.entry(ShortcutId.ID_VOLUME_DOWN_VALUE, new int[] { R.drawable.ic_logo_a11y_volume_down_24dp, R.color.volume_color, R.string.volume_down_label, R.string.volume_down_label, - }); - }}; + }) + ); /** Shortcut id used to identify. */ private int mShortcutId = ShortcutId.UNSPECIFIED_ID_VALUE.ordinal(); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java index 317201d2c2d9..f358ba2d3ccd 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java @@ -125,6 +125,7 @@ public class FloatingRotationButton implements RotationButton { taskbarMarginLeft, taskbarMarginBottom, floatingRotationButtonPositionLeft); final int diameter = res.getDimensionPixelSize(mButtonDiameterResource); + mKeyButtonView.setDiameter(diameter); mContainerSize = diameter + Math.max(defaultMargin, Math.max(taskbarMarginLeft, taskbarMarginBottom)); } @@ -195,6 +196,7 @@ public class FloatingRotationButton implements RotationButton { public void updateIcon(int lightIconColor, int darkIconColor) { mAnimatedDrawable = (AnimatedVectorDrawable) mKeyButtonView.getContext() .getDrawable(mRotationButtonController.getIconResId()); + mAnimatedDrawable.setBounds(0, 0, mKeyButtonView.getWidth(), mKeyButtonView.getHeight()); mKeyButtonView.setImageDrawable(mAnimatedDrawable); mKeyButtonView.setColors(lightIconColor, darkIconColor); } @@ -248,8 +250,14 @@ public class FloatingRotationButton implements RotationButton { updateDimensionResources(); if (mIsShowing) { + updateIcon(mRotationButtonController.getLightIconColor(), + mRotationButtonController.getDarkIconColor()); final LayoutParams layoutParams = adjustViewPositionAndCreateLayoutParams(); mWindowManager.updateViewLayout(mKeyButtonContainer, layoutParams); + if (mAnimatedDrawable != null) { + mAnimatedDrawable.reset(); + mAnimatedDrawable.start(); + } } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java index 2145166e9bc5..75412f94ccb1 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java @@ -37,6 +37,7 @@ public class FloatingRotationButtonView extends ImageView { private static final float BACKGROUND_ALPHA = 0.92f; private KeyButtonRipple mRipple; + private int mDiameter; private final Paint mOvalBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private final Configuration mLastConfiguration; @@ -93,10 +94,25 @@ public class FloatingRotationButtonView extends ImageView { mRipple.setDarkIntensity(darkIntensity); } + /** + * Sets the view's diameter. + * + * @param diameter the diameter value for the view + */ + void setDiameter(int diameter) { + mDiameter = diameter; + } + @Override public void draw(Canvas canvas) { int d = Math.min(getWidth(), getHeight()); canvas.drawOval(0, 0, d, d, mOvalBgPaint); super.draw(canvas); } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(mDiameter, mDiameter); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS new file mode 100644 index 000000000000..69ebb7674f72 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS @@ -0,0 +1,7 @@ +set noparent + +# Bug component: 78010 + +caitlinshk@google.com +evanlaird@google.com +pixel@google.com diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS index 4657e9b84550..92a333e9ec2a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS @@ -1,6 +1,6 @@ per-file *Notification* = set noparent per-file *Notification* = file:../notification/OWNERS -per-file NotificationIcon* = ccassidy@google.com, evanlaird@google.com, pixel@google.com +per-file NotificationIcon* = file:../OWNERS per-file NotificationShadeWindowControllerImpl.java = dupin@google.com, cinek@google.com, beverlyt@google.com, pixel@google.com, juliacr@google.com diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OWNERS new file mode 100644 index 000000000000..1c52b8d25347 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OWNERS @@ -0,0 +1,3 @@ +set noparent + +include /packages/SystemUI/src/com/android/systemui/statusbar/OWNERS diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 178102e2876d..25a0b4530498 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -16,6 +16,38 @@ filegroup { visibility: ["//visibility:public"], } +filegroup { + name: "ravenwood-services-policies", + srcs: [ + "texts/ravenwood-services-policies.txt", + ], + visibility: ["//visibility:public"], +} + +filegroup { + name: "ravenwood-framework-policies", + srcs: [ + "texts/ravenwood-framework-policies.txt", + ], + visibility: ["//visibility:public"], +} + +filegroup { + name: "ravenwood-standard-options", + srcs: [ + "texts/ravenwood-standard-options.txt", + ], + visibility: ["//visibility:public"], +} + +filegroup { + name: "ravenwood-annotation-allowed-classes", + srcs: [ + "texts/ravenwood-annotation-allowed-classes.txt", + ], + visibility: ["//visibility:public"], +} + java_library { name: "ravenwood-annotations-lib", srcs: [":ravenwood-annotations"], @@ -151,6 +183,82 @@ java_device_for_host { filegroup { name: "ravenwood-services-jarjar-rules", - srcs: ["ravenwood-services-jarjar-rules.txt"], + srcs: ["texts/ravenwood-services-jarjar-rules.txt"], visibility: ["//frameworks/base"], } + +java_library { + name: "services.fakes.ravenwood-jarjar", + installable: false, + srcs: [":services.fakes-sources"], + libs: [ + "ravenwood-framework", + "services.core.ravenwood", + ], + jarjar_rules: ":ravenwood-services-jarjar-rules", + visibility: ["//visibility:private"], +} + +java_library { + name: "mockito-ravenwood-prebuilt", + installable: false, + static_libs: [ + "mockito-robolectric-prebuilt", + ], +} + +java_library { + name: "inline-mockito-ravenwood-prebuilt", + installable: false, + static_libs: [ + "inline-mockito-robolectric-prebuilt", + ], +} + +android_ravenwood_libgroup { + name: "ravenwood-runtime", + libs: [ + "100-framework-minus-apex.ravenwood", + "200-kxml2-android", + + "android.test.mock.ravenwood", + "ravenwood-helper-runtime", + "hoststubgen-helper-runtime.ravenwood", + "services.core.ravenwood-jarjar", + "services.fakes.ravenwood-jarjar", + + // ICU + "core-icu4j-for-host.ravenwood", + "icu4j-icudata-jarjar", + "icu4j-icutzdata-jarjar", + + // Provide runtime versions of utils linked in below + "junit", + "truth", + "flag-junit", + "ravenwood-framework", + "ravenwood-junit-impl", + "ravenwood-junit-impl-flag", + "mockito-ravenwood-prebuilt", + "inline-mockito-ravenwood-prebuilt", + + // It's a stub, so it should be towards the end. + "z00-all-updatable-modules-system-stubs", + ], + jni_libs: [ + "libandroid_runtime", + ], +} + +android_ravenwood_libgroup { + name: "ravenwood-utils", + libs: [ + "junit", + "truth", + "flag-junit", + "ravenwood-framework", + "ravenwood-junit", + "mockito-ravenwood-prebuilt", + "inline-mockito-ravenwood-prebuilt", + ], +} diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt index 331dbb19ca37..331dbb19ca37 100644 --- a/ravenwood/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt index 371c3acab144..371c3acab144 100644 --- a/ravenwood/framework-minus-apex-ravenwood-policies.txt +++ b/ravenwood/texts/ravenwood-framework-policies.txt diff --git a/ravenwood/ravenwood-services-jarjar-rules.txt b/ravenwood/texts/ravenwood-services-jarjar-rules.txt index 8fdd3408f74d..8fdd3408f74d 100644 --- a/ravenwood/ravenwood-services-jarjar-rules.txt +++ b/ravenwood/texts/ravenwood-services-jarjar-rules.txt diff --git a/ravenwood/services.core-ravenwood-policies.txt b/ravenwood/texts/ravenwood-services-policies.txt index d8d563e05435..d8d563e05435 100644 --- a/ravenwood/services.core-ravenwood-policies.txt +++ b/ravenwood/texts/ravenwood-services-policies.txt diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt index f64f26d7962a..f64f26d7962a 100644 --- a/ravenwood/ravenwood-standard-options.txt +++ b/ravenwood/texts/ravenwood-standard-options.txt diff --git a/services/Android.bp b/services/Android.bp index a0d345430a4a..76fc1ba77c9b 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -108,6 +108,8 @@ filegroup { filegroup { name: "services-non-updatable-sources", srcs: [ + ":incremental_aidl", + ":services.core-aidl-sources", ":services.core-sources", ":services.core-sources-am-wm", "core/java/com/android/server/am/package.html", @@ -356,4 +358,8 @@ non_updatable_exportable_droidstubs { }, }, api_surface: "system-server", + sdk_version: "module_current", + libs: [ + "framework-annotations-lib", + ], } diff --git a/services/appfunctions/OWNERS b/services/appfunctions/OWNERS new file mode 100644 index 000000000000..b3108944a3ce --- /dev/null +++ b/services/appfunctions/OWNERS @@ -0,0 +1 @@ +include /core/java/android/app/appfunctions/OWNERS diff --git a/services/core/Android.bp b/services/core/Android.bp index fa323fd04837..9fbd8aa217dc 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -30,6 +30,18 @@ filegroup { ], } +filegroup { + name: "services.core-aidl-sources", + srcs: [ + ":dumpstate_aidl", + ":framework_native_aidl", + ":gsiservice_aidl", + ":installd_aidl", + ":storaged_aidl", + ":vold_aidl", + ], +} + java_library_static { name: "services-config-update", srcs: [ @@ -151,14 +163,9 @@ java_library_static { ":android.hardware.tv.hdmi.earc-V1-java-source", ":statslog-art-java-gen", ":statslog-contexthub-java-gen", + ":services.core-aidl-sources", ":services.core-sources", ":services.core.protologsrc", - ":dumpstate_aidl", - ":framework_native_aidl", - ":gsiservice_aidl", - ":installd_aidl", - ":storaged_aidl", - ":vold_aidl", ":platform-compat-config", ":platform-compat-overrides", ":display-device-config", diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 797993647be7..ab333b9928a0 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -157,7 +157,7 @@ public final class BatteryService extends SystemService { private int mLastMaxChargingVoltage; private int mLastChargeCounter; private int mLastBatteryCycleCount; - private int mLastCharingState; + private int mLastChargingState; /** * The last seen charging policy. This requires the * {@link android.Manifest.permission#BATTERY_STATS} permission and should therefore not be @@ -555,7 +555,7 @@ public final class BatteryService extends SystemService { || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter || mInvalidCharger != mLastInvalidCharger || mHealthInfo.batteryCycleCount != mLastBatteryCycleCount - || mHealthInfo.chargingState != mLastCharingState)) { + || mHealthInfo.chargingState != mLastChargingState)) { if (mPlugType != mLastPlugType) { if (mLastPlugType == BATTERY_PLUGGED_NONE) { @@ -738,7 +738,7 @@ public final class BatteryService extends SystemService { mLastBatteryLevelCritical = mBatteryLevelCritical; mLastInvalidCharger = mInvalidCharger; mLastBatteryCycleCount = mHealthInfo.batteryCycleCount; - mLastCharingState = mHealthInfo.chargingState; + mLastChargingState = mHealthInfo.chargingState; } } diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index eb037095c6c9..d9926a4a0f0d 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -150,6 +150,15 @@ public class PackageWatchdog { private static final int DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD = PackageHealthObserverImpact.USER_IMPACT_LEVEL_71; + // Comma separated list of all packages exempt from user impact level threshold. If a package + // in the list is crash looping, all the mitigations including factory reset will be performed. + private static final String PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD = + "persist.device_config.configuration.packages_exempt_from_impact_level_threshold"; + + // Comma separated list of default packages exempt from user impact level threshold. + private static final String DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD = + "com.android.systemui"; + private long mNumberOfNativeCrashPollsRemaining; private static final int DB_VERSION = 1; @@ -196,6 +205,8 @@ public class PackageWatchdog { private final DeviceConfig.OnPropertiesChangedListener mOnPropertyChangedListener = this::onPropertyChanged; + private final Set<String> mPackagesExemptFromImpactLevelThreshold = new ArraySet<>(); + // The set of packages that have been synced with the ExplicitHealthCheckController @GuardedBy("mLock") private Set<String> mRequestedHealthCheckPackages = new ArraySet<>(); @@ -518,7 +529,7 @@ public class PackageWatchdog { @FailureReasons int failureReason, int currentObserverImpact, int mitigationCount) { - if (currentObserverImpact < getUserImpactLevelLimit()) { + if (allowMitigations(currentObserverImpact, versionedPackage)) { synchronized (mLock) { mLastMitigation = mSystemClock.uptimeMillis(); } @@ -526,6 +537,13 @@ public class PackageWatchdog { } } + private boolean allowMitigations(int currentObserverImpact, + VersionedPackage versionedPackage) { + return currentObserverImpact < getUserImpactLevelLimit() + || getPackagesExemptFromImpactLevelThreshold().contains( + versionedPackage.getPackageName()); + } + private long getMitigationWindowMs() { return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS); } @@ -657,6 +675,15 @@ public class PackageWatchdog { DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD); } + private Set<String> getPackagesExemptFromImpactLevelThreshold() { + if (mPackagesExemptFromImpactLevelThreshold.isEmpty()) { + String packageNames = SystemProperties.get(PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD, + DEFAULT_PACKAGES_EXEMPT_FROM_IMPACT_LEVEL_THRESHOLD); + return Set.of(packageNames.split("\\s*,\\s*")); + } + return mPackagesExemptFromImpactLevelThreshold; + } + /** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */ @Retention(SOURCE) @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_LEVEL_0, diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index 47b65eb885ab..1f88657e5dbc 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -353,8 +353,8 @@ public final class AppExitInfoTracker { } /** Called when there is a low memory kill */ - void scheduleNoteLmkdProcKilled(final int pid, final int uid) { - mKillHandler.obtainMessage(KillHandler.MSG_LMKD_PROC_KILLED, pid, uid) + void scheduleNoteLmkdProcKilled(final int pid, final int uid, final int rssKb) { + mKillHandler.obtainMessage(KillHandler.MSG_LMKD_PROC_KILLED, pid, uid, Long.valueOf(rssKb)) .sendToTarget(); } @@ -401,9 +401,9 @@ public final class AppExitInfoTracker { if (lmkd != null) { updateExistingExitInfoRecordLocked(info, null, - ApplicationExitInfo.REASON_LOW_MEMORY); + ApplicationExitInfo.REASON_LOW_MEMORY, (Long) lmkd.second); } else if (zygote != null) { - updateExistingExitInfoRecordLocked(info, (Integer) zygote.second, null); + updateExistingExitInfoRecordLocked(info, (Integer) zygote.second, null, null); } else { scheduleLogToStatsdLocked(info, false); } @@ -486,7 +486,7 @@ public final class AppExitInfoTracker { */ @GuardedBy("mLock") private void updateExistingExitInfoRecordLocked(ApplicationExitInfo info, - Integer status, Integer reason) { + Integer status, Integer reason, Long rssKb) { if (info == null || !isFresh(info.getTimestamp())) { // if the record is way outdated, don't update it then (because of potential pid reuse) return; @@ -513,6 +513,9 @@ public final class AppExitInfoTracker { immediateLog = true; } } + if (rssKb != null) { + info.setRss(rssKb.longValue()); + } scheduleLogToStatsdLocked(info, immediateLog); } @@ -523,7 +526,7 @@ public final class AppExitInfoTracker { */ @GuardedBy("mLock") private boolean updateExitInfoIfNecessaryLocked( - int pid, int uid, Integer status, Integer reason) { + int pid, int uid, Integer status, Integer reason, Long rssKb) { Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid); if (k != null) { uid = k; @@ -552,7 +555,7 @@ public final class AppExitInfoTracker { // always be the first one we se as `getExitInfosLocked()` returns them sorted // by most-recent-first. isModified[0] = true; - updateExistingExitInfoRecordLocked(info, status, reason); + updateExistingExitInfoRecordLocked(info, status, reason, rssKb); return FOREACH_ACTION_STOP_ITERATION; } return FOREACH_ACTION_NONE; @@ -1668,11 +1671,11 @@ public final class AppExitInfoTracker { switch (msg.what) { case MSG_LMKD_PROC_KILLED: mAppExitInfoSourceLmkd.onProcDied(msg.arg1 /* pid */, msg.arg2 /* uid */, - null /* status */); + null /* status */, (Long) msg.obj /* rss_kb */); break; case MSG_CHILD_PROC_DIED: mAppExitInfoSourceZygote.onProcDied(msg.arg1 /* pid */, msg.arg2 /* uid */, - (Integer) msg.obj /* status */); + (Integer) msg.obj /* status */, null /* rss_kb */); break; case MSG_PROC_DIED: { ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj; @@ -1833,7 +1836,7 @@ public final class AppExitInfoTracker { } } - void onProcDied(final int pid, final int uid, final Integer status) { + void onProcDied(final int pid, final int uid, final Integer status, final Long rssKb) { if (DEBUG_PROCESSES) { Slog.i(TAG, mTag + ": proc died: pid=" + pid + " uid=" + uid + ", status=" + status); @@ -1846,8 +1849,12 @@ public final class AppExitInfoTracker { // Unlikely but possible: the record has been created // Let's update it if we could find a ApplicationExitInfo record synchronized (mLock) { - if (!updateExitInfoIfNecessaryLocked(pid, uid, status, mPresetReason)) { - addLocked(pid, uid, status); + if (!updateExitInfoIfNecessaryLocked(pid, uid, status, mPresetReason, rssKb)) { + if (rssKb != null) { + addLocked(pid, uid, rssKb); // lmkd + } else { + addLocked(pid, uid, status); // zygote + } } // Notify any interesed party regarding the lmkd kills diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index 11db302ebbd5..4b95a62df057 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -38,6 +38,7 @@ per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNE per-file ContentProviderHelper.java = varunshah@google.com, omakoto@google.com, jsharkey@google.com, yamasani@google.com per-file CachedAppOptimizer.java = file:/PERFORMANCE_OWNERS +per-file Freezer.java = file:/PERFORMANCE_OWNERS # Multiuser per-file User* = file:/MULTIUSER_OWNERS diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 97678aa922a4..b239b6476564 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -945,12 +945,14 @@ public final class ProcessList { try { switch (inputData.readInt()) { case LMK_PROCKILL: - if (receivedLen != 12) { + if (receivedLen != 16) { return false; } final int pid = inputData.readInt(); final int uid = inputData.readInt(); - mAppExitInfoTracker.scheduleNoteLmkdProcKilled(pid, uid); + final int rssKb = inputData.readInt(); + mAppExitInfoTracker.scheduleNoteLmkdProcKilled(pid, uid, + rssKb); return true; case LMK_KILL_OCCURRED: if (receivedLen diff --git a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java index 46b4f48165f9..44907457f649 100644 --- a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java +++ b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java @@ -17,8 +17,10 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiDeviceInfo; + import java.util.ArrayList; import java.util.Iterator; +import java.util.List; /** * Buffer storage to keep incoming messages for later processing. Used to @@ -83,6 +85,16 @@ final class DelayedMessageBuffer { return false; } + List<HdmiCecMessage> getBufferedMessagesWithOpcode(int opcode) { + List<HdmiCecMessage> messages = new ArrayList<>(); + for (HdmiCecMessage message : mBuffer) { + if (message.getOpcode() == opcode) { + messages.add(message); + } + } + return messages; + } + void processAllMessages() { // Use the copied buffer. ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<>(mBuffer); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 46061a56631c..6bc55886936e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -205,7 +205,9 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { resetSelectRequestBuffer(); launchDeviceDiscovery(); startQueuedActions(); - if (!mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) { + List<HdmiCecMessage> bufferedActiveSource = mDelayedMessageBuffer + .getBufferedMessagesWithOpcode(Constants.MESSAGE_ACTIVE_SOURCE); + if (bufferedActiveSource.isEmpty()) { addAndStartAction(new RequestActiveSourceAction(this, new IHdmiControlCallback.Stub() { @Override public void onComplete(int result) { @@ -220,9 +222,33 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } })); + } else { + addCecDeviceForBufferedActiveSource(bufferedActiveSource.get(0)); } } + // Add a new CEC device with known information from the buffered <Active Source> message. This + // helps TvInputCallback#onInputAdded to be called such that the message can be processed and + // the TV to switch to the new active input. + @ServiceThreadOnly + private void addCecDeviceForBufferedActiveSource(HdmiCecMessage bufferedActiveSource) { + assertRunOnServiceThread(); + if (bufferedActiveSource == null) { + return; + } + int source = bufferedActiveSource.getSource(); + int physicalAddress = HdmiUtils.twoBytesToInt(bufferedActiveSource.getParams()); + List<Integer> deviceTypes = HdmiUtils.getTypeFromAddress(source); + HdmiDeviceInfo newDevice = HdmiDeviceInfo.cecDeviceBuilder() + .setLogicalAddress(source) + .setPhysicalAddress(physicalAddress) + .setDisplayName(HdmiUtils.getDefaultDeviceName(source)) + .setDeviceType(deviceTypes.get(0)) + .setVendorId(Constants.VENDOR_ID_UNKNOWN) + .build(); + mService.getHdmiCecNetwork().addCecDevice(newDevice); + } + @ServiceThreadOnly public void setSelectRequestBuffer(SelectRequestBuffer requestBuffer) { assertRunOnServiceThread(); @@ -577,6 +603,12 @@ public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @Constants.HandleMessageResult protected int handleReportPhysicalAddress(HdmiCecMessage message) { super.handleReportPhysicalAddress(message); + // Ignore <Report Physical Address> while DeviceDiscoveryAction is in progress to avoid + // starting a NewDeviceAction which might interfere in creating the list of known devices. + if (hasAction(DeviceDiscoveryAction.class)) { + return Constants.HANDLED; + } + int path = HdmiUtils.twoBytesToInt(message.getParams()); int address = message.getSource(); int type = message.getParams()[2]; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java index a23c08a9e5c6..16b00de9702c 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java @@ -524,8 +524,7 @@ public class HdmiCecMessageValidator { if ((value & 0x80) != 0x00) { return false; } - // Validate than not more than one bit is set - return (Integer.bitCount(value) <= 1); + return true; } /** @@ -770,6 +769,7 @@ public class HdmiCecMessageValidator { * @return true if the UI Broadcast type is valid */ private static boolean isValidUiBroadcastType(int value) { + value = value & 0xFF; return ((value == 0x00) || (value == 0x01) || (value == 0x10) diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index 17f2fcc5b9d8..bb35b378866b 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -340,6 +340,11 @@ class LockSettingsShellCommand extends ShellCommand { getOutPrintWriter().println("Profile uses unified challenge"); return false; } + if (mOld.isEmpty()) { + getOutPrintWriter().println( + "User has a lock credential, but old credential was not provided"); + return false; + } try { final boolean result = mLockPatternUtils.checkCredential(getOldCredential(), diff --git a/services/core/java/com/android/server/net/Android.bp b/services/core/java/com/android/server/net/Android.bp index 3ac2d232dfc8..68dc7816c5a4 100644 --- a/services/core/java/com/android/server/net/Android.bp +++ b/services/core/java/com/android/server/net/Android.bp @@ -9,3 +9,10 @@ java_aconfig_library { name: "net_flags_lib", aconfig_declarations: "net_flags", } + +java_aconfig_library { + name: "net_flags_host_lib", + aconfig_declarations: "net_flags", + host_supported: true, + mode: "test", +} diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java index 5ea3e70f7957..74f0d9cf3e39 100644 --- a/services/core/java/com/android/server/net/NetworkManagementService.java +++ b/services/core/java/com/android/server/net/NetworkManagementService.java @@ -81,8 +81,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; import com.android.internal.util.DumpUtils; import com.android.internal.util.HexDump; -import com.android.modules.utils.build.SdkLevel; -import com.android.net.module.util.NetdUtils; import com.android.net.module.util.PermissionUtils; import com.android.server.FgThread; import com.android.server.LocalServices; @@ -833,144 +831,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } @Override - public boolean getIpForwardingEnabled() throws IllegalStateException{ - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException( - "NMS#getIpForwardingEnabled not supported in V+"); - } - try { - return mNetdService.ipfwdEnabled(); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void setIpForwardingEnabled(boolean enable) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException( - "NMS#setIpForwardingEnabled not supported in V+"); - } try { - if (enable) { - mNetdService.ipfwdEnableForwarding("tethering"); - } else { - mNetdService.ipfwdDisableForwarding("tethering"); - } - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void startTethering(String[] dhcpRange) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException("NMS#startTethering not supported in V+"); - } - try { - NetdUtils.tetherStart(mNetdService, true /* usingLegacyDnsProxy */, dhcpRange); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void stopTethering() { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException("NMS#stopTethering not supported in V+"); - } - try { - mNetdService.tetherStop(); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public boolean isTetheringStarted() { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException("NMS#isTetheringStarted not supported in V+"); - } - try { - return mNetdService.tetherIsEnabled(); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void tetherInterface(String iface) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException("NMS#tetherInterface not supported in V+"); - } - try { - final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress(); - final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength()); - NetdUtils.tetherInterface(mNetdService, iface, dest); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void untetherInterface(String iface) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException("NMS#untetherInterface not supported in V+"); - } - try { - NetdUtils.untetherInterface(mNetdService, iface); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public String[] listTetheredInterfaces() { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException( - "NMS#listTetheredInterfaces not supported in V+"); - } - try { - return mNetdService.tetherInterfaceList(); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void enableNat(String internalInterface, String externalInterface) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException("NMS#enableNat not supported in V+"); - } - try { - mNetdService.tetherAddForward(internalInterface, externalInterface); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void disableNat(String internalInterface, String externalInterface) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (SdkLevel.isAtLeastV()) { - throw new UnsupportedOperationException("NMS#disableNat not supported in V+"); - } - try { - mNetdService.tetherRemoveForward(internalInterface, externalInterface); - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } - } - - @Override public void setInterfaceQuota(String iface, long quotaBytes) { PermissionUtils.enforceNetworkStackPermission(mContext); @@ -1126,30 +986,19 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDataSaverModeEnabled"); try { - if (SdkLevel.isAtLeastV()) { - // setDataSaverEnabled throws if it fails to set data saver. - mContext.getSystemService(ConnectivityManager.class) - .setDataSaverEnabled(enable); - mDataSaverMode = enable; - if (mUseMeteredFirewallChains) { - // Copy mDataSaverMode state to FIREWALL_CHAIN_METERED_ALLOW - // until ConnectivityService allows manipulation of the data saver mode via - // FIREWALL_CHAIN_METERED_ALLOW. - synchronized (mRulesLock) { - mFirewallChainStates.put(FIREWALL_CHAIN_METERED_ALLOW, enable); - } - } - return true; - } else { - final boolean changed = mNetdService.bandwidthEnableDataSaver(enable); - if (changed) { - mDataSaverMode = enable; - } else { - Log.e(TAG, "setDataSaverMode(" + enable + "): failed to set iptables"); + // setDataSaverEnabled throws if it fails to set data saver. + mContext.getSystemService(ConnectivityManager.class).setDataSaverEnabled(enable); + mDataSaverMode = enable; + if (mUseMeteredFirewallChains) { + // Copy mDataSaverMode state to FIREWALL_CHAIN_METERED_ALLOW + // until ConnectivityService allows manipulation of the data saver mode via + // FIREWALL_CHAIN_METERED_ALLOW. + synchronized (mRulesLock) { + mFirewallChainStates.put(FIREWALL_CHAIN_METERED_ALLOW, enable); } - return changed; } - } catch (RemoteException | IllegalStateException e) { + return true; + } catch (IllegalStateException e) { Log.e(TAG, "setDataSaverMode(" + enable + "): failed with exception", e); return false; } finally { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 079f3381162b..7d2915ba48a2 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -530,6 +530,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ private boolean mUseDifferentDelaysForBackgroundChain; + /** + * Core uids and apps without the internet permission will not have any firewall rules applied + * to them. + */ + private boolean mNeverApplyRulesToCoreUids; + // See main javadoc for instructions on how to use these locks. final Object mUidRulesFirstLock = new Object(); final Object mNetworkPoliciesSecondLock = new Object(); @@ -622,16 +628,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray(); - @GuardedBy("mUidRulesFirstLock") - final SparseIntArray mUidFirewallDozableRules = new SparseIntArray(); - @GuardedBy("mUidRulesFirstLock") - final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray(); - @GuardedBy("mUidRulesFirstLock") - final SparseIntArray mUidFirewallBackgroundRules = new SparseIntArray(); - @GuardedBy("mUidRulesFirstLock") - final SparseIntArray mUidFirewallRestrictedModeRules = new SparseIntArray(); - @GuardedBy("mUidRulesFirstLock") - final SparseIntArray mUidFirewallLowPowerStandbyModeRules = new SparseIntArray(); /** Set of states for the child firewall chains. True if the chain is active. */ @GuardedBy("mUidRulesFirstLock") @@ -770,7 +766,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** List of apps indexed by uid and whether they have the internet permission */ @GuardedBy("mUidRulesFirstLock") - private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray(); + @VisibleForTesting + final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray(); /** * Map of uid -> UidStateCallbackInfo objects holding the data received from @@ -1048,6 +1045,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUseMeteredFirewallChains = Flags.useMeteredFirewallChains(); mUseDifferentDelaysForBackgroundChain = Flags.useDifferentDelaysForBackgroundChain(); + mNeverApplyRulesToCoreUids = Flags.neverApplyRulesToCoreUids(); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { @@ -4098,6 +4096,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + mUseMeteredFirewallChains); fout.println(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN + ": " + mUseDifferentDelaysForBackgroundChain); + fout.println(Flags.FLAG_NEVER_APPLY_RULES_TO_CORE_UIDS + ": " + + mNeverApplyRulesToCoreUids); fout.println(); fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode); @@ -4118,7 +4118,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.increaseIndent(); for (int i = 0; i < mSubscriptionPlans.size(); i++) { final int subId = mSubscriptionPlans.keyAt(i); - fout.println("Subscriber ID " + subId + ":"); + fout.println("Subscription ID " + subId + ":"); fout.increaseIndent(); final SubscriptionPlan[] plans = mSubscriptionPlans.valueAt(i); if (!ArrayUtils.isEmpty(plans)) { @@ -4589,7 +4589,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @VisibleForTesting @GuardedBy("mUidRulesFirstLock") void updateRestrictedModeAllowlistUL() { - mUidFirewallRestrictedModeRules.clear(); + final SparseIntArray uidRules = new SparseIntArray(); forEachUid("updateRestrictedModeAllowlist", uid -> { synchronized (mUidRulesFirstLock) { final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL( @@ -4599,13 +4599,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add // non-default rules. if (newFirewallRule != FIREWALL_RULE_DEFAULT) { - mUidFirewallRestrictedModeRules.append(uid, newFirewallRule); + uidRules.append(uid, newFirewallRule); } } }); if (mRestrictedNetworkingMode) { // firewall rules only need to be set when this mode is being enabled. - setUidFirewallRulesUL(FIREWALL_CHAIN_RESTRICTED, mUidFirewallRestrictedModeRules); + setUidFirewallRulesUL(FIREWALL_CHAIN_RESTRICTED, uidRules); } enableFirewallChainUL(FIREWALL_CHAIN_RESTRICTED, mRestrictedNetworkingMode); } @@ -4689,8 +4689,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void updateRulesForPowerSaveUL() { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL"); try { - updateRulesForAllowlistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE, - mUidFirewallPowerSaveRules); + updateRulesForAllowlistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE); } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } @@ -4705,8 +4704,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void updateRulesForDeviceIdleUL() { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForDeviceIdleUL"); try { - updateRulesForAllowlistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE, - mUidFirewallDozableRules); + updateRulesForAllowlistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE); } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } @@ -4720,13 +4718,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // NOTE: since both fw_dozable and fw_powersave uses the same map // (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method. @GuardedBy("mUidRulesFirstLock") - private void updateRulesForAllowlistedPowerSaveUL(boolean enabled, int chain, - SparseIntArray rules) { + private void updateRulesForAllowlistedPowerSaveUL(boolean enabled, int chain) { if (enabled) { // Sync the allowlists before enabling the chain. We don't care about the rules if // we are disabling the chain. - final SparseIntArray uidRules = rules; - uidRules.clear(); + final SparseIntArray uidRules = new SparseIntArray(); final List<UserInfo> users = mUserManager.getUsers(); for (int ui = users.size() - 1; ui >= 0; ui--) { UserInfo user = users.get(ui); @@ -4755,9 +4751,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateRulesForBackgroundChainUL() { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForBackgroundChainUL"); try { - final SparseIntArray uidRules = mUidFirewallBackgroundRules; - uidRules.clear(); - + final SparseIntArray uidRules = new SparseIntArray(); final List<UserInfo> users = mUserManager.getUsers(); for (int ui = users.size() - 1; ui >= 0; ui--) { final UserInfo user = users.get(ui); @@ -4794,17 +4788,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForLowPowerStandbyUL"); try { if (mLowPowerStandbyActive) { - mUidFirewallLowPowerStandbyModeRules.clear(); + final SparseIntArray uidRules = new SparseIntArray(); for (int i = mUidState.size() - 1; i >= 0; i--) { final int uid = mUidState.keyAt(i); final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid); if (hasInternetPermissionUL(uid) && (effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) { - mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW); + uidRules.put(uid, FIREWALL_RULE_ALLOW); } } setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, - mUidFirewallLowPowerStandbyModeRules, CHAIN_TOGGLE_ENABLE); + uidRules, CHAIN_TOGGLE_ENABLE); } else { setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, null, CHAIN_TOGGLE_DISABLE); } @@ -4822,10 +4816,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid); if (mUidState.contains(uid) && (effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) { - mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW); setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW); } else { - mUidFirewallLowPowerStandbyModeRules.delete(uid); setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_DEFAULT); } } @@ -4896,6 +4888,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { int[] idleUids = mUsageStats.getIdleUidsForUser(user.id); for (int uid : idleUids) { if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) { + if (mNeverApplyRulesToCoreUids && !isUidValidForRulesUL(uid)) { + // This check is needed to keep mUidFirewallStandbyRules free of any + // such uids. Doing this keeps it in sync with the actual rules applied + // in the underlying connectivity stack. + continue; + } // quick check: if this uid doesn't have INTERNET permission, it // doesn't have network access anyway, so it is a waste to mess // with it here. @@ -5198,6 +5196,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private boolean isUidValidForAllowlistRulesUL(int uid) { + return isUidValidForRulesUL(uid); + } + + @GuardedBy("mUidRulesFirstLock") + private boolean isUidValidForRulesUL(int uid) { return UserHandle.isApp(uid) && hasInternetPermissionUL(uid); } @@ -5313,16 +5316,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mActivityManagerInternal.onUidBlockedReasonsChanged(uid, BLOCKED_REASON_NONE); mUidPolicy.delete(uid); mUidFirewallStandbyRules.delete(uid); - mUidFirewallDozableRules.delete(uid); - mUidFirewallPowerSaveRules.delete(uid); - mUidFirewallBackgroundRules.delete(uid); mBackgroundTransitioningUids.delete(uid); mPowerSaveWhitelistExceptIdleAppIds.delete(uid); mPowerSaveWhitelistAppIds.delete(uid); mPowerSaveTempWhitelistAppIds.delete(uid); mAppIdleTempWhitelistAppIds.delete(uid); - mUidFirewallRestrictedModeRules.delete(uid); - mUidFirewallLowPowerStandbyModeRules.delete(uid); synchronized (mUidStateCallbackInfos) { mUidStateCallbackInfos.remove(uid); } @@ -6217,41 +6215,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) { - final int size = uidRules.size(); - final SparseIntArray sdkSandboxUids = new SparseIntArray(); - for (int index = 0; index < size; index++) { - final int uid = uidRules.keyAt(index); - final int rule = uidRules.valueAt(index); - if (Process.isApplicationUid(uid)) { - sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule); - } - } - - for (int index = 0; index < sdkSandboxUids.size(); index++) { - final int uid = sdkSandboxUids.keyAt(index); - final int rule = sdkSandboxUids.valueAt(index); - uidRules.put(uid, rule); - } - } - /** * Set uid rules on a particular firewall chain. This is going to synchronize the rules given * here to netd. It will clean up dead rules and make sure the target chain only contains rules * specified here. */ + @GuardedBy("mUidRulesFirstLock") private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) { - addSdkSandboxUidsIfNeeded(uidRules); try { int size = uidRules.size(); - int[] uids = new int[size]; - int[] rules = new int[size]; + final IntArray uids = new IntArray(size); + final IntArray rules = new IntArray(size); for(int index = size - 1; index >= 0; --index) { - uids[index] = uidRules.keyAt(index); - rules[index] = uidRules.valueAt(index); + final int uid = uidRules.keyAt(index); + if (mNeverApplyRulesToCoreUids && !isUidValidForRulesUL(uid)) { + continue; + } + uids.add(uid); + rules.add(uidRules.valueAt(index)); + if (Process.isApplicationUid(uid)) { + uids.add(Process.toSdkSandboxUid(uid)); + rules.add(uidRules.valueAt(index)); + } } - mNetworkManager.setFirewallUidRules(chain, uids, rules); - mLogger.firewallRulesChanged(chain, uids, rules); + final int[] uidArray = uids.toArray(); + final int[] ruleArray = rules.toArray(); + mNetworkManager.setFirewallUidRules(chain, uidArray, ruleArray); + mLogger.firewallRulesChanged(chain, uidArray, ruleArray); } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting firewall uid rules", e); } catch (RemoteException e) { @@ -6264,26 +6254,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ @GuardedBy("mUidRulesFirstLock") private void setUidFirewallRuleUL(int chain, int uid, int rule) { + if (mNeverApplyRulesToCoreUids && !isUidValidForRulesUL(uid)) { + return; + } if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setUidFirewallRuleUL: " + chain + "/" + uid + "/" + rule); } try { - if (chain == FIREWALL_CHAIN_DOZABLE) { - mUidFirewallDozableRules.put(uid, rule); - } else if (chain == FIREWALL_CHAIN_STANDBY) { + if (chain == FIREWALL_CHAIN_STANDBY) { mUidFirewallStandbyRules.put(uid, rule); - } else if (chain == FIREWALL_CHAIN_POWERSAVE) { - mUidFirewallPowerSaveRules.put(uid, rule); - } else if (chain == FIREWALL_CHAIN_RESTRICTED) { - mUidFirewallRestrictedModeRules.put(uid, rule); - } else if (chain == FIREWALL_CHAIN_LOW_POWER_STANDBY) { - mUidFirewallLowPowerStandbyModeRules.put(uid, rule); - } else if (chain == FIREWALL_CHAIN_BACKGROUND) { - mUidFirewallBackgroundRules.put(uid, rule); - } - // Note that we do not need keep a separate cache of uid rules for chains that we do - // not call #setUidFirewallRulesUL for. + } try { mNetworkManager.setFirewallUidRule(chain, uid, rule); @@ -6328,6 +6309,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Resets all firewall rules associated with an UID. */ private void resetUidFirewallRules(int uid) { + // Resetting rules for uids with isUidValidForRulesUL = false should be OK as no rules + // should be previously set and the downstream code will skip no-op changes. try { mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT); diff --git a/services/core/java/com/android/server/net/flags.aconfig b/services/core/java/com/android/server/net/flags.aconfig index 586baf022897..7f04e665567e 100644 --- a/services/core/java/com/android/server/net/flags.aconfig +++ b/services/core/java/com/android/server/net/flags.aconfig @@ -27,3 +27,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "never_apply_rules_to_core_uids" + namespace: "backstage_power" + description: "Removes all rule bookkeeping and evaluation logic for core uids and uids without the internet permission" + bug: "356956588" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/core/java/com/android/server/net/watchlist/OWNERS b/services/core/java/com/android/server/net/watchlist/OWNERS index d0c4e553ad8c..eef1e46b2ba6 100644 --- a/services/core/java/com/android/server/net/watchlist/OWNERS +++ b/services/core/java/com/android/server/net/watchlist/OWNERS @@ -1,2 +1 @@ -alanstokes@google.com simonjw@google.com diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index ee755dd395d8..8c1eab90bba5 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -156,7 +156,8 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO, UserManager.DISALLOW_SIM_GLOBALLY, UserManager.DISALLOW_ASSIST_CONTENT, - UserManager.DISALLOW_THREAD_NETWORK + UserManager.DISALLOW_THREAD_NETWORK, + UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO }); public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet( @@ -208,7 +209,8 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_CELLULAR_2G, UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO, - UserManager.DISALLOW_THREAD_NETWORK + UserManager.DISALLOW_THREAD_NETWORK, + UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO ); /** @@ -255,8 +257,9 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_CELLULAR_2G, UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO, - UserManager.DISALLOW_THREAD_NETWORK - ); + UserManager.DISALLOW_THREAD_NETWORK, + UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO + ); /** * Special user restrictions that profile owner of an organization-owned managed profile can diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java index f8c678aa3aa3..e9407c2acb91 100644 --- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java +++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java @@ -135,6 +135,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.KeepForWeakReference; import com.android.internal.camera.flags.Flags; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.os.BackgroundThread; @@ -2006,8 +2007,12 @@ public final class SensorPrivacyService extends SystemService { } private class CallStateHelper { - private OutgoingEmergencyStateCallback mEmergencyStateCallback; - private CallStateCallback mCallStateCallback; + // TelephonyCallback instances are only weakly referenced when registered, so we need + // to ensure these fields are kept during optimization to preserve lifecycle semantics. + @KeepForWeakReference + private final OutgoingEmergencyStateCallback mEmergencyStateCallback; + @KeepForWeakReference + private final CallStateCallback mCallStateCallback; private boolean mIsInEmergencyCall; private boolean mMicUnmutedForEmergencyCall; diff --git a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java index aa2b74edaff2..58c3ba5013fa 100644 --- a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java +++ b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessor.java @@ -56,12 +56,17 @@ public class ZoneInfoDbTimeZoneProviderEventPreProcessor // enables immediate failover to a secondary provider, one that might provide valid IDs for // the same location, which should provide better behavior than just ignoring the event. if (hasInvalidZones(event)) { - TimeZoneProviderStatus providerStatus = new TimeZoneProviderStatus.Builder( - event.getTimeZoneProviderStatus()) - .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED) - .build(); - return TimeZoneProviderEvent.createUncertainEvent( - event.getCreationElapsedMillis(), providerStatus); + TimeZoneProviderStatus providerStatus = event.getTimeZoneProviderStatus(); + TimeZoneProviderStatus.Builder providerStatusBuilder; + if (providerStatus != null) { + providerStatusBuilder = new TimeZoneProviderStatus.Builder(providerStatus); + } else { + providerStatusBuilder = new TimeZoneProviderStatus.Builder(); + } + return TimeZoneProviderEvent.createUncertainEvent(event.getCreationElapsedMillis(), + providerStatusBuilder + .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED) + .build()); } return event; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 67c2b28492d9..ccb6ba7e6344 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -367,6 +367,7 @@ import android.window.WindowOnBackInvokedDispatcher; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.KeepForWeakReference; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; @@ -938,6 +939,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private RemoteCallbackList<IScreenCaptureObserver> mCaptureCallbacks; + // Ensure the field is kept during optimization to preserve downstream weak refs. + @KeepForWeakReference private final ColorDisplayService.ColorTransformController mColorTransformController = (matrix, translation) -> mWmService.mH.post(() -> { synchronized (mWmService.mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 1353ff09b292..a31099281306 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2291,7 +2291,7 @@ class Task extends TaskFragment { // Apply crop to root tasks only and clear the crops of the descendant tasks. int width = 0; int height = 0; - if (isRootTask()) { + if (isRootTask() && !mTransitionController.mIsWaitingForDisplayEnabled) { final Rect taskBounds = getBounds(); width = taskBounds.width(); height = taskBounds.height(); diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS index 02cba21b8269..3a83b461e8b9 100644 --- a/services/core/jni/OWNERS +++ b/services/core/jni/OWNERS @@ -30,7 +30,8 @@ per-file com_android_server_power_stats_* = file:/BATTERY_STATS_OWNERS per-file com_android_server_security_* = file:/core/java/android/security/OWNERS per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS -per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com +per-file com_android_server_am_CachedAppOptimizer.cpp = file:/PERFORMANCE_OWNERS +per-file com_android_server_am_Freezer.cpp = file:/PERFORMANCE_OWNERS per-file com_android_server_companion_virtual_InputController.cpp = file:/services/companion/java/com/android/server/companion/virtual/OWNERS # Memory diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 1c22087965b8..6e65a7453cf5 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1115,9 +1115,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void onUserUnlocked(@NonNull TargetUser user) { - if (user.isPreCreated()) return; - mService.handleOnUserUnlocked(user.getUserIdentifier()); + public void onUserSwitching(@NonNull TargetUser from, @NonNull TargetUser to) { + if (to.isPreCreated()) return; + mService.handleOnUserSwitching(from.getUserIdentifier(), to.getUserIdentifier()); } } @@ -3680,8 +3680,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mDevicePolicyEngine.handleUnlockUser(userId); } - void handleOnUserUnlocked(int userId) { - showNewUserDisclaimerIfNecessary(userId); + void handleOnUserSwitching(int fromUserId, int toUserId) { + showNewUserDisclaimerIfNecessary(toUserId); } void handleStopUser(int userId) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java index 1000bfa5f6c9..dbd60c5af274 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java @@ -17,6 +17,7 @@ package com.android.server.devicepolicy; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.VerifierDeviceIdentity; import android.net.wifi.WifiManager; import android.os.Build; @@ -66,13 +67,14 @@ class EnterpriseSpecificIdCalculator { mMeid = meid; mSerialNumber = Build.getSerial(); WifiManager wifiManager = context.getSystemService(WifiManager.class); - Preconditions.checkState(wifiManager != null, "Unable to access WiFi service"); - final String[] macAddresses = wifiManager.getFactoryMacAddresses(); - if (macAddresses == null || macAddresses.length == 0) { - mMacAddress = ""; - } else { - mMacAddress = macAddresses[0]; + String macAddress = ""; + if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) { + final String[] macAddresses = wifiManager.getFactoryMacAddresses(); + if (macAddresses != null && macAddresses.length > 0) { + macAddress = macAddresses[0]; + } } + mMacAddress = macAddress; } private static String getPaddedTruncatedString(String input, int maxLength) { diff --git a/services/fakes/Android.bp b/services/fakes/Android.bp index 148054b31e89..d44bb5ae302c 100644 --- a/services/fakes/Android.bp +++ b/services/fakes/Android.bp @@ -16,5 +16,5 @@ filegroup { "java/**/*.java", ], path: "java", - visibility: ["//frameworks/base"], + visibility: ["//frameworks/base/ravenwood:__subpackages__"], } diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 3ed6ad78343b..dab397864613 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -354,6 +354,9 @@ public final class ProfcollectForwardingService extends SystemService { private static void createAndUploadReport(ProfcollectForwardingService pfs) { BackgroundThread.get().getThreadHandler().post(() -> { + if (pfs.mIProfcollect == null) { + return; + } String reportName; try { reportName = pfs.mIProfcollect.report(pfs.mUsageSetting) + ".zip"; @@ -398,17 +401,19 @@ public final class ProfcollectForwardingService extends SystemService { if (randomNum >= traceFrequency) { return; } - // For a small percentage a traces, we collect the initialization behavior. - boolean traceInitialization = ThreadLocalRandom.current().nextInt(10) < 1; - int traceDelay = traceInitialization ? 0 : 1000; - String traceTag = traceInitialization ? "camera_init" : "camera"; - BackgroundThread.get().getThreadHandler().postDelayed(() -> { + final int traceDuration = 5000; + final String traceTag = "camera"; + BackgroundThread.get().getThreadHandler().post(() -> { + if (mIProfcollect == null) { + return; + } try { - mIProfcollect.trace_process(traceTag, "android.hardware.camera.provider"); + mIProfcollect.trace_process(traceTag, "android.hardware.camera.provider", + traceDuration); } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); } - }, traceDelay); + }); } }, null); } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java index adcbf5c9d059..194bf4ba73f3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java @@ -442,20 +442,24 @@ public class ApplicationExitInfoTest { IMPORTANCE_FOREGROUND_SERVICE, // importance null); // description - // Case 4: Create a process from another package with kill from lmkd + /* + * Case 4: Create a process from another package with kill from lmkd + * We expect LMKD's reported RSS to be the process' last seen RSS. + */ final int app2UidUser2 = 1010234; final int app2PidUser2 = 12348; final long app2Pss1 = 54321; final long app2Rss1 = 65432; + final long lmkd_reported_rss = 43215; final String app2ProcessName = "com.android.test.stub2:process"; final String app2PackageName = "com.android.test.stub2"; sleep(1); final long now4 = System.currentTimeMillis(); - doReturn(new Pair<Long, Object>(now4, Integer.valueOf(0))) + doReturn(null) .when(mAppExitInfoTracker.mAppExitInfoSourceZygote) .remove(anyInt(), anyInt()); - doReturn(new Pair<Long, Object>(now4, null)) + doReturn(new Pair<Long, Object>(now4, Long.valueOf(lmkd_reported_rss))) .when(mAppExitInfoTracker.mAppExitInfoSourceLmkd) .remove(anyInt(), anyInt()); @@ -490,7 +494,7 @@ public class ApplicationExitInfoTest { null, // subReason 0, // status app2Pss1, // pss - app2Rss1, // rss + lmkd_reported_rss, // rss IMPORTANCE_CACHED, // importance null); // description @@ -499,6 +503,11 @@ public class ApplicationExitInfoTest { mAppExitInfoTracker.getExitInfo(null, app2UidUser2, 0, 0, list); assertEquals(1, list.size()); + info = list.get(0); + + // Verify the AppExitInfo has the LMKD reported RSS + assertEquals(lmkd_reported_rss, info.getRss()); + // Case 5: App native crash final int app3UidUser2 = 1010345; final int app3PidUser2 = 12349; @@ -599,7 +608,7 @@ public class ApplicationExitInfoTest { null, // subReason 0, // status app2Pss1, // pss - app2Rss1, // rss + lmkd_reported_rss, // rss IMPORTANCE_CACHED, // importance null); // description diff --git a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS index 2cbc226da780..4fac647c4ceb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS +++ b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS @@ -1,3 +1,4 @@ include /services/core/java/com/android/server/am/OWNERS per-file ApplicationStartInfoTest.java = yforta@google.com, carmenjackson@google.com, jji@google.com +per-file CachedAppOptimizerTest.java = file:/PERFORMANCE_OWNERS diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java index 67ae9984266f..a4e636c01d65 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -26,6 +26,7 @@ import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE; +import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON; import static com.google.common.truth.Truth.assertThat; @@ -1878,4 +1879,61 @@ public class HdmiCecLocalDeviceTvTest { assertThat(mPowerManager.isInteractive()).isTrue(); } + + @Test + public void handleReportPhysicalAddress_DeviceDiscoveryActionInProgress_noNewDeviceAction() { + mHdmiControlService.getHdmiCecNetwork().clearDeviceList(); + mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mNativeWrapper.clearResultMessages(); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportPhysicalAddressFromPlayback1 = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_PLAYBACK_1, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK); + HdmiCecMessage reportPhysicalAddressFromPlayback2 = + HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_PLAYBACK_2, 0x2000, HdmiDeviceInfo.DEVICE_PLAYBACK); + HdmiCecMessage giveOsdName = HdmiCecMessageBuilder.buildGiveOsdNameCommand( + ADDR_TV, ADDR_PLAYBACK_2); + // Skip state waiting for <Report Physical Address> for DeviceDiscoveryAction s.t. message + // can be dispatched to local device TV. + mNativeWrapper.onCecMessage(reportPhysicalAddressFromPlayback1); + mNativeWrapper.clearResultMessages(); + mTestLooper.dispatchAll(); + + mNativeWrapper.onCecMessage(reportPhysicalAddressFromPlayback2); + mTestLooper.dispatchAll(); + + // NewDeviceAction did not start and <Give OSD Name> was not sent. + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveOsdName); + } + + @Test + public void onOneTouchPlay_wakeUp_addCecDevice() { + assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false)) + .isEmpty(); + mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, + HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED); + mPowerManager.setInteractive(false); + mTestLooper.dispatchAll(); + + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1, + mTvLogicalAddress); + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + 0x1000); + assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED); + assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(activeSource)).isEqualTo( + Constants.HANDLED); + mTestLooper.dispatchAll(); + assertThat(mPowerManager.isInteractive()).isTrue(); + + // FakePowerManagerWrapper#wakeUp() doesn't broadcast Intent.ACTION_SCREEN_ON so we have to + // manually call this method. + mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON); + mTestLooper.dispatchAll(); + assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false)) + .hasSize(1); + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java index 0aa72d00be1b..ce7dbda895c0 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java @@ -239,6 +239,9 @@ public class HdmiCecMessageValidatorTest { public void isValid_setAnalogueTimer_clearAnalogueTimer() { assertMessageValidity("04:33:0C:08:10:1E:04:30:08:00:13:AD:06").isEqualTo(OK); assertMessageValidity("04:34:04:0C:16:0F:08:37:00:02:EA:60:03:34").isEqualTo(OK); + // Allow [Recording Sequence] set multiple days of the week. + // e.g. Monday (0x02) | Tuesday (0x04) -> Monday or Tuesday (0x06) + assertMessageValidity("04:34:04:0C:16:0F:08:37:06:02:EA:60:03:34").isEqualTo(OK); assertMessageValidity("0F:33:0C:08:10:1E:04:30:08:00:13:AD:06") .isEqualTo(ERROR_DESTINATION); @@ -307,7 +310,7 @@ public class HdmiCecMessageValidatorTest { // Invalid Recording Sequence assertMessageValidity("04:99:12:06:0C:2D:5A:19:90:91:04:00:B1").isEqualTo(ERROR_PARAMETER); // Invalid Recording Sequence - assertMessageValidity("04:97:0C:08:15:05:04:1E:21:00:C4:C2:11:D8:75:30") + assertMessageValidity("04:97:0C:08:15:05:04:1E:A1:00:C4:C2:11:D8:75:30") .isEqualTo(ERROR_PARAMETER); // Invalid Digital Broadcast System @@ -353,7 +356,7 @@ public class HdmiCecMessageValidatorTest { // Invalid Recording Sequence assertMessageValidity("40:A2:14:09:12:28:4B:19:84:05:10:00").isEqualTo(ERROR_PARAMETER); // Invalid Recording Sequence - assertMessageValidity("40:A1:0C:08:15:05:04:1E:14:04:20").isEqualTo(ERROR_PARAMETER); + assertMessageValidity("40:A1:0C:08:15:05:04:1E:94:04:20").isEqualTo(ERROR_PARAMETER); // Invalid external source specifier assertMessageValidity("40:A2:14:09:12:28:4B:19:10:08:10:00").isEqualTo(ERROR_PARAMETER); // Invalid External PLug diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 3d6884925098..dddab657be14 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -108,6 +108,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -165,6 +166,7 @@ import android.os.PowerExemptionManager; import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.PowerSaveState; +import android.os.Process; import android.os.RemoteException; import android.os.SimpleClock; import android.os.SystemClock; @@ -197,6 +199,7 @@ import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent; import com.android.internal.util.test.FsUtil; @@ -2310,6 +2313,70 @@ public class NetworkPolicyManagerServiceTest { assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } + @SuppressWarnings("GuardedBy") // For not holding mUidRulesFirstLock + @Test + @RequiresFlagsEnabled(Flags.FLAG_NEVER_APPLY_RULES_TO_CORE_UIDS) + public void testRulesNeverAppliedToCoreUids() throws Exception { + clearInvocations(mNetworkManager); + + final int coreAppId = Process.FIRST_APPLICATION_UID - 102; + final int coreUid = UserHandle.getUid(USER_ID, coreAppId); + + // Enable all restrictions and add this core uid to all allowlists. + mService.mDeviceIdleMode = true; + mService.mRestrictPower = true; + setRestrictBackground(true); + expectHasUseRestrictedNetworksPermission(coreUid, true); + enableRestrictedMode(true); + final NetworkPolicyManagerInternal internal = LocalServices.getService( + NetworkPolicyManagerInternal.class); + internal.setLowPowerStandbyActive(true); + internal.setLowPowerStandbyAllowlist(new int[]{coreUid}); + internal.onTempPowerSaveWhitelistChange(coreAppId, true, REASON_OTHER, "testing"); + + when(mPowerExemptionManager.getAllowListedAppIds(anyBoolean())) + .thenReturn(new int[]{coreAppId}); + mPowerAllowlistReceiver.onReceive(mServiceContext, null); + + // A normal uid would undergo a rule change from denied to allowed on all chains, but we + // should not request any rule change for this core uid. + verify(mNetworkManager, never()).setFirewallUidRule(anyInt(), eq(coreUid), anyInt()); + verify(mNetworkManager, never()).setFirewallUidRules(anyInt(), + argThat(ar -> ArrayUtils.contains(ar, coreUid)), any(int[].class)); + } + + @SuppressWarnings("GuardedBy") // For not holding mUidRulesFirstLock + @Test + @RequiresFlagsEnabled(Flags.FLAG_NEVER_APPLY_RULES_TO_CORE_UIDS) + public void testRulesNeverAppliedToUidsWithoutInternetPermission() throws Exception { + clearInvocations(mNetworkManager); + + mService.mInternetPermissionMap.clear(); + expectHasInternetPermission(UID_A, false); + + // Enable all restrictions and add this uid to all allowlists. + mService.mDeviceIdleMode = true; + mService.mRestrictPower = true; + setRestrictBackground(true); + expectHasUseRestrictedNetworksPermission(UID_A, true); + enableRestrictedMode(true); + final NetworkPolicyManagerInternal internal = LocalServices.getService( + NetworkPolicyManagerInternal.class); + internal.setLowPowerStandbyActive(true); + internal.setLowPowerStandbyAllowlist(new int[]{UID_A}); + internal.onTempPowerSaveWhitelistChange(APP_ID_A, true, REASON_OTHER, "testing"); + + when(mPowerExemptionManager.getAllowListedAppIds(anyBoolean())) + .thenReturn(new int[]{APP_ID_A}); + mPowerAllowlistReceiver.onReceive(mServiceContext, null); + + // A normal uid would undergo a rule change from denied to allowed on all chains, but we + // should not request any rule this uid without the INTERNET permission. + verify(mNetworkManager, never()).setFirewallUidRule(anyInt(), eq(UID_A), anyInt()); + verify(mNetworkManager, never()).setFirewallUidRules(anyInt(), + argThat(ar -> ArrayUtils.contains(ar, UID_A)), any(int[].class)); + } + private boolean isUidState(int uid, int procState, int procStateSeq, int capability) { final NetworkPolicyManager.UidState uidState = mService.getUidStateForTest(uid); if (uidState == null) { diff --git a/services/tests/timetests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java index f3440f7c9d1c..ea3b409e5929 100644 --- a/services/tests/timetests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java +++ b/services/tests/timetests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneProviderEventPreProcessorTest.java @@ -39,13 +39,23 @@ public class ZoneInfoDbTimeZoneProviderEventPreProcessorTest { private static final long ARBITRARY_TIME_MILLIS = 11223344; + private final List<String> mNonExistingTimeZones = Arrays.asList( + "SystemV/HST10", "Atlantic/Atlantis", "EUROPE/LONDON", "Etc/GMT-5:30"); private final ZoneInfoDbTimeZoneProviderEventPreProcessor mPreProcessor = new ZoneInfoDbTimeZoneProviderEventPreProcessor(); + private static final TimeZoneProviderStatus ARBITRARY_TIME_ZONE_PROVIDER_STATUS = + new TimeZoneProviderStatus.Builder() + .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK) + .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK) + .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK) + .build(); + @Test public void timeZoneIdsFromZoneInfoDbAreValid() { for (String timeZone : TimeZone.getAvailableIDs()) { - TimeZoneProviderEvent event = timeZoneProviderEvent(timeZone); + TimeZoneProviderEvent event = timeZoneProviderEvent(timeZone, + ARBITRARY_TIME_ZONE_PROVIDER_STATUS); assertWithMessage("Time zone %s should be supported", timeZone) .that(mPreProcessor.preProcess(event)).isEqualTo(event); } @@ -53,11 +63,9 @@ public class ZoneInfoDbTimeZoneProviderEventPreProcessorTest { @Test public void eventWithNonExistingZones_areMappedToUncertainEvent() { - List<String> nonExistingTimeZones = Arrays.asList( - "SystemV/HST10", "Atlantic/Atlantis", "EUROPE/LONDON", "Etc/GMT-5:30"); - - for (String timeZone : nonExistingTimeZones) { - TimeZoneProviderEvent event = timeZoneProviderEvent(timeZone); + for (String timeZone : mNonExistingTimeZones) { + TimeZoneProviderEvent event = timeZoneProviderEvent(timeZone, + ARBITRARY_TIME_ZONE_PROVIDER_STATUS); TimeZoneProviderStatus expectedProviderStatus = new TimeZoneProviderStatus.Builder(event.getTimeZoneProviderStatus()) @@ -73,14 +81,31 @@ public class ZoneInfoDbTimeZoneProviderEventPreProcessorTest { } } - private static TimeZoneProviderEvent timeZoneProviderEvent(String... timeZoneIds) { - TimeZoneProviderStatus providerStatus = new TimeZoneProviderStatus.Builder() - .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_OK) - .setConnectivityDependencyStatus(DEPENDENCY_STATUS_OK) - .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_OK) - .build(); + @Test + public void eventWithNullProviderStatus_areMappedToUncertainEvent() { + for (String timeZone : mNonExistingTimeZones) { + TimeZoneProviderEvent eventWithNullStatus = timeZoneProviderEvent(timeZone, + /* providerStatus= */ null); + + TimeZoneProviderStatus expectedProviderStatus = + new TimeZoneProviderStatus.Builder() + .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_FAILED) + .build(); + + TimeZoneProviderEvent expectedResultEvent = + TimeZoneProviderEvent.createUncertainEvent( + eventWithNullStatus.getCreationElapsedMillis(), + expectedProviderStatus); + assertWithMessage(timeZone + " with null time zone provider status") + .that(mPreProcessor.preProcess(eventWithNullStatus)) + .isEqualTo(expectedResultEvent); + } + } + + private static TimeZoneProviderEvent timeZoneProviderEvent(String timeZoneId, + TimeZoneProviderStatus providerStatus) { TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder() - .setTimeZoneIds(Arrays.asList(timeZoneIds)) + .setTimeZoneIds(Arrays.asList(timeZoneId)) .setElapsedRealtimeMillis(ARBITRARY_TIME_MILLIS) .build(); return TimeZoneProviderEvent.createSuggestionEvent( diff --git a/test-mock/Android.bp b/test-mock/Android.bp index e29d321e5105..71f303311047 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -47,14 +47,16 @@ java_sdk_library { compile_dex: true, default_to_stubs: true, dist_group: "android", + + // This module cannot generate stubs from the api signature files as stubs depends on the + // private APIs, which are not visible in the api signature files. + build_from_text_stub: false, } java_library { name: "android.test.mock.ravenwood", + defaults: ["ravenwood-internal-only-visibility-java"], srcs: [":android-test-mock-sources"], - visibility: [ - "//frameworks/base", - ], } android_ravenwood_test { diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java index 3722fefb12ad..c0e90f9232d6 100644 --- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java +++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; @@ -77,6 +78,7 @@ import org.mockito.stubbing.Answer; import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -413,6 +415,311 @@ public class CrashRecoveryTest { verify(rescuePartyObserver, never()).executeBootLoopMitigation(2); } + @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testCrashLoopWithRescuePartyAndRollbackObserver() throws Exception { + PackageWatchdog watchdog = createWatchdog(); + RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); + RollbackPackageHealthObserver rollbackObserver = + setUpRollbackPackageHealthObserver(watchdog); + VersionedPackage versionedPackageA = new VersionedPackage(APP_A, VERSION_CODE); + + when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> { + ApplicationInfo info = new ApplicationInfo(); + info.flags |= ApplicationInfo.FLAG_PERSISTENT + | ApplicationInfo.FLAG_SYSTEM; + return info; + }); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: SCOPED_DEVICE_CONFIG_RESET + verify(rescuePartyObserver).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rollbackObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: ALL_DEVICE_CONFIG_RESET + verify(rescuePartyObserver).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); + verify(rollbackObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: WARM_REBOOT + verify(rescuePartyObserver).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); + verify(rollbackObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: Low impact rollback + verify(rollbackObserver).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); + + // update available rollbacks to mock rollbacks being applied after the call to + // rollbackObserver.execute + when(mRollbackManager.getAvailableRollbacks()).thenReturn( + List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL)); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD reached. No more mitigations applied + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); + verify(rollbackObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + } + + @Test + @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testCrashLoopWithRescuePartyAndRollbackObserverEnableDeprecateFlagReset() + throws Exception { + PackageWatchdog watchdog = createWatchdog(); + RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); + RollbackPackageHealthObserver rollbackObserver = + setUpRollbackPackageHealthObserver(watchdog); + VersionedPackage versionedPackageA = new VersionedPackage(APP_A, VERSION_CODE); + + when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> { + ApplicationInfo info = new ApplicationInfo(); + info.flags |= ApplicationInfo.FLAG_PERSISTENT + | ApplicationInfo.FLAG_SYSTEM; + return info; + }); + + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: WARM_REBOOT + verify(rescuePartyObserver).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rollbackObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: Low impact rollback + verify(rollbackObserver).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + + // update available rollbacks to mock rollbacks being applied after the call to + // rollbackObserver.execute + when(mRollbackManager.getAvailableRollbacks()).thenReturn( + List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL)); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD reached. No more mitigations applied + verify(rescuePartyObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rollbackObserver, never()).execute(versionedPackageA, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + } + + @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testCrashLoopSystemUIWithRescuePartyAndRollbackObserver() throws Exception { + PackageWatchdog watchdog = createWatchdog(); + RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); + RollbackPackageHealthObserver rollbackObserver = + setUpRollbackPackageHealthObserver(watchdog); + String systemUi = "com.android.systemui"; + VersionedPackage versionedPackageUi = new VersionedPackage( + systemUi, VERSION_CODE); + RollbackInfo rollbackInfoUi = getRollbackInfo(systemUi, VERSION_CODE, 1, + PackageManager.ROLLBACK_USER_IMPACT_LOW); + when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_LOW, + ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL, rollbackInfoUi)); + + when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> { + ApplicationInfo info = new ApplicationInfo(); + info.flags |= ApplicationInfo.FLAG_PERSISTENT + | ApplicationInfo.FLAG_SYSTEM; + return info; + }); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: SCOPED_DEVICE_CONFIG_RESET + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: ALL_DEVICE_CONFIG_RESET + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: WARM_REBOOT + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: Low impact rollback + verify(rollbackObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + + // update available rollbacks to mock rollbacks being applied after the call to + // rollbackObserver.execute + when(mRollbackManager.getAvailableRollbacks()).thenReturn( + List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL)); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: RESET_SETTINGS_UNTRUSTED_DEFAULTS + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 5); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: RESET_SETTINGS_UNTRUSTED_CHANGES + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 5); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 6); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: RESET_SETTINGS_TRUSTED_DEFAULTS + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 6); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 7); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: Factory reset. High impact rollbacks are performed only for boot loops. + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 7); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 8); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + } + + @Test + @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) + public void testCrashLoopSystemUIWithRescuePartyAndRollbackObserverEnableDeprecateFlagReset() + throws Exception { + PackageWatchdog watchdog = createWatchdog(); + RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); + RollbackPackageHealthObserver rollbackObserver = + setUpRollbackPackageHealthObserver(watchdog); + String systemUi = "com.android.systemui"; + VersionedPackage versionedPackageUi = new VersionedPackage( + systemUi, VERSION_CODE); + RollbackInfo rollbackInfoUi = getRollbackInfo(systemUi, VERSION_CODE, 1, + PackageManager.ROLLBACK_USER_IMPACT_LOW); + when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_LOW, + ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL, rollbackInfoUi)); + + when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> { + ApplicationInfo info = new ApplicationInfo(); + info.flags |= ApplicationInfo.FLAG_PERSISTENT + | ApplicationInfo.FLAG_SYSTEM; + return info; + }); + + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: WARM_REBOOT + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: Low impact rollback + verify(rollbackObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + + // update available rollbacks to mock rollbacks being applied after the call to + // rollbackObserver.execute + when(mRollbackManager.getAvailableRollbacks()).thenReturn( + List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL)); + + raiseFatalFailureAndDispatch(watchdog, + Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); + + // Mitigation: Factory reset. High impact rollbacks are performed only for boot loops. + verify(rescuePartyObserver).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + verify(rescuePartyObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); + verify(rollbackObserver, never()).execute(versionedPackageUi, + PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); + } + RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) { RollbackPackageHealthObserver rollbackObserver = spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager)); @@ -424,7 +731,6 @@ public class CrashRecoveryTest { watchdog.registerHealthObserver(rollbackObserver); return rollbackObserver; } - RescuePartyObserver setUpRescuePartyObserver(PackageWatchdog watchdog) { setCrashRecoveryPropRescueBootCount(0); RescuePartyObserver rescuePartyObserver = spy(RescuePartyObserver.getInstance(mSpyContext)); @@ -686,4 +992,20 @@ public class CrashRecoveryTest { mTestLooper.moveTimeForward(milliSeconds); mTestLooper.dispatchAll(); } + + private void raiseFatalFailureAndDispatch(PackageWatchdog watchdog, + List<VersionedPackage> packages, int failureReason) { + long triggerFailureCount = watchdog.getTriggerFailureCount(); + if (failureReason == PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK + || failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) { + triggerFailureCount = 1; + } + for (int i = 0; i < triggerFailureCount; i++) { + watchdog.onPackageFailure(packages, failureReason); + } + mTestLooper.dispatchAll(); + if (Flags.recoverabilityDetection()) { + moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS); + } + } } diff --git a/tools/systemfeatures/OWNERS b/tools/systemfeatures/OWNERS new file mode 100644 index 000000000000..66c8506f58be --- /dev/null +++ b/tools/systemfeatures/OWNERS @@ -0,0 +1 @@ +include /PERFORMANCE_OWNERS diff --git a/tools/systemfeatures/README.md b/tools/systemfeatures/README.md new file mode 100644 index 000000000000..5836f81e5fd3 --- /dev/null +++ b/tools/systemfeatures/README.md @@ -0,0 +1,11 @@ +# Build-time system feature support + +## Overview + +System features exposed from `PackageManager` are defined and aggregated as +`<feature>` xml attributes across various partitions, and are currently queried +at runtime through the framework. This directory contains tooling that will +support *build-time* queries of select system features, enabling optimizations +like code stripping and conditionally dependencies when so configured. + +### TODO(b/203143243): Expand readme after landing codegen. |