diff options
76 files changed, 2254 insertions, 1039 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  # ****************************************************************** @@ -28,7 +28,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/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/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..2643bae4060f 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; @@ -104,19 +107,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; 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..4f285ff4eb94 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; @@ -94,15 +97,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 +131,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 +156,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. 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/api/Android.bp b/api/Android.bp index d4ba964046ee..4b26eb48f5de 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 { diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp index 12820f9ff277..8dfddf0e13c8 100644 --- a/api/StubLibraries.bp +++ b/api/StubLibraries.bp @@ -1345,4 +1345,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..b6b1a7e44510 100644 --- a/api/api.go +++ b/api/api.go @@ -54,16 +54,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 +73,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) { @@ -532,8 +538,8 @@ func createFullExportableApiLibraries(ctx android.LoadHookContext) {  }  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) @@ -568,7 +574,6 @@ 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 +610,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..47d167093b39 --- /dev/null +++ b/api/api_test.go @@ -0,0 +1,254 @@ +// 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.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/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/ServiceManager.java b/core/java/android/os/ServiceManager.java index 0be2d3e30c33..e95c6a44c281 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().getService(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..6c9a5c7f9fff 100644 --- a/core/java/android/os/ServiceManagerNative.java +++ b/core/java/android/os/ServiceManagerNative.java @@ -58,12 +58,12 @@ class ServiceManagerProxy implements IServiceManager {      }      @UnsupportedAppUsage -    public IBinder getService(String name) throws RemoteException { +    public Service getService(String name) throws RemoteException {          // Same as checkService (old versions of servicemanager had both methods). -        return mServiceManager.checkService(name); +        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/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/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/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/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS index 7ad68aac62c5..b01b2b7ad520 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,6 @@  atsjenk@google.com  jorgegil@google.com  madym@google.com -nmusgrave@google.com  pbdr@google.com  tkachenkoi@google.com  vaniadesmonda@google.com 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/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/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java index fe78c9b23353..395f81d73351 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       */ @@ -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); +      }      /** @@ -1081,22 +1082,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 +1093,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 +1103,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 +1121,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 +1146,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); +      }      /** @@ -1223,12 +1174,7 @@ public final class NfcAdapter {       */      @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 +1185,17 @@ 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 CardEmulation#setPreferredService(Activity, 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 +1205,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);      }      /** @@ -1862,14 +1807,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 +1826,25 @@ 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(); +            try { +                NfcAdapter.sService.updateDiscoveryTechnology(token, +                        pollTechnology, listenTechnology); +            } catch (RemoteException e) { +                attemptDeadServiceRecovery(e); +            } +        } else { +            mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology); +        }      }      /** @@ -2021,22 +1976,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 +1993,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 +2012,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 +2031,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 +2048,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 +2063,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 +2080,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 +2209,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);      }      /** @@ -2473,22 +2328,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 +2375,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 +2392,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 +2412,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 +2483,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);      } @@ -2772,22 +2560,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,12 +2574,30 @@ 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)); +    } + +    interface ServiceCall { +        void call() throws RemoteException; +    } + +    void callService(ServiceCall call) {          try {              if (sService == null) {                  attemptDeadServiceRecovery(null);              } -            sService.notifyPollingLoop(frame); +            call.call();          } catch (RemoteException e) {              attemptDeadServiceRecovery(e);              // Try one more time @@ -2814,39 +2606,46 @@ public final class NfcAdapter {                  return;              }              try { -                sService.notifyPollingLoop(frame); +                call.call();              } catch (RemoteException ee) {                  Log.e(TAG, "Failed to recover NFC Service.");              }          }      } - -   /** -     * Notifies the system of a an HCE session being deactivated. -     *     * -     * @hide -     */ -    @TestApi -    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) -    public void notifyHceDeactivated() { +    interface ServiceCallReturn<T> { +        T call() throws RemoteException; +    } +    <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) {          try {              if (sService == null) {                  attemptDeadServiceRecovery(null);              } -            sService.notifyHceDeactivated(); +            return call.call();          } catch (RemoteException e) {              attemptDeadServiceRecovery(e);              // Try one more time              if (sService == null) {                  Log.e(TAG, "Failed to recover NFC Service."); -                return; +                return defaultReturn;              }              try { -                sService.notifyHceDeactivated(); +                return call.call();              } catch (RemoteException ee) {                  Log.e(TAG, "Failed to recover NFC Service.");              }          } +        return defaultReturn; +    } + +   /** +     * Notifies the system of a an HCE session being deactivated. +     *     * +     * @hide +     */ +    @TestApi +    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) +    public void notifyHceDeactivated() { +        callService(() ->  sService.notifyHceDeactivated());      }      /** @@ -2862,22 +2661,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 +2676,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 +2756,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..f6138a63fae4 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -141,6 +141,34 @@ public final class NfcOemExtension {          }      } +    /** +     * 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() { +        try { +            NfcAdapter.sService.setScreenState(); +        } catch (RemoteException e) { +            mAdapter.attemptDeadServiceRecovery(e); +        } +    } + +    /** +     * 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() { +        try { +            NfcAdapter.sService.checkFirmware(); +        } catch (RemoteException e) { +            mAdapter.attemptDeadServiceRecovery(e); +        } +    } +      private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {          @Override          public void onTagConnected(boolean connected, Tag tag) throws RemoteException { 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..2fe2ce39813b 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"; @@ -268,12 +272,16 @@ public final class CardEmulation {      }      /** +     * <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 +289,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,6 +321,11 @@ 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       */ @@ -364,9 +383,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 @@ -401,6 +420,128 @@ public final class CardEmulation {      }      /** +     * 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) { +        pollingLoopFilter = validatePollingLoopFilter(pollingLoopFilter); + +        try { +            return sService.removePollingLoopFilterForService(mContext.getUser().getIdentifier(), +                    service, pollingLoopFilter); +        } catch (RemoteException e) { +            // Try one more time +            recoverService(); +            if (sService == null) { +                Log.e(TAG, "Failed to recover CardEmulationService."); +                return false; +            } +            try { +                return sService.removePollingLoopFilterForService( +                        mContext.getUser().getIdentifier(), service, +                        pollingLoopFilter); +            } catch (RemoteException ee) { +                Log.e(TAG, "Failed to reach CardEmulationService."); +                return 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) { +        pollingLoopPatternFilter = validatePollingLoopPatternFilter(pollingLoopPatternFilter); + +        try { +            return sService.registerPollingLoopPatternFilterForService( +                    mContext.getUser().getIdentifier(), +                    service, pollingLoopPatternFilter, autoTransact); +        } catch (RemoteException e) { +            // Try one more time +            recoverService(); +            if (sService == null) { +                Log.e(TAG, "Failed to recover CardEmulationService."); +                return false; +            } +            try { +                return sService.registerPollingLoopPatternFilterForService( +                        mContext.getUser().getIdentifier(), service, +                        pollingLoopPatternFilter, autoTransact); +            } catch (RemoteException ee) { +                Log.e(TAG, "Failed to reach CardEmulationService."); +                return 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) { +        pollingLoopPatternFilter = validatePollingLoopPatternFilter(pollingLoopPatternFilter); + +        try { +            return sService.removePollingLoopPatternFilterForService( +                    mContext.getUser().getIdentifier(), service, pollingLoopPatternFilter); +        } catch (RemoteException e) { +            // Try one more time +            recoverService(); +            if (sService == null) { +                Log.e(TAG, "Failed to recover CardEmulationService."); +                return false; +            } +            try { +                return sService.removePollingLoopPatternFilterForService( +                        mContext.getUser().getIdentifier(), service, +                        pollingLoopPatternFilter); +            } catch (RemoteException ee) { +                Log.e(TAG, "Failed to reach CardEmulationService."); +                return false; +            } +        } +    } + +    /**       * Registers a list of AIDs for a specific category for the       * specified service.       * @@ -780,6 +921,13 @@ public final class CardEmulation {      /**       * 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. @@ -835,6 +983,13 @@ public final class CardEmulation {      /**       * 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) @@ -998,6 +1153,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) 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/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/ravenwood/Android.bp b/ravenwood/Android.bp index 178102e2876d..33d3624d4522 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,77 @@ 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", + +        // 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/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/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/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 46061a56631c..54490899ab5f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -577,6 +577,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/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/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..365c9b51a395 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -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)) { 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/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/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java index 67ae9984266f..01c4d1fa6b5c 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -1878,4 +1878,33 @@ 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); +    }  } diff --git a/telephony/OWNERS b/telephony/OWNERS index 7607c64150d8..92af034217a9 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -15,4 +15,4 @@ per-file CarrierConfigManager.java=set noparent  per-file CarrierConfigManager.java=amruthr@google.com,tgunn@google.com,rgreenwalt@google.com,satk@google.com  #Domain Selection is jointly owned, add additional owners for domain selection specific files -per-file TransportSelectorCallback.java,WwanSelectorCallback.java,DomainSelectionService.java,DomainSelectionService.aidl,DomainSelector.java,EmergencyRegResult.java,EmergencyRegResult.aidl,IDomainSelectionServiceController.aidl,IDomainSelector.aidl,ITransportSelectorCallback.aidl,ITransportSelectorResultCallback.aidl,IWwanSelectorCallback.aidl,IWwanSelectorResultCallback.aidl=hwangoo@google.com,forestchoi@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,radhikaagrawal@google.com,jdyou@google.com +per-file TransportSelectorCallback.java,WwanSelectorCallback.java,DomainSelectionService.java,DomainSelectionService.aidl,DomainSelector.java,EmergencyRegResult.java,EmergencyRegResult.aidl,IDomainSelectionServiceController.aidl,IDomainSelector.aidl,ITransportSelectorCallback.aidl,ITransportSelectorResultCallback.aidl,IWwanSelectorCallback.aidl,IWwanSelectorResultCallback.aidl=hwangoo@google.com,jaesikkong@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,radhikaagrawal@google.com,jdyou@google.com diff --git a/test-mock/Android.bp b/test-mock/Android.bp index e29d321e5105..59766579eee2 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -51,10 +51,8 @@ java_sdk_library {  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); +        } +    }  }  |