Merge "Ravenwood: sdk to test_current" into main
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index e092499..65bc8cc 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/Android.bp
@@ -44,6 +44,7 @@
"apct-perftests-resources-manager-apps",
"apct-perftests-utils",
"collector-device-lib",
+ "conscrypt-test-support",
"compatibility-device-util-axt",
"junit",
"junit-params",
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/BufferType.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/BufferType.java
new file mode 100644
index 0000000..bdc2a82
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/BufferType.java
@@ -0,0 +1,48 @@
+/*
+ * 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 java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Enumeration that provides allocation of direct or heap buffers.
+ */
+@SuppressWarnings("unused")
+public enum BufferType {
+ HEAP {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocate(size);
+ }
+ },
+ DIRECT {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocateDirect(size);
+ }
+ };
+
+ abstract ByteBuffer newBuffer(int size);
+
+ ByteBuffer newApplicationBuffer(SSLEngine engine) {
+ return newBuffer(engine.getSession().getApplicationBufferSize());
+ }
+
+ ByteBuffer newPacketBuffer(SSLEngine engine) {
+ return newBuffer(engine.getSession().getPacketBufferSize());
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java
new file mode 100644
index 0000000..c69ae39
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016 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 android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import androidx.test.filters.LargeTest;
+
+import org.conscrypt.TestUtils;
+
+import java.nio.ByteBuffer;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Benchmark for comparing cipher encrypt performance.
+ */
+@RunWith(JUnitParamsRunner.class)
+@LargeTest
+public final class CipherEncryptPerfTest {
+
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public enum BufferType {
+ ARRAY,
+ HEAP_HEAP,
+ HEAP_DIRECT,
+ DIRECT_DIRECT,
+ DIRECT_HEAP
+ }
+
+ private enum MyCipherFactory implements CipherFactory {
+ JDK {
+ @Override
+ public Cipher newCipher(String transformation)
+ throws NoSuchPaddingException, NoSuchAlgorithmException {
+ return Cipher.getInstance(transformation);
+ }
+ },
+ CONSCRYPT {
+ @Override
+ public Cipher newCipher(String transformation)
+ throws NoSuchPaddingException, NoSuchAlgorithmException {
+ return Cipher.getInstance(transformation, TestUtils.getConscryptProvider());
+ }
+ };
+ }
+
+ private class Config {
+ BufferType b_bufferType;
+ CipherFactory c_provider;
+ Transformation a_tx;
+ Config(BufferType bufferType, CipherFactory cipherFactory, Transformation transformation) {
+ b_bufferType = bufferType;
+ c_provider = cipherFactory;
+ a_tx = transformation;
+ }
+ public BufferType bufferType() {
+ return b_bufferType;
+ }
+
+ public CipherFactory cipherFactory() {
+ return c_provider;
+ }
+
+ public Transformation transformation() {
+ return a_tx;
+ }
+ }
+
+ 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)},
+ };
+ }
+
+ private EncryptStrategy encryptStrategy;
+
+ @Test
+ @Parameters(method = "getParams")
+ public void encrypt(Config config) throws Exception {
+ switch (config.bufferType()) {
+ case ARRAY:
+ encryptStrategy = new ArrayStrategy(config);
+ break;
+ default:
+ encryptStrategy = new ByteBufferStrategy(config);
+ break;
+ }
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ encryptStrategy.encrypt();
+ }
+ }
+
+ private static abstract class EncryptStrategy {
+ private final Key key;
+ final Cipher cipher;
+ final int outputSize;
+
+ EncryptStrategy(Config config) throws Exception {
+ Transformation tx = config.transformation();
+ key = tx.newEncryptKey();
+ cipher = config.cipherFactory().newCipher(tx.toFormattedString());
+ initCipher();
+
+ int messageSize = messageSize(tx.toFormattedString());
+ outputSize = cipher.getOutputSize(messageSize);
+ }
+
+ final void initCipher() throws Exception {
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ }
+
+ final int messageSize(String transformation) throws Exception {
+ Cipher conscryptCipher = Cipher.getInstance(
+ transformation, TestUtils.getConscryptProvider());
+ conscryptCipher.init(Cipher.ENCRYPT_MODE, key);
+ return conscryptCipher.getBlockSize() > 0 ?
+ conscryptCipher.getBlockSize() : 128;
+ }
+
+ final byte[] newMessage() {
+ return TestUtils.newTextMessage(cipher.getBlockSize());
+ }
+
+ abstract int encrypt() throws Exception;
+ }
+
+ private static final class ArrayStrategy extends EncryptStrategy {
+ private final byte[] plainBytes;
+ private final byte[] cipherBytes;
+
+ ArrayStrategy(Config config) throws Exception {
+ super(config);
+
+ plainBytes = newMessage();
+ cipherBytes = new byte[outputSize];
+ }
+
+ @Override
+ int encrypt() throws Exception {
+ initCipher();
+ return cipher.doFinal(plainBytes, 0, plainBytes.length, cipherBytes, 0);
+ }
+ }
+
+ private static final class ByteBufferStrategy extends EncryptStrategy {
+ private final ByteBuffer input;
+ private final ByteBuffer output;
+
+ ByteBufferStrategy(Config config) throws Exception {
+ super(config);
+
+ switch (config.bufferType()) {
+ case HEAP_HEAP:
+ input = ByteBuffer.wrap(newMessage());
+ output = ByteBuffer.allocate(outputSize);
+ break;
+ case HEAP_DIRECT:
+ input = ByteBuffer.wrap(newMessage());
+ output = ByteBuffer.allocateDirect(outputSize);
+ break;
+ case DIRECT_DIRECT:
+ input = toDirect(newMessage());
+ output = ByteBuffer.allocateDirect(outputSize);
+ break;
+ case DIRECT_HEAP:
+ input = toDirect(newMessage());
+ output = ByteBuffer.allocate(outputSize);
+ break;
+ default: {
+ throw new IllegalStateException(
+ "Unexpected buffertype: " + config.bufferType());
+ }
+ }
+ }
+
+ @Override
+ int encrypt() throws Exception {
+ initCipher();
+ input.position(0);
+ output.clear();
+ return cipher.doFinal(input, output);
+ }
+
+ private static ByteBuffer toDirect(byte[] data) {
+ ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
+ buffer.put(data);
+ buffer.flip();
+ return buffer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherFactory.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherFactory.java
new file mode 100644
index 0000000..f8a3d5f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherFactory.java
@@ -0,0 +1,27 @@
+/*
+ * 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 java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * Factory for {@link Cipher} instances.
+ */
+public interface CipherFactory {
+ Cipher newCipher(String transformation) throws NoSuchPaddingException, NoSuchAlgorithmException;
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientEndpoint.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientEndpoint.java
new file mode 100644
index 0000000..1a7258a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientEndpoint.java
@@ -0,0 +1,110 @@
+/*
+ * 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 java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.nio.channels.ClosedChannelException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.conscrypt.ChannelType;
+
+/**
+ * Client-side endpoint. Provides basic services for sending/receiving messages from the client
+ * socket.
+ */
+final class ClientEndpoint {
+ private final SSLSocket socket;
+ private InputStream input;
+ private OutputStream output;
+
+ ClientEndpoint(SSLSocketFactory socketFactory, ChannelType channelType, int port,
+ String[] protocols, String[] ciphers) throws IOException {
+ socket = channelType.newClientSocket(socketFactory, InetAddress.getLoopbackAddress(), port);
+ socket.setEnabledProtocols(protocols);
+ socket.setEnabledCipherSuites(ciphers);
+ }
+
+ void start() {
+ try {
+ socket.startHandshake();
+ input = socket.getInputStream();
+ output = socket.getOutputStream();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+
+ void stop() {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ int readMessage(byte[] buffer) {
+ try {
+ int totalBytesRead = 0;
+ while (totalBytesRead < buffer.length) {
+ int remaining = buffer.length - totalBytesRead;
+ int bytesRead = input.read(buffer, totalBytesRead, remaining);
+ if (bytesRead == -1) {
+ break;
+ }
+ totalBytesRead += bytesRead;
+ }
+ return totalBytesRead;
+ } catch (SSLException e) {
+ if (e.getCause() instanceof EOFException) {
+ return -1;
+ }
+ throw new RuntimeException(e);
+ } catch (ClosedChannelException e) {
+ // Thrown for channel-based sockets. Just treat like EOF.
+ return -1;
+ } catch (SocketException e) {
+ // The socket was broken. Just treat like EOF.
+ return -1;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void sendMessage(byte[] data) {
+ try {
+ output.write(data);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void flush() {
+ try {
+ output.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java
new file mode 100644
index 0000000..dd9f4eb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 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.ChannelType;
+import org.conscrypt.TestUtils;
+import static org.conscrypt.TestUtils.getCommonProtocolSuites;
+import static org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertEquals;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import androidx.test.filters.LargeTest;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketException;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import android.conscrypt.ServerEndpoint.MessageProcessor;
+
+/**
+ * Benchmark for comparing performance of server socket implementations.
+ */
+@RunWith(JUnitParamsRunner.class)
+@LargeTest
+public final class ClientSocketPerfTest {
+
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Provider for the test configuration
+ */
+ private class Config {
+ EndpointFactory a_clientFactory;
+ EndpointFactory b_serverFactory;
+ int c_messageSize;
+ String d_cipher;
+ ChannelType e_channelType;
+ PerfTestProtocol f_protocol;
+ Config(EndpointFactory clientFactory,
+ EndpointFactory serverFactory,
+ int messageSize,
+ String cipher,
+ ChannelType channelType,
+ PerfTestProtocol protocol) {
+ a_clientFactory = clientFactory;
+ b_serverFactory = serverFactory;
+ c_messageSize = messageSize;
+ d_cipher = cipher;
+ e_channelType = channelType;
+ f_protocol = protocol;
+ }
+ public EndpointFactory clientFactory() {
+ return a_clientFactory;
+ }
+
+ public EndpointFactory serverFactory() {
+ return b_serverFactory;
+ }
+
+ public int messageSize() {
+ return c_messageSize;
+ }
+
+ public String cipher() {
+ return d_cipher;
+ }
+
+ public ChannelType channelType() {
+ return e_channelType;
+ }
+
+ public PerfTestProtocol protocol() {
+ return f_protocol;
+ }
+ }
+
+ private Object[] getParams() {
+ return new Object[][] {
+ new Object[] {new Config(
+ EndpointFactory.CONSCRYPT,
+ EndpointFactory.CONSCRYPT,
+ 64,
+ "AES128-GCM",
+ ChannelType.CHANNEL,
+ PerfTestProtocol.TLSv13)},
+ };
+ }
+
+
+ private ClientEndpoint client;
+ private ServerEndpoint server;
+ private byte[] message;
+ private ExecutorService executor;
+ private Future<?> sendingFuture;
+ private volatile boolean stopping;
+
+ private static final AtomicLong bytesCounter = new AtomicLong();
+ private AtomicBoolean recording = new AtomicBoolean();
+
+ private void setup(Config config) throws Exception {
+ message = newTextMessage(512);
+
+ // Always use the same server for consistency across the benchmarks.
+ server = config.serverFactory().newServer(
+ ChannelType.CHANNEL, config.messageSize(), config.protocol().getProtocols(),
+ ciphers(config));
+
+ server.setMessageProcessor(new ServerEndpoint.MessageProcessor() {
+ @Override
+ public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
+ if (recording.get()) {
+ // Server received a message, increment the count.
+ bytesCounter.addAndGet(numBytes);
+ }
+ }
+ });
+ Future<?> connectedFuture = server.start();
+
+ client = config.clientFactory().newClient(
+ config.channelType(), server.port(), config.protocol().getProtocols(), ciphers(config));
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+
+ executor = Executors.newSingleThreadExecutor();
+ sendingFuture = executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread thread = Thread.currentThread();
+ while (!stopping && !thread.isInterrupted()) {
+ client.sendMessage(message);
+ }
+ } finally {
+ client.flush();
+ }
+ }
+ });
+ }
+
+ void close() throws Exception {
+ stopping = true;
+
+ // Wait for the sending thread to stop.
+ sendingFuture.get(5, TimeUnit.SECONDS);
+
+ client.stop();
+ server.stop();
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Simple benchmark for the amount of time to send a given number of messages
+ */
+ @Test
+ @Parameters(method = "getParams")
+ public void time(Config config) throws Exception {
+ reset();
+ setup(config);
+ recording.set(true);
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ while (bytesCounter.get() < config.messageSize()) {
+ }
+ bytesCounter.set(0);
+ }
+ recording.set(false);
+ close();
+ }
+
+ void reset() {
+ stopping = false;
+ bytesCounter.set(0);
+ }
+
+ private String[] ciphers(Config config) {
+ return new String[] {config.cipher()};
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EndpointFactory.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EndpointFactory.java
new file mode 100644
index 0000000..0655f45
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EndpointFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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.ChannelType;
+import org.conscrypt.TestUtils;
+import java.io.IOException;
+import java.security.Provider;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Utility for creating test client and server instances.
+ */
+public enum EndpointFactory {
+ CONSCRYPT(newConscryptFactories(false)),
+ CONSCRYPT_ENGINE(newConscryptFactories(true));
+
+ private final Factories factories;
+
+ EndpointFactory(Factories factories) {
+ this.factories = factories;
+ }
+
+ public ClientEndpoint newClient(ChannelType channelType, int port, String[] protocols,
+ String[] ciphers) throws IOException {
+ return new ClientEndpoint(
+ factories.clientFactory, channelType, port, protocols, ciphers);
+ }
+
+ public ServerEndpoint newServer(ChannelType channelType, int messageSize,
+ String[] protocols, String[] ciphers) throws IOException {
+ return new ServerEndpoint(factories.serverFactory, factories.serverSocketFactory,
+ channelType, messageSize, protocols, ciphers);
+ }
+
+ private static final class Factories {
+ final SSLSocketFactory clientFactory;
+ final SSLSocketFactory serverFactory;
+ final SSLServerSocketFactory serverSocketFactory;
+
+ private Factories(SSLSocketFactory clientFactory, SSLSocketFactory serverFactory,
+ SSLServerSocketFactory serverSocketFactory) {
+ this.clientFactory = clientFactory;
+ this.serverFactory = serverFactory;
+ this.serverSocketFactory = serverSocketFactory;
+ }
+ }
+
+ private static Factories newConscryptFactories(boolean useEngineSocket) {
+ Provider provider = TestUtils.getConscryptProvider();
+ SSLContext clientContext = TestUtils.newClientSslContext(provider);
+ SSLContext serverContext = TestUtils.newServerSslContext(provider);
+ final SSLSocketFactory clientFactory = clientContext.getSocketFactory();
+ final SSLSocketFactory serverFactory = serverContext.getSocketFactory();
+ final SSLServerSocketFactory serverSocketFactory = serverContext.getServerSocketFactory();
+ TestUtils.setUseEngineSocket(clientFactory, useEngineSocket);
+ TestUtils.setUseEngineSocket(serverFactory, useEngineSocket);
+ TestUtils.setUseEngineSocket(serverSocketFactory, useEngineSocket);
+ return new Factories(clientFactory, serverFactory, serverSocketFactory);
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/OWNERS b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/OWNERS
new file mode 100644
index 0000000..7efabfd
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 24949
+include platform/libcore:/OWNERS
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/PerfTestProtocol.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/PerfTestProtocol.java
new file mode 100644
index 0000000..4defe71
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/PerfTestProtocol.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+public enum PerfTestProtocol {
+
+ TLSv13("TLSv1.3"),
+ TLSv12("TLSv1.2");
+
+ private final String[] protocols;
+
+ PerfTestProtocol(String... protocols) {
+ this.protocols = protocols;
+ }
+
+ public String[] getProtocols() {
+ return protocols.clone();
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerEndpoint.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerEndpoint.java
new file mode 100644
index 0000000..3631c3f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerEndpoint.java
@@ -0,0 +1,199 @@
+/*
+ * 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 java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.SocketException;
+import java.nio.channels.ClosedChannelException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.conscrypt.ChannelType;
+
+/**
+ * A simple socket-based test server.
+ */
+final class ServerEndpoint {
+ /**
+ * A processor for receipt of a single message.
+ */
+ public interface MessageProcessor {
+ void processMessage(byte[] message, int numBytes, OutputStream os);
+ }
+
+ /**
+ * A {@link MessageProcessor} that simply echos back the received message to the client.
+ */
+ public static final class EchoProcessor implements MessageProcessor {
+ @Override
+ public void processMessage(byte[] message, int numBytes, OutputStream os) {
+ try {
+ os.write(message, 0, numBytes);
+ os.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final ServerSocket serverSocket;
+ private final ChannelType channelType;
+ private final SSLSocketFactory socketFactory;
+ private final int messageSize;
+ private final String[] protocols;
+ private final String[] cipherSuites;
+ private final byte[] buffer;
+ private SSLSocket socket;
+ private ExecutorService executor;
+ private InputStream inputStream;
+ private OutputStream outputStream;
+ private volatile boolean stopping;
+ private volatile MessageProcessor messageProcessor = new EchoProcessor();
+ private volatile Future<?> processFuture;
+
+ ServerEndpoint(SSLSocketFactory socketFactory, SSLServerSocketFactory serverSocketFactory,
+ ChannelType channelType, int messageSize, String[] protocols,
+ String[] cipherSuites) throws IOException {
+ this.serverSocket = channelType.newServerSocket(serverSocketFactory);
+ this.socketFactory = socketFactory;
+ this.channelType = channelType;
+ this.messageSize = messageSize;
+ this.protocols = protocols;
+ this.cipherSuites = cipherSuites;
+ buffer = new byte[messageSize];
+ }
+
+ void setMessageProcessor(MessageProcessor messageProcessor) {
+ this.messageProcessor = messageProcessor;
+ }
+
+ Future<?> start() throws IOException {
+ executor = Executors.newSingleThreadExecutor();
+ return executor.submit(new AcceptTask());
+ }
+
+ void stop() {
+ try {
+ stopping = true;
+
+ if (socket != null) {
+ socket.close();
+ socket = null;
+ }
+
+ if (processFuture != null) {
+ processFuture.get(5, TimeUnit.SECONDS);
+ }
+
+ serverSocket.close();
+
+ if (executor != null) {
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ executor = null;
+ }
+ } catch (IOException | InterruptedException | ExecutionException | TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int port() {
+ return serverSocket.getLocalPort();
+ }
+
+ private final class AcceptTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ if (stopping) {
+ return;
+ }
+ socket = channelType.accept(serverSocket, socketFactory);
+ socket.setEnabledProtocols(protocols);
+ socket.setEnabledCipherSuites(cipherSuites);
+
+ socket.startHandshake();
+
+ inputStream = socket.getInputStream();
+ outputStream = socket.getOutputStream();
+
+ if (stopping) {
+ return;
+ }
+ processFuture = executor.submit(new ProcessTask());
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final class ProcessTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ Thread thread = Thread.currentThread();
+ while (!stopping && !thread.isInterrupted()) {
+ int bytesRead = readMessage();
+ if (!stopping && !thread.isInterrupted()) {
+ messageProcessor.processMessage(buffer, bytesRead, outputStream);
+ }
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private int readMessage() throws IOException {
+ int totalBytesRead = 0;
+ while (!stopping && totalBytesRead < messageSize) {
+ try {
+ int remaining = messageSize - totalBytesRead;
+ int bytesRead = inputStream.read(buffer, totalBytesRead, remaining);
+ if (bytesRead == -1) {
+ break;
+ }
+ totalBytesRead += bytesRead;
+ } catch (SSLException e) {
+ if (e.getCause() instanceof EOFException) {
+ break;
+ }
+ throw e;
+ } catch (ClosedChannelException e) {
+ // Thrown for channel-based sockets. Just treat like EOF.
+ break;
+ } catch (SocketException e) {
+ // The socket was broken. Just treat like EOF.
+ break;
+ }
+ }
+ return totalBytesRead;
+ }
+ }
+}
\ 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
new file mode 100644
index 0000000..ba2a65a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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.ChannelType;
+import static org.conscrypt.TestUtils.getCommonProtocolSuites;
+import static org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import android.conscrypt.ServerEndpoint.MessageProcessor;
+
+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 for comparing performance of server socket implementations.
+ */
+@RunWith(JUnitParamsRunner.class)
+@LargeTest
+public final class ServerSocketPerfTest {
+
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Provider for the benchmark configuration
+ */
+ private class Config {
+ EndpointFactory a_clientFactory;
+ EndpointFactory b_serverFactory;
+ int c_messageSize;
+ String d_cipher;
+ ChannelType e_channelType;
+ Config(EndpointFactory clientFactory,
+ EndpointFactory serverFactory,
+ int messageSize,
+ String cipher,
+ ChannelType channelType) {
+ a_clientFactory = clientFactory;
+ b_serverFactory = serverFactory;
+ c_messageSize = messageSize;
+ d_cipher = cipher;
+ e_channelType = channelType;
+ }
+ public EndpointFactory clientFactory() {
+ return a_clientFactory;
+ }
+
+ public EndpointFactory serverFactory() {
+ return b_serverFactory;
+ }
+
+ public int messageSize() {
+ return c_messageSize;
+ }
+
+ public String cipher() {
+ return d_cipher;
+ }
+
+ public ChannelType channelType() {
+ return e_channelType;
+ }
+ }
+
+ private Object[] getParams() {
+ return new Object[][] {
+ new Object[] {new Config(
+ EndpointFactory.CONSCRYPT,
+ EndpointFactory.CONSCRYPT,
+ 64,
+ "AES128-GCM",
+ ChannelType.CHANNEL)},
+ };
+ }
+
+ private ClientEndpoint client;
+ private ServerEndpoint server;
+ private ExecutorService executor;
+ private Future<?> receivingFuture;
+ private volatile boolean stopping;
+ private static final AtomicLong bytesCounter = new AtomicLong();
+ private AtomicBoolean recording = new AtomicBoolean();
+
+ private void setup(final Config config) throws Exception {
+ recording.set(false);
+
+ byte[] message = newTextMessage(config.messageSize());
+
+ final ChannelType channelType = config.channelType();
+
+ server = config.serverFactory().newServer(
+ channelType, config.messageSize(), getCommonProtocolSuites(), ciphers(config));
+ server.setMessageProcessor(new MessageProcessor() {
+ @Override
+ public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
+ try {
+ try {
+ while (!stopping) {
+ os.write(inMessage, 0, numBytes);
+ }
+ } finally {
+ os.flush();
+ }
+ } catch (SocketException e) {
+ // Just ignore.
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ Future<?> connectedFuture = server.start();
+
+ // Always use the same client for consistency across the benchmarks.
+ client = config.clientFactory().newClient(
+ ChannelType.CHANNEL, server.port(), getCommonProtocolSuites(), ciphers(config));
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+
+ // Start the server-side streaming by sending a message to the server.
+ client.sendMessage(message);
+ client.flush();
+
+ executor = Executors.newSingleThreadExecutor();
+ receivingFuture = executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ Thread thread = Thread.currentThread();
+ byte[] buffer = new byte[config.messageSize()];
+ while (!stopping && !thread.isInterrupted()) {
+ int numBytes = client.readMessage(buffer);
+ if (numBytes < 0) {
+ return;
+ }
+ assertEquals(config.messageSize(), numBytes);
+
+ // Increment the message counter if we're recording.
+ if (recording.get()) {
+ bytesCounter.addAndGet(numBytes);
+ }
+ }
+ }
+ });
+ }
+
+ void close() throws Exception {
+ stopping = true;
+ // Stop and wait for sending to complete.
+ server.stop();
+ client.stop();
+ executor.shutdown();
+ receivingFuture.get(5, TimeUnit.SECONDS);
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ @Test
+ @Parameters(method = "getParams")
+ public void throughput(Config config) throws Exception {
+ setup(config);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ recording.set(true);
+ while (bytesCounter.get() < config.messageSize()) {
+ }
+ bytesCounter.set(0);
+ recording.set(false);
+ }
+ close();
+ }
+
+ private String[] ciphers(Config config) {
+ return new String[] {config.cipher()};
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java
new file mode 100644
index 0000000..78fe732
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java
@@ -0,0 +1,88 @@
+/*
+ * 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 java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.KeyGenerator;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * Supported cipher transformations.
+ */
+@SuppressWarnings({"ImmutableEnumChecker", "unused"})
+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) {
+ this.algorithm = algorithm;
+ this.mode = mode;
+ this.padding = padding;
+ this.keyGen = keyGen;
+ }
+
+ final String algorithm;
+ final String mode;
+ final String padding;
+ final KeyGen keyGen;
+
+ String toFormattedString() {
+ return algorithm + "/" + mode + "/" + padding;
+ }
+
+ Key newEncryptKey() {
+ return keyGen.newEncryptKey();
+ }
+
+ private interface KeyGen { Key newEncryptKey(); }
+
+ private static final class RsaKeyGen implements KeyGen {
+ @Override
+ public Key newEncryptKey() {
+ try {
+ // Use Bouncy castle
+ KeyPairGenerator generator =
+ KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
+ generator.initialize(2048);
+ KeyPair pair = generator.generateKeyPair();
+ return pair.getPublic();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static final class AesKeyGen implements KeyGen {
+ @Override
+ public Key newEncryptKey() {
+ try {
+ // Just use the JDK's provider.
+ KeyGenerator keyGen = KeyGenerator.getInstance("AES");
+ keyGen.init(256);
+ return keyGen.generateKey();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/api/Android.bp b/api/Android.bp
index fd2a6d2..bf4e6a1 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -157,6 +157,7 @@
genrule {
name: "frameworks-base-api-system-current-compat",
srcs: [
+ ":android.api.public.latest",
":android.api.system.latest",
":android-incompatibilities.api.system.latest",
":frameworks-base-api-current.txt",
@@ -165,33 +166,35 @@
out: ["updated-baseline.txt"],
tools: ["metalava"],
cmd: metalava_cmd +
+ "--check-compatibility:api:released $(location :android.api.public.latest) " +
"--check-compatibility:api:released $(location :android.api.system.latest) " +
- "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " +
"--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+ "$(location :frameworks-base-api-current.txt) " +
"$(location :frameworks-base-api-system-current.txt)",
}
genrule {
name: "frameworks-base-api-module-lib-current-compat",
srcs: [
+ ":android.api.public.latest",
+ ":android.api.system.latest",
":android.api.module-lib.latest",
":android-incompatibilities.api.module-lib.latest",
":frameworks-base-api-current.txt",
+ ":frameworks-base-api-system-current.txt",
":frameworks-base-api-module-lib-current.txt",
],
out: ["updated-baseline.txt"],
tools: ["metalava"],
cmd: metalava_cmd +
+ "--check-compatibility:api:released $(location :android.api.public.latest) " +
+ "--check-compatibility:api:released $(location :android.api.system.latest) " +
"--check-compatibility:api:released $(location :android.api.module-lib.latest) " +
- // Note: having "public" be the base of module-lib is not perfect -- it should
- // ideally be a merged public+system (which metalava is not currently able to generate).
- // This "base" will help when migrating from MODULE_LIBS -> public, but not when
- // migrating from MODULE_LIBS -> system (where it needs to instead be listed as
- // an incompatibility).
- "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " +
"--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+ "$(location :frameworks-base-api-current.txt) " +
+ "$(location :frameworks-base-api-system-current.txt) " +
"$(location :frameworks-base-api-module-lib-current.txt)",
}
@@ -370,7 +373,6 @@
high_mem: true, // Lots of sources => high memory use, see b/170701554
installable: false,
annotations_enabled: true,
- previous_api: ":android.api.public.latest",
merge_annotations_dirs: ["metalava-manual"],
defaults_visibility: ["//frameworks/base/api"],
visibility: [
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 5b7e25b..12820f9 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -38,6 +38,9 @@
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
],
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.public.latest",
check_api: {
current: {
api_file: ":non-updatable-current.txt",
@@ -118,6 +121,9 @@
"module-classpath-stubs-defaults",
],
flags: priv_apps,
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.system.latest",
check_api: {
current: {
api_file: ":non-updatable-system-current.txt",
@@ -178,6 +184,9 @@
"module-classpath-stubs-defaults",
],
flags: test + priv_apps_in_stubs,
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.test.latest",
check_api: {
current: {
api_file: ":non-updatable-test-current.txt",
@@ -257,6 +266,9 @@
"module-classpath-stubs-defaults",
],
flags: priv_apps_in_stubs + module_libs,
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.module-lib.latest",
check_api: {
current: {
api_file: ":non-updatable-module-lib-current.txt",
@@ -571,6 +583,9 @@
],
defaults: ["android-non-updatable_everything_from_text_defaults"],
full_api_surface_stub: "android_stubs_current.from-text",
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.public.latest",
}
java_api_library {
@@ -582,6 +597,9 @@
],
defaults: ["android-non-updatable_everything_from_text_defaults"],
full_api_surface_stub: "android_system_stubs_current.from-text",
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.system.latest",
}
java_api_library {
@@ -594,6 +612,9 @@
],
defaults: ["android-non-updatable_everything_from_text_defaults"],
full_api_surface_stub: "android_test_stubs_current.from-text",
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.test.latest",
}
java_api_library {
@@ -606,6 +627,9 @@
],
defaults: ["android-non-updatable_everything_from_text_defaults"],
full_api_surface_stub: "android_module_lib_stubs_current_full.from-text",
+ // Use full Android API not just the non-updatable API as the latter is incomplete
+ // and can result in incorrect behavior.
+ previous_api: ":android.api.combined.module-lib.latest",
}
// This module generates a stub jar that is a union of the test and module lib
@@ -623,6 +647,8 @@
defaults: ["android-non-updatable_everything_from_text_defaults"],
full_api_surface_stub: "android_test_module_lib_stubs_current.from-text",
+ // No need to specify previous_api as this is not used for compiling against.
+
// This module is only used for hiddenapi, and other modules should not
// depend on this module.
visibility: ["//visibility:private"],
@@ -922,7 +948,7 @@
"i18n.module.public.api.stubs.source.system.api.contribution",
"i18n.module.public.api.stubs.source.module_lib.api.contribution",
],
- previous_api: ":android.api.public.latest",
+ previous_api: ":android.api.combined.module-lib.latest",
}
// Java API library definitions per API surface
diff --git a/api/api.go b/api/api.go
index 449fac6..d4db49e 100644
--- a/api/api.go
+++ b/api/api.go
@@ -478,7 +478,7 @@
props.Api_contributions = transformArray(
modules, "", fmt.Sprintf(".stubs.source%s.api.contribution", apiSuffix))
props.Defaults_visibility = []string{"//visibility:public"}
- props.Previous_api = proptools.StringPtr(":android.api.public.latest")
+ props.Previous_api = proptools.StringPtr(":android.api.combined." + sdkKind.String() + ".latest")
ctx.CreateModule(java.DefaultsFactory, &props)
}
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 2866e71..d645938 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3454,6 +3454,8 @@
field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
field public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; // 0xa
field public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; // 0x8
+ field @FlaggedApi("android.view.accessibility.global_action_media_play_pause") public static final int GLOBAL_ACTION_MEDIA_PLAY_PAUSE = 22; // 0x16
+ field @FlaggedApi("android.view.accessibility.global_action_menu") public static final int GLOBAL_ACTION_MENU = 21; // 0x15
field public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; // 0x4
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index d70fa19..81cc674 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -67,6 +67,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.accessibility.Flags;
import android.view.inputmethod.EditorInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -625,6 +626,18 @@
*/
public static final int GLOBAL_ACTION_DPAD_CENTER = 20;
+ /**
+ * Action to trigger menu key event.
+ */
+ @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MENU)
+ public static final int GLOBAL_ACTION_MENU = 21;
+
+ /**
+ * Action to trigger media play/pause key event.
+ */
+ @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MEDIA_PLAY_PAUSE)
+ public static final int GLOBAL_ACTION_MEDIA_PLAY_PAUSE = 22;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c7e5d88..a6eed50 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4419,7 +4419,8 @@
* @see #DISPLAY_HASH_SERVICE
* @see android.view.displayhash.DisplayHashManager
*/
- public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
+ // TODO(b/347269120): Re-add @Nullable
+ public abstract Object getSystemService(@ServiceName @NonNull String name);
/**
* Return the handle to a system-level service by class.
@@ -4463,7 +4464,8 @@
* <b>never</b> throw a {@link RuntimeException} if the name is not supported.
*/
@SuppressWarnings("unchecked")
- public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) {
+ // TODO(b/347269120): Re-add @Nullable
+ public final <T> T getSystemService(@NonNull Class<T> serviceClass) {
// Because subclasses may override getSystemService(String) we cannot
// perform a lookup by class alone. We must first map the class to its
// service name then invoke the string-based method.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e0cf0a5..a475c29 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -932,7 +932,8 @@
}
@Override
- public @Nullable Object getSystemService(String name) {
+ // TODO(b/347269120): Re-add @Nullable
+ public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index d008034..cba4423 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -25,8 +25,6 @@
import dalvik.system.VMRuntime;
-import libcore.io.IoUtils;
-
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -65,7 +63,7 @@
mMemoryRegistration = new MemoryRegistration(mSize);
mCleaner = Cleaner.create(mFileDescriptor,
- new Closer(mFileDescriptor, mMemoryRegistration));
+ new Closer(mFileDescriptor.getInt$(), mMemoryRegistration));
}
/**
@@ -328,20 +326,21 @@
* Cleaner that closes the FD
*/
private static final class Closer implements Runnable {
- private FileDescriptor mFd;
+ private int mFd;
private MemoryRegistration mMemoryReference;
- private Closer(FileDescriptor fd, MemoryRegistration memoryReference) {
+ private Closer(int fd, MemoryRegistration memoryReference) {
mFd = fd;
- IoUtils.setFdOwner(mFd, this);
mMemoryReference = memoryReference;
}
@Override
public void run() {
- IoUtils.closeQuietly(mFd);
- mFd = null;
-
+ try {
+ FileDescriptor fd = new FileDescriptor();
+ fd.setInt$(mFd);
+ Os.close(fd);
+ } catch (ErrnoException e) { /* swallow error */ }
mMemoryReference.release();
mMemoryReference = null;
}
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index 685654a..a62efdf 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -82,6 +82,20 @@
flag {
namespace: "accessibility"
+ name: "global_action_menu"
+ description: "Allow AccessibilityService to perform GLOBAL_ACTION_MENU"
+ bug: "334954140"
+}
+
+flag {
+ namespace: "accessibility"
+ name: "global_action_media_play_pause"
+ description: "Allow AccessibilityService to perform GLOBAL_ACTION_MEDIA_PLAY_PAUSE"
+ bug: "334954140"
+}
+
+flag {
+ namespace: "accessibility"
name: "granular_scrolling"
description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
bug: "302376158"
diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS
index fd73d35..0472b6c4 100644
--- a/core/java/android/window/flags/OWNERS
+++ b/core/java/android/window/flags/OWNERS
@@ -1,3 +1,4 @@
per-file responsible_apis.aconfig = file:/BAL_OWNERS
per-file large_screen_experiences_app_compat.aconfig = file:/LSE_APP_COMPAT_OWNERS
per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS
+per-file lse_desktop_experience.aconfig = file:/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index f67f161..8a230de 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -117,6 +117,7 @@
],
defaults: [
+ "aconfig_lib_cc_shared_link.defaults",
"latest_android_media_audio_common_types_cpp_target_shared",
],
@@ -361,6 +362,7 @@
"libdl_android",
"libtimeinstate",
"server_configurable_flags",
+ "libaconfig_storage_read_api_cc",
"libimage_io",
"libultrahdr",
"libperfetto_c",
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 59066eb..0b9bde8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5937,6 +5937,10 @@
<string name="accessibility_system_action_hardware_a11y_shortcut_label">Accessibility Shortcut</string>
<!-- Label for dismissing the notification shade [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_dismiss_notification_shade">Dismiss Notification Shade</string>
+ <!-- Label for menu action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_menu_label">Menu</string>
+ <!-- Label for media play/pause action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_media_play_pause_label">Media Play/Pause</string>
<!-- Label for Dpad up action [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_dpad_up_label">Dpad Up</string>
<!-- Label for Dpad down action [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 54ab147..8b13a11 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4433,6 +4433,8 @@
<java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" />
<java-symbol type="string" name="accessibility_system_action_hardware_a11y_shortcut_label" />
<java-symbol type="string" name="accessibility_system_action_dismiss_notification_shade" />
+ <java-symbol type="string" name="accessibility_system_action_menu_label" />
+ <java-symbol type="string" name="accessibility_system_action_media_play_pause_label" />
<java-symbol type="string" name="accessibility_system_action_dpad_up_label" />
<java-symbol type="string" name="accessibility_system_action_dpad_down_label" />
<java-symbol type="string" name="accessibility_system_action_dpad_left_label" />
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index c8015d4..7b70b41 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -87,7 +87,7 @@
bitmap.compress(Bitmap.CompressFormat.PNG, 90, mImage.getOutputStream());
final AssetFileDescriptor afd = new AssetFileDescriptor(
- ParcelFileDescriptor.dup(mImage.getFileDescriptor()), 0, mSize, null);
+ new ParcelFileDescriptor(mImage.getFileDescriptor()), 0, mSize, null);
when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any())).thenReturn(
afd);
}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 24aea37..ecf4eb4 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -17,7 +17,6 @@
package android.security;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -112,29 +111,6 @@
}
/**
- * Informs Keystore 2.0 about changing user's password
- *
- * @param userId - Android user id of the user
- * @param password - a secret derived from the synthetic password provided by the
- * LockSettingsService
- * @return 0 if successful or a {@code ResponseCode}
- * @hide
- */
- public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
- StrictMode.noteDiskWrite();
- try {
- getService().onUserPasswordChanged(userId, password);
- return 0;
- } catch (ServiceSpecificException e) {
- Log.e(TAG, "onUserPasswordChanged failed", e);
- return e.errorCode;
- } catch (Exception e) {
- Log.e(TAG, "Can not connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- /**
* Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to
* Swipe or None. Keystore uses this notification to delete the user's auth-bound keys.
*
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 1385f42..7ad68aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
@@ -5,3 +5,4 @@
nmusgrave@google.com
pbdr@google.com
tkachenkoi@google.com
+vaniadesmonda@google.com
diff --git a/libs/nativehelper_jvm/Android.bp b/libs/nativehelper_jvm/Android.bp
new file mode 100644
index 0000000..b5b7028
--- /dev/null
+++ b/libs/nativehelper_jvm/Android.bp
@@ -0,0 +1,19 @@
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_library_host_static {
+ name: "libnativehelper_jvm",
+ srcs: [
+ "JNIPlatformHelp.c",
+ "JniConstants.c",
+ "file_descriptor_jni.c",
+ ],
+ whole_static_libs: ["libnativehelper_any_vm"],
+ export_static_lib_headers: ["libnativehelper_any_vm"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
diff --git a/libs/nativehelper_jvm/JNIPlatformHelp.c b/libs/nativehelper_jvm/JNIPlatformHelp.c
new file mode 100644
index 0000000..9df31a8
--- /dev/null
+++ b/libs/nativehelper_jvm/JNIPlatformHelp.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <nativehelper/JNIPlatformHelp.h>
+
+#include <stddef.h>
+
+#include "JniConstants.h"
+
+static int GetBufferPosition(JNIEnv* env, jobject nioBuffer) {
+ return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_position(env));
+}
+
+static int GetBufferLimit(JNIEnv* env, jobject nioBuffer) {
+ return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_limit(env));
+}
+
+static int GetBufferElementSizeShift(JNIEnv* env, jobject nioBuffer) {
+ jclass byteBufferClass = JniConstants_NioByteBufferClass(env);
+ jclass shortBufferClass = JniConstants_NioShortBufferClass(env);
+ jclass charBufferClass = JniConstants_NioCharBufferClass(env);
+ jclass intBufferClass = JniConstants_NioIntBufferClass(env);
+ jclass floatBufferClass = JniConstants_NioFloatBufferClass(env);
+ jclass longBufferClass = JniConstants_NioLongBufferClass(env);
+ jclass doubleBufferClass = JniConstants_NioDoubleBufferClass(env);
+
+ // Check the type of the Buffer
+ if ((*env)->IsInstanceOf(env, nioBuffer, byteBufferClass)) {
+ return 0;
+ } else if ((*env)->IsInstanceOf(env, nioBuffer, shortBufferClass) ||
+ (*env)->IsInstanceOf(env, nioBuffer, charBufferClass)) {
+ return 1;
+ } else if ((*env)->IsInstanceOf(env, nioBuffer, intBufferClass) ||
+ (*env)->IsInstanceOf(env, nioBuffer, floatBufferClass)) {
+ return 2;
+ } else if ((*env)->IsInstanceOf(env, nioBuffer, longBufferClass) ||
+ (*env)->IsInstanceOf(env, nioBuffer, doubleBufferClass)) {
+ return 3;
+ }
+ return 0;
+}
+
+jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
+ jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env);
+ jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod);
+ if (hasArray) {
+ jmethodID arrayMethod = JniConstants_NioBuffer_array(env);
+ return (*env)->CallObjectMethod(env, nioBuffer, arrayMethod);
+ } else {
+ return NULL;
+ }
+}
+
+int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
+ jmethodID hasArrayMethod = JniConstants_NioBuffer_hasArray(env);
+ jboolean hasArray = (*env)->CallBooleanMethod(env, nioBuffer, hasArrayMethod);
+ if (hasArray) {
+ jmethodID arrayOffsetMethod = JniConstants_NioBuffer_arrayOffset(env);
+ jint arrayOffset = (*env)->CallIntMethod(env, nioBuffer, arrayOffsetMethod);
+ const int position = GetBufferPosition(env, nioBuffer);
+ jint elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
+ return (arrayOffset + position) << elementSizeShift;
+ } else {
+ return 0;
+ }
+}
+
+jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
+ // in Java 11, the address field of a HeapByteBuffer contains a non-zero value despite
+ // HeapByteBuffer being a non-direct buffer. In that case, this should still return 0.
+ jmethodID isDirectMethod = JniConstants_NioBuffer_isDirect(env);
+ jboolean isDirect = (*env)->CallBooleanMethod(env, nioBuffer, isDirectMethod);
+ if (isDirect == JNI_FALSE) {
+ return 0L;
+ }
+ jlong baseAddress = (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
+ if (baseAddress != 0) {
+ const int position = GetBufferPosition(env, nioBuffer);
+ const int shift = GetBufferElementSizeShift(env, nioBuffer);
+ baseAddress += position << shift;
+ }
+ return baseAddress;
+}
+
+jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
+ jint* position, jint* limit, jint* elementSizeShift) {
+ *position = GetBufferPosition(env, nioBuffer);
+ *limit = GetBufferLimit(env, nioBuffer);
+ *elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
+ return (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
+}
diff --git a/libs/nativehelper_jvm/JniConstants.c b/libs/nativehelper_jvm/JniConstants.c
new file mode 100644
index 0000000..ca58f61
--- /dev/null
+++ b/libs/nativehelper_jvm/JniConstants.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JniConstants.h"
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#define LOG_TAG "JniConstants"
+#include <log/log.h>
+
+// jclass constants list:
+// <class, signature, androidOnly>
+#define JCLASS_CONSTANTS_LIST(V) \
+ V(FileDescriptor, "java/io/FileDescriptor", false) \
+ V(NioBuffer, "java/nio/Buffer", false) \
+ V(NioByteBuffer, "java/nio/ByteBuffer", false) \
+ V(NioShortBuffer, "java/nio/ShortBuffer", false) \
+ V(NioCharBuffer, "java/nio/CharBuffer", false) \
+ V(NioIntBuffer, "java/nio/IntBuffer", false) \
+ V(NioFloatBuffer, "java/nio/FloatBuffer", false) \
+ V(NioLongBuffer, "java/nio/LongBuffer", false) \
+ V(NioDoubleBuffer, "java/nio/DoubleBuffer", false)
+
+// jmethodID's of public methods constants list:
+// <Class, method, method-string, signature, is_static>
+#define JMETHODID_CONSTANTS_LIST(V) \
+ V(FileDescriptor, init, "<init>", "()V", false) \
+ V(NioBuffer, array, "array", "()Ljava/lang/Object;", false) \
+ V(NioBuffer, hasArray, "hasArray", "()Z", false) \
+ V(NioBuffer, isDirect, "isDirect", "()Z", false) \
+ V(NioBuffer, arrayOffset, "arrayOffset", "()I", false)
+
+// jfieldID constants list:
+// <Class, field, signature, is_static>
+#define JFIELDID_CONSTANTS_LIST(V) \
+ V(FileDescriptor, fd, "I", false) \
+ V(NioBuffer, address, "J", false) \
+ V(NioBuffer, limit, "I", false) \
+ V(NioBuffer, position, "I", false)
+
+#define CLASS_NAME(cls) g_ ## cls
+#define METHOD_NAME(cls, method) g_ ## cls ## _ ## method
+#define FIELD_NAME(cls, field) g_ ## cls ## _ ## field
+
+//
+// Declare storage for cached classes, methods and fields.
+//
+
+#define JCLASS_DECLARE_STORAGE(cls, ...) \
+ static jclass CLASS_NAME(cls) = NULL;
+JCLASS_CONSTANTS_LIST(JCLASS_DECLARE_STORAGE)
+#undef JCLASS_DECLARE_STORAGE
+
+#define JMETHODID_DECLARE_STORAGE(cls, method, ...) \
+ static jmethodID METHOD_NAME(cls, method) = NULL;
+JMETHODID_CONSTANTS_LIST(JMETHODID_DECLARE_STORAGE)
+#undef JMETHODID_DECLARE_STORAGE
+
+#define JFIELDID_DECLARE_STORAGE(cls, field, ...) \
+ static jfieldID FIELD_NAME(cls, field) = NULL;
+JFIELDID_CONSTANTS_LIST(JFIELDID_DECLARE_STORAGE)
+#undef JFIELDID_DECLARE_STORAGE
+
+//
+// Helper methods
+//
+
+static jclass FindClass(JNIEnv* env, const char* signature, bool androidOnly) {
+ jclass cls = (*env)->FindClass(env, signature);
+ if (cls == NULL) {
+ LOG_ALWAYS_FATAL_IF(!androidOnly, "Class not found: %s", signature);
+ return NULL;
+ }
+ return (*env)->NewGlobalRef(env, cls);
+}
+
+static jmethodID FindMethod(JNIEnv* env, jclass cls,
+ const char* name, const char* signature, bool isStatic) {
+ jmethodID method;
+ if (isStatic) {
+ method = (*env)->GetStaticMethodID(env, cls, name, signature);
+ } else {
+ method = (*env)->GetMethodID(env, cls, name, signature);
+ }
+ LOG_ALWAYS_FATAL_IF(method == NULL, "Method not found: %s:%s", name, signature);
+ return method;
+}
+
+static jfieldID FindField(JNIEnv* env, jclass cls,
+ const char* name, const char* signature, bool isStatic) {
+ jfieldID field;
+ if (isStatic) {
+ field = (*env)->GetStaticFieldID(env, cls, name, signature);
+ } else {
+ field = (*env)->GetFieldID(env, cls, name, signature);
+ }
+ LOG_ALWAYS_FATAL_IF(field == NULL, "Field not found: %s:%s", name, signature);
+ return field;
+}
+
+static pthread_once_t g_initialized = PTHREAD_ONCE_INIT;
+static JNIEnv* g_init_env;
+
+static void InitializeConstants() {
+ // Initialize cached classes.
+#define JCLASS_INITIALIZE(cls, signature, androidOnly) \
+ CLASS_NAME(cls) = FindClass(g_init_env, signature, androidOnly);
+ JCLASS_CONSTANTS_LIST(JCLASS_INITIALIZE)
+#undef JCLASS_INITIALIZE
+
+ // Initialize cached methods.
+#define JMETHODID_INITIALIZE(cls, method, name, signature, isStatic) \
+ METHOD_NAME(cls, method) = \
+ FindMethod(g_init_env, CLASS_NAME(cls), name, signature, isStatic);
+ JMETHODID_CONSTANTS_LIST(JMETHODID_INITIALIZE)
+#undef JMETHODID_INITIALIZE
+
+ // Initialize cached fields.
+#define JFIELDID_INITIALIZE(cls, field, signature, isStatic) \
+ FIELD_NAME(cls, field) = \
+ FindField(g_init_env, CLASS_NAME(cls), #field, signature, isStatic);
+ JFIELDID_CONSTANTS_LIST(JFIELDID_INITIALIZE)
+#undef JFIELDID_INITIALIZE
+}
+
+void EnsureInitialized(JNIEnv* env) {
+ // This method has to be called in every cache accesses because library can be built
+ // 2 different ways and existing usage for compat version doesn't have a good hook for
+ // initialization and is widely used.
+ g_init_env = env;
+ pthread_once(&g_initialized, InitializeConstants);
+}
+
+// API exported by libnativehelper_api.h.
+
+void jniUninitializeConstants() {
+ // Uninitialize cached classes, methods and fields.
+ //
+ // NB we assume the runtime is stopped at this point and do not delete global
+ // references.
+#define JCLASS_INVALIDATE(cls, ...) CLASS_NAME(cls) = NULL;
+ JCLASS_CONSTANTS_LIST(JCLASS_INVALIDATE);
+#undef JCLASS_INVALIDATE
+
+#define JMETHODID_INVALIDATE(cls, method, ...) METHOD_NAME(cls, method) = NULL;
+ JMETHODID_CONSTANTS_LIST(JMETHODID_INVALIDATE);
+#undef JMETHODID_INVALIDATE
+
+#define JFIELDID_INVALIDATE(cls, field, ...) FIELD_NAME(cls, field) = NULL;
+ JFIELDID_CONSTANTS_LIST(JFIELDID_INVALIDATE);
+#undef JFIELDID_INVALIDATE
+
+ // If jniConstantsUninitialize is called, runtime has shutdown. Reset
+ // state as some tests re-start the runtime.
+ pthread_once_t o = PTHREAD_ONCE_INIT;
+ memcpy(&g_initialized, &o, sizeof(o));
+}
+
+//
+// Accessors
+//
+
+#define JCLASS_ACCESSOR_IMPL(cls, ...) \
+jclass JniConstants_ ## cls ## Class(JNIEnv* env) { \
+ EnsureInitialized(env); \
+ return CLASS_NAME(cls); \
+}
+JCLASS_CONSTANTS_LIST(JCLASS_ACCESSOR_IMPL)
+#undef JCLASS_ACCESSOR_IMPL
+
+#define JMETHODID_ACCESSOR_IMPL(cls, method, ...) \
+jmethodID JniConstants_ ## cls ## _ ## method(JNIEnv* env) { \
+ EnsureInitialized(env); \
+ return METHOD_NAME(cls, method); \
+}
+JMETHODID_CONSTANTS_LIST(JMETHODID_ACCESSOR_IMPL)
+
+#define JFIELDID_ACCESSOR_IMPL(cls, field, ...) \
+jfieldID JniConstants_ ## cls ## _ ## field(JNIEnv* env) { \
+ EnsureInitialized(env); \
+ return FIELD_NAME(cls, field); \
+}
+JFIELDID_CONSTANTS_LIST(JFIELDID_ACCESSOR_IMPL)
diff --git a/libs/nativehelper_jvm/JniConstants.h b/libs/nativehelper_jvm/JniConstants.h
new file mode 100644
index 0000000..e7a266d
--- /dev/null
+++ b/libs/nativehelper_jvm/JniConstants.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+//
+// Classes in constants cache.
+//
+// NB The implementations of these methods are generated by the JCLASS_ACCESSOR_IMPL macro in
+// JniConstants.c.
+//
+jclass JniConstants_FileDescriptorClass(JNIEnv* env);
+jclass JniConstants_NioByteBufferClass(JNIEnv* env);
+jclass JniConstants_NioShortBufferClass(JNIEnv* env);
+jclass JniConstants_NioCharBufferClass(JNIEnv* env);
+jclass JniConstants_NioIntBufferClass(JNIEnv* env);
+jclass JniConstants_NioFloatBufferClass(JNIEnv* env);
+jclass JniConstants_NioLongBufferClass(JNIEnv* env);
+jclass JniConstants_NioDoubleBufferClass(JNIEnv* env);
+
+//
+// Methods in the constants cache.
+//
+// NB The implementations of these methods are generated by the JMETHODID_ACCESSOR_IMPL macro in
+// JniConstants.c.
+//
+jmethodID JniConstants_FileDescriptor_init(JNIEnv* env);
+jmethodID JniConstants_NioBuffer_array(JNIEnv* env);
+jmethodID JniConstants_NioBuffer_arrayOffset(JNIEnv* env);
+jmethodID JniConstants_NioBuffer_hasArray(JNIEnv* env);
+jmethodID JniConstants_NioBuffer_isDirect(JNIEnv* env);
+
+//
+// Fields in the constants cache.
+//
+// NB The implementations of these methods are generated by the JFIELDID_ACCESSOR_IMPL macro in
+// JniConstants.c.
+//
+jfieldID JniConstants_FileDescriptor_fd(JNIEnv* env);
+jfieldID JniConstants_NioBuffer_address(JNIEnv* env);
+jfieldID JniConstants_NioBuffer_limit(JNIEnv* env);
+jfieldID JniConstants_NioBuffer_position(JNIEnv* env);
+
+__END_DECLS
diff --git a/libs/nativehelper_jvm/OWNERS b/libs/nativehelper_jvm/OWNERS
new file mode 100644
index 0000000..5d55f6e
--- /dev/null
+++ b/libs/nativehelper_jvm/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 326772
+
+include /libs/hwui/OWNERS
+include platform/libnativehelper:/OWNERS
+
+diegoperez@google.com
+jgaillard@google.com
diff --git a/libs/nativehelper_jvm/README b/libs/nativehelper_jvm/README
new file mode 100644
index 0000000..755c422
--- /dev/null
+++ b/libs/nativehelper_jvm/README
@@ -0,0 +1,2 @@
+libnativehelper_jvm is a JVM-compatible version of libnativehelper.
+It should be used instead of libnativehelper whenever a host library is meant to run on a JVM.
\ No newline at end of file
diff --git a/libs/nativehelper_jvm/file_descriptor_jni.c b/libs/nativehelper_jvm/file_descriptor_jni.c
new file mode 100644
index 0000000..36880cd
--- /dev/null
+++ b/libs/nativehelper_jvm/file_descriptor_jni.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/file_descriptor_jni.h>
+
+#include <stddef.h>
+
+#define LOG_TAG "file_descriptor_jni"
+#include <log/log.h>
+
+#include "JniConstants.h"
+
+static void EnsureArgumentIsFileDescriptor(JNIEnv* env, jobject instance) {
+ LOG_ALWAYS_FATAL_IF(instance == NULL, "FileDescriptor is NULL");
+ jclass jifd = JniConstants_FileDescriptorClass(env);
+ LOG_ALWAYS_FATAL_IF(!(*env)->IsInstanceOf(env, instance, jifd),
+ "Argument is not a FileDescriptor");
+}
+
+JNIEXPORT _Nullable jobject AFileDescriptor_create(JNIEnv* env) {
+ return (*env)->NewObject(env,
+ JniConstants_FileDescriptorClass(env),
+ JniConstants_FileDescriptor_init(env));
+}
+
+JNIEXPORT int AFileDescriptor_getFd(JNIEnv* env, jobject fileDescriptor) {
+ EnsureArgumentIsFileDescriptor(env, fileDescriptor);
+ return (*env)->GetIntField(env, fileDescriptor, JniConstants_FileDescriptor_fd(env));
+}
+
+JNIEXPORT void AFileDescriptor_setFd(JNIEnv* env, jobject fileDescriptor, int fd) {
+ EnsureArgumentIsFileDescriptor(env, fileDescriptor);
+ (*env)->SetIntField(env, fileDescriptor, JniConstants_FileDescriptor_fd(env), fd);
+}
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 746c280..8f16f76 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -23,6 +23,9 @@
cc_library_shared {
name: "libjnigraphics",
+ defaults: [
+ "bug_24465209_workaround",
+ ],
cflags: [
"-Wall",
@@ -47,13 +50,6 @@
static_libs: ["libarect"],
- arch: {
- arm: {
- // TODO: This is to work around b/24465209. Remove after root cause is fixed
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
- },
- },
host_supported: true,
target: {
android: {
diff --git a/nfc/lint-baseline.xml b/nfc/lint-baseline.xml
index 1dfdd29..d0f797e 100644
--- a/nfc/lint-baseline.xml
+++ b/nfc/lint-baseline.xml
@@ -210,4 +210,59 @@
column="23"/>
</issue>
+ <issue
+ id="FlaggedApi"
+ message="Method `PollingFrame()` is a flagged API and should be inside an `if (Flags.nfcReadPollingLoop())` check (or annotate the surrounding method `handleMessage` with `@FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) to transfer requirement to caller`)"
+ errorLine1=" pollingFrames.add(new PollingFrame(frame));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/cardemulation/HostApduService.java"
+ line="335"
+ column="43"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `processPollingFrames()` is a flagged API and should be inside an `if (Flags.nfcReadPollingLoop())` check (or annotate the surrounding method `handleMessage` with `@FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) to transfer requirement to caller`)"
+ errorLine1=" processPollingFrames(pollingFrames);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/cardemulation/HostApduService.java"
+ line="337"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `NfcOemExtension()` is a flagged API and should be inside an `if (Flags.nfcOemExtension())` check (or annotate the surrounding method `NfcAdapter` with `@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) to transfer requirement to caller`)"
+ errorLine1=" mNfcOemExtension = new NfcOemExtension(mContext, this);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
+ line="895"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVendorNciResponse()` is a flagged API and should be inside an `if (Flags.nfcVendorCmd())` check (or annotate the surrounding method `onVendorResponseReceived` with `@FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD) to transfer requirement to caller`)"
+ errorLine1=" executor.execute(() -> callback.onVendorNciResponse(gid, oid, payload));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcVendorNciCallbackListener.java"
+ line="88"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVendorNciNotification()` is a flagged API and should be inside an `if (Flags.nfcVendorCmd())` check (or annotate the surrounding method `onVendorNotificationReceived` with `@FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD) to transfer requirement to caller`)"
+ errorLine1=" executor.execute(() -> callback.onVendorNciNotification(gid, oid, payload));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcVendorNciCallbackListener.java"
+ line="106"
+ column="44"/>
+ </issue>
+
</issues>
\ No newline at end of file
diff --git a/packages/CtsShim/Android.bp b/packages/CtsShim/Android.bp
index baafe7b..a94c8c5 100644
--- a/packages/CtsShim/Android.bp
+++ b/packages/CtsShim/Android.bp
@@ -61,7 +61,6 @@
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
"com.android.apex.cts.shim.v2_legacy",
- "com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_sdk_target_p",
"com.android.apex.cts.shim.v3",
],
@@ -102,7 +101,6 @@
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
"com.android.apex.cts.shim.v2_legacy",
- "com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_sdk_target_p",
"com.android.apex.cts.shim.v3",
],
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index d6b7ecf..5b3d47e 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -93,7 +93,6 @@
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
"com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
- "com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_legacy",
"com.android.apex.cts.shim.v2_sdk_target_p",
"com.android.apex.cts.shim.v2_unsigned_payload",
@@ -200,7 +199,6 @@
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
"com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
- "com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_legacy",
"com.android.apex.cts.shim.v2_sdk_target_p",
"com.android.apex.cts.shim.v2_unsigned_payload",
diff --git a/packages/CtsShim/build/jni/Android.bp b/packages/CtsShim/build/jni/Android.bp
index 2dbf2a2..ac85d2b 100644
--- a/packages/CtsShim/build/jni/Android.bp
+++ b/packages/CtsShim/build/jni/Android.bp
@@ -33,7 +33,6 @@
"com.android.apex.cts.shim.v1",
"com.android.apex.cts.shim.v2",
"com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
- "com.android.apex.cts.shim.v2_no_hashtree",
"com.android.apex.cts.shim.v2_legacy",
"com.android.apex.cts.shim.v2_sdk_target_p",
"com.android.apex.cts.shim.v2_unsigned_payload",
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index 5966c9f..e4bc7b4 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -11,3 +11,6 @@
# Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS)
per-file *.xml=*
+
+# Notification-related utilities
+per-file **/notification/** = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 0c89a5d..adcb8d4 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -59,7 +59,7 @@
]
}
],
-
+
"auto-end-to-end-postsubmit": [
{
"name": "AndroidAutomotiveHomeTests",
@@ -78,7 +78,7 @@
]
}
],
-
+
"postsubmit": [
{
// Permission indicators
@@ -90,7 +90,7 @@
]
}
],
-
+
// v2/sysui/suite/test-mapping-sysui-screenshot-test
"sysui-screenshot-test": [
{
@@ -128,7 +128,7 @@
]
}
],
-
+
// v2/sysui/suite/test-mapping-sysui-screenshot-test-staged
"sysui-screenshot-test-staged": [
{
@@ -153,5 +153,13 @@
}
]
}
+ ],
+ "sysui-robo-test": [
+ {
+ "name": "SystemUIGoogleRoboRNGTests"
+ },
+ {
+ "name": "SystemUIGoogleRobo2RNGTests"
+ }
]
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index da49201..5c5ff1e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -42,6 +42,7 @@
import android.view.KeyEvent;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.Flags;
import com.android.internal.R;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
@@ -178,6 +179,18 @@
private static final int SYSTEM_ACTION_ID_DPAD_CENTER =
AccessibilityService.GLOBAL_ACTION_DPAD_CENTER; // 20
+ /**
+ * Action ID to trigger menu key event.
+ */
+ private static final int SYSTEM_ACTION_ID_MENU =
+ AccessibilityService.GLOBAL_ACTION_MENU; // 21
+
+ /**
+ * Action ID to trigger media play/pause key event.
+ */
+ private static final int SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE =
+ AccessibilityService.GLOBAL_ACTION_MEDIA_PLAY_PAUSE; // 22
+
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
private final SystemActionsBroadcastReceiver mReceiver;
@@ -305,6 +318,14 @@
R.string.accessibility_system_action_dpad_center_label,
SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER);
+ RemoteAction actionMenu = createRemoteAction(
+ R.string.accessibility_system_action_menu_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_MENU);
+
+ RemoteAction actionMediaPlayPause = createRemoteAction(
+ R.string.accessibility_system_action_media_play_pause_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_MEDIA_PLAY_PAUSE);
+
mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK);
mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME);
mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS);
@@ -324,6 +345,8 @@
mA11yManager.registerSystemAction(actionDpadLeft, SYSTEM_ACTION_ID_DPAD_LEFT);
mA11yManager.registerSystemAction(actionDpadRight, SYSTEM_ACTION_ID_DPAD_RIGHT);
mA11yManager.registerSystemAction(actionDpadCenter, SYSTEM_ACTION_ID_DPAD_CENTER);
+ mA11yManager.registerSystemAction(actionMenu, SYSTEM_ACTION_ID_MENU);
+ mA11yManager.registerSystemAction(actionMediaPlayPause, SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE);
registerOrUnregisterDismissNotificationShadeAction();
}
@@ -433,6 +456,14 @@
labelId = R.string.accessibility_system_action_dpad_center_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER;
break;
+ case SYSTEM_ACTION_ID_MENU:
+ labelId = R.string.accessibility_system_action_menu_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_MENU;
+ break;
+ case SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE:
+ labelId = R.string.accessibility_system_action_media_play_pause_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_MEDIA_PLAY_PAUSE;
+ break;
default:
return;
}
@@ -569,6 +600,16 @@
sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
}
+ @VisibleForTesting
+ void handleMenu() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MENU);
+ }
+
+ @VisibleForTesting
+ void handleMediaPlayPause() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ }
+
private class SystemActionsBroadcastReceiver extends BroadcastReceiver {
private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK";
private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME";
@@ -592,6 +633,9 @@
private static final String INTENT_ACTION_DPAD_LEFT = "SYSTEM_ACTION_DPAD_LEFT";
private static final String INTENT_ACTION_DPAD_RIGHT = "SYSTEM_ACTION_DPAD_RIGHT";
private static final String INTENT_ACTION_DPAD_CENTER = "SYSTEM_ACTION_DPAD_CENTER";
+ private static final String INTENT_ACTION_MENU = "SYSTEM_ACTION_MENU";
+ private static final String INTENT_ACTION_MEDIA_PLAY_PAUSE =
+ "SYSTEM_ACTION_MEDIA_PLAY_PAUSE";
private PendingIntent createPendingIntent(Context context, String intentAction) {
switch (intentAction) {
@@ -612,7 +656,9 @@
case INTENT_ACTION_DPAD_DOWN:
case INTENT_ACTION_DPAD_LEFT:
case INTENT_ACTION_DPAD_RIGHT:
- case INTENT_ACTION_DPAD_CENTER: {
+ case INTENT_ACTION_DPAD_CENTER:
+ case INTENT_ACTION_MENU:
+ case INTENT_ACTION_MEDIA_PLAY_PAUSE: {
Intent intent = new Intent(intentAction);
intent.setPackage(context.getPackageName());
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -645,6 +691,8 @@
intentFilter.addAction(INTENT_ACTION_DPAD_LEFT);
intentFilter.addAction(INTENT_ACTION_DPAD_RIGHT);
intentFilter.addAction(INTENT_ACTION_DPAD_CENTER);
+ intentFilter.addAction(INTENT_ACTION_MENU);
+ intentFilter.addAction(INTENT_ACTION_MEDIA_PLAY_PAUSE);
return intentFilter;
}
@@ -724,6 +772,18 @@
handleDpadCenter();
break;
}
+ case INTENT_ACTION_MENU: {
+ if (Flags.globalActionMenu()) {
+ handleMenu();
+ }
+ break;
+ }
+ case INTENT_ACTION_MEDIA_PLAY_PAUSE: {
+ if (Flags.globalActionMediaPlayPause()) {
+ handleMediaPlayPause();
+ }
+ break;
+ }
default:
break;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
index b478d5c..da3e487 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.accessibility;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
@@ -25,11 +26,15 @@
import android.hardware.input.InputManager;
import android.os.RemoteException;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.KeyEvent;
+import android.view.accessibility.Flags;
import androidx.test.filters.SmallTest;
@@ -43,6 +48,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -76,6 +82,9 @@
private SystemActions mSystemActions;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
@@ -130,4 +139,40 @@
verify(mTelecomManager).endCall();
}
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_GLOBAL_ACTION_MENU)
+ public void handleMenu_injectsKeyEvents() {
+ final List<KeyEvent> keyEvents = new ArrayList<>();
+ doAnswer(invocation -> {
+ keyEvents.add(new KeyEvent(invocation.getArgument(0)));
+ return null;
+ }).when(mInputManager).injectInputEvent(any(), anyInt());
+
+ mSystemActions.handleMenu();
+
+ assertThat(keyEvents.size()).isEqualTo(2);
+ assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MENU);
+ assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MENU);
+ assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_GLOBAL_ACTION_MEDIA_PLAY_PAUSE)
+ public void handleMediaPlayPause_injectsKeyEvents() {
+ final List<KeyEvent> keyEvents = new ArrayList<>();
+ doAnswer(invocation -> {
+ keyEvents.add(new KeyEvent(invocation.getArgument(0)));
+ return null;
+ }).when(mInputManager).injectInputEvent(any(), anyInt());
+
+ mSystemActions.handleMediaPlayPause();
+
+ assertThat(keyEvents.size()).isEqualTo(2);
+ assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 9747579..2945af5 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -34,6 +34,7 @@
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.accessibility.Flags;
import com.android.internal.R;
import com.android.internal.accessibility.util.AccessibilityUtils;
@@ -328,6 +329,18 @@
sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER,
InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD);
return true;
+ case AccessibilityService.GLOBAL_ACTION_MENU:
+ if (Flags.globalActionMenu()) {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MENU,
+ InputDevice.SOURCE_KEYBOARD);
+ }
+ return true;
+ case AccessibilityService.GLOBAL_ACTION_MEDIA_PLAY_PAUSE:
+ if (Flags.globalActionMediaPlayPause()) {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+ InputDevice.SOURCE_KEYBOARD);
+ }
+ return true;
default:
Slog.e(TAG, "Invalid action id: " + actionId);
return false;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 98263df..48072e8 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -2296,7 +2296,8 @@
ipw.println();
if (dumpConstants) {
- mConstants.dump(ipw);
+ mFgConstants.dump(ipw);
+ mBgConstants.dump(ipw);
}
if (dumpHistory) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ac29f85..7157646 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -252,9 +252,6 @@
private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce";
private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys";
- private static final boolean FIX_UNLOCKED_DEVICE_REQUIRED_KEYS =
- android.security.Flags.fixUnlockedDeviceRequiredKeysV2();
-
// Duration that LockSettingsService will store the gatekeeper password for. This allows
// multiple biometric enrollments without prompting the user to enter their password via
// ConfirmLockPassword/ConfirmLockPattern multiple times. This needs to be at least the duration
@@ -662,7 +659,6 @@
mActivityManager = injector.getActivityManager();
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
@@ -899,13 +895,7 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
- if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- // Notify keystore that a new user was added.
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- AndroidKeyStoreMaintenance.onUserAdded(userHandle);
- }
- } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
+ if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
} else if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
@@ -1089,32 +1079,14 @@
// Note: if this migration gets interrupted (e.g. by the device powering off), there
// shouldn't be a problem since this will run again on the next boot, and
// setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent.
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
- for (UserInfo user : mUserManager.getAliveUsers()) {
- removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
- synchronized (mSpManager) {
- migrateUserToSpWithBoundKeysLocked(user.id);
- }
+ if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
+ for (UserInfo user : mUserManager.getAliveUsers()) {
+ removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
+ synchronized (mSpManager) {
+ migrateUserToSpWithBoundKeysLocked(user.id);
}
- setBoolean(MIGRATED_SP_FULL, true, 0);
}
- } else {
- if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) {
- for (UserInfo user : mUserManager.getAliveUsers()) {
- removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
- synchronized (mSpManager) {
- migrateUserToSpWithBoundCeKeyLocked(user.id);
- }
- }
- setString(MIGRATED_SP_CE_ONLY, "true", 0);
- }
-
- if (getBoolean(MIGRATED_SP_FULL, false, 0)) {
- // The FIX_UNLOCKED_DEVICE_REQUIRED_KEYS flag was enabled but then got disabled.
- // Ensure the full migration runs again the next time the flag is enabled...
- setBoolean(MIGRATED_SP_FULL, false, 0);
- }
+ setBoolean(MIGRATED_SP_FULL, true, 0);
}
mThirdPartyAppsStarted = true;
@@ -1122,30 +1094,6 @@
}
@GuardedBy("mSpManager")
- private void migrateUserToSpWithBoundCeKeyLocked(@UserIdInt int userId) {
- if (isUserSecure(userId)) {
- Slogf.d(TAG, "User %d is secured; no migration needed", userId);
- return;
- }
- long protectorId = getCurrentLskfBasedProtectorId(userId);
- if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) {
- Slogf.i(TAG, "Migrating unsecured user %d to SP-based credential", userId);
- initializeSyntheticPassword(userId);
- } else {
- Slogf.i(TAG, "Existing unsecured user %d has a synthetic password; re-encrypting CE " +
- "key with it", userId);
- AuthenticationResult result = mSpManager.unlockLskfBasedProtector(
- getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId,
- null);
- if (result.syntheticPassword == null) {
- Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId);
- return;
- }
- setCeStorageProtection(userId, result.syntheticPassword);
- }
- }
-
- @GuardedBy("mSpManager")
private void migrateUserToSpWithBoundKeysLocked(@UserIdInt int userId) {
if (isUserSecure(userId)) {
Slogf.d(TAG, "User %d is secured; no migration needed", userId);
@@ -1454,11 +1402,6 @@
}
@VisibleForTesting /** Note: this method is overridden in unit tests */
- void setKeystorePassword(byte[] password, int userHandle) {
- AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
- }
-
- @VisibleForTesting /** Note: this method is overridden in unit tests */
void initKeystoreSuperKeys(@UserIdInt int userId, SyntheticPassword sp, boolean allowExisting) {
final byte[] password = sp.deriveKeyStorePassword();
try {
@@ -2195,9 +2138,7 @@
return;
}
onSyntheticPasswordUnlocked(userId, result.syntheticPassword);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- unlockKeystore(userId, result.syntheticPassword);
- }
+ unlockKeystore(userId, result.syntheticPassword);
unlockCeStorage(userId, result.syntheticPassword);
}
}
@@ -2503,9 +2444,7 @@
// long time, so for now we keep doing it just in case it's ever important. Don't wait
// until initKeystoreSuperKeys() to do this; that can be delayed if the user is being
// created during early boot, and maybe something will use Keystore before then.
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- AndroidKeyStoreMaintenance.onUserAdded(userId);
- }
+ AndroidKeyStoreMaintenance.onUserAdded(userId);
synchronized (mUserCreationAndRemovalLock) {
// During early boot, don't actually create the synthetic password yet, but rather
@@ -2931,9 +2870,7 @@
LockscreenCredential.createNone(), sp, userId);
setCurrentLskfBasedProtectorId(protectorId, userId);
setCeStorageProtection(userId, sp);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
- }
+ initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
onSyntheticPasswordCreated(userId, sp);
Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId);
return sp;
@@ -3048,9 +2985,6 @@
if (!mSpManager.hasSidForUser(userId)) {
mSpManager.newSidForUser(getGateKeeperService(), sp, userId);
mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
- if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- setKeystorePassword(sp.deriveKeyStorePassword(), userId);
- }
}
} else {
// Cache all profile password if they use unified challenge. This will later be used to
@@ -3061,11 +2995,7 @@
gateKeeperClearSecureUserId(userId);
unlockCeStorage(userId, sp);
unlockKeystore(userId, sp);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- AndroidKeyStoreMaintenance.onUserLskfRemoved(userId);
- } else {
- setKeystorePassword(null, userId);
- }
+ AndroidKeyStoreMaintenance.onUserLskfRemoved(userId);
removeBiometricsForUser(userId);
}
setCurrentLskfBasedProtectorId(newProtectorId, userId);
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index 94340ec..c1fad33 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,6 +1,7 @@
michaelwr@google.com
santoscordon@google.com
-philipjunker@google.com
+petsjonkin@google.com
+brup@google.com
per-file ThermalManagerService.java=file:/THERMAL_OWNERS
per-file LowPowerStandbyController.java=qingxun@google.com
diff --git a/services/core/java/com/android/server/timezonedetector/OWNERS b/services/core/java/com/android/server/timezonedetector/OWNERS
index dfa07d8..4220d14 100644
--- a/services/core/java/com/android/server/timezonedetector/OWNERS
+++ b/services/core/java/com/android/server/timezonedetector/OWNERS
@@ -1,7 +1,6 @@
# Bug component: 847766
# This is the main list for platform time / time zone detection maintainers, for this dir and
# ultimately referenced by other OWNERS files for components maintained by the same team.
-nfuller@google.com
boullanger@google.com
jmorace@google.com
kanyinsola@google.com
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index f62c76e..b3c31a9 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -267,6 +267,10 @@
return KeyStoreAuthorization.getInstance();
}
+ AlarmManager getAlarmManager() {
+ return mContext.getSystemService(AlarmManager.class);
+ }
+
Looper getLooper() {
return Looper.myLooper();
}
@@ -285,7 +289,7 @@
mLockPatternUtils = injector.getLockPatternUtils();
mKeyStoreAuthorization = injector.getKeyStoreAuthorization();
mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper());
- mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ mAlarmManager = injector.getAlarmManager();
}
@Override
@@ -845,12 +849,7 @@
continue;
}
- final boolean trusted;
- if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) {
- trusted = getUserTrustStateInner(id) == TrustState.TRUSTED;
- } else {
- trusted = aggregateIsTrusted(id);
- }
+ final boolean trusted = getUserTrustStateInner(id) == TrustState.TRUSTED;
boolean showingKeyguard = true;
boolean biometricAuthenticated = false;
boolean currentUserIsUnlocked = false;
@@ -911,19 +910,15 @@
private void notifyKeystoreOfDeviceLockState(int userId, boolean isLocked) {
if (isLocked) {
- if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) {
- // A profile with unified challenge is unlockable not by its own biometrics and
- // trust agents, but rather by those of the parent user. Therefore, when protecting
- // the profile's UnlockedDeviceRequired keys, we must use the parent's list of
- // biometric SIDs and weak unlock methods, not the profile's.
- int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId)
- ? resolveProfileParent(userId) : userId;
+ // A profile with unified challenge is unlockable not by its own biometrics and
+ // trust agents, but rather by those of the parent user. Therefore, when protecting
+ // the profile's UnlockedDeviceRequired keys, we must use the parent's list of
+ // biometric SIDs and weak unlock methods, not the profile's.
+ int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId)
+ ? resolveProfileParent(userId) : userId;
- mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(authUserId),
- isWeakUnlockMethodEnabled(authUserId));
- } else {
- mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(userId), false);
- }
+ mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(authUserId),
+ isWeakUnlockMethodEnabled(authUserId));
} else {
// Notify Keystore that the device is now unlocked for the user. Note that for unlocks
// with LSKF, this is redundant with the call from LockSettingsService which provides
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index e7565ee..45ea2db3 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -629,9 +629,12 @@
synchronized (mLock) {
if (mLastWallpaper != null) {
WallpaperData targetWallpaper = null;
- if (mLastWallpaper.connection.containsDisplay(displayId)) {
+ if (mLastWallpaper.connection != null &&
+ mLastWallpaper.connection.containsDisplay(displayId)) {
targetWallpaper = mLastWallpaper;
- } else if (mFallbackWallpaper.connection.containsDisplay(displayId)) {
+ } else if (mFallbackWallpaper != null &&
+ mFallbackWallpaper.connection != null &&
+ mFallbackWallpaper.connection.containsDisplay(displayId)) {
targetWallpaper = mFallbackWallpaper;
}
if (targetWallpaper == null) return;
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 0532e04..7aec42b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.trust;
+import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
@@ -26,12 +28,22 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import static java.util.Collections.singleton;
+
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustListener;
@@ -60,20 +72,24 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.security.KeyStoreAuthorization;
+import android.service.trust.GrantTrustResult;
+import android.service.trust.ITrustAgentService;
+import android.service.trust.ITrustAgentServiceCallback;
import android.service.trust.TrustAgentService;
import android.testing.TestableContext;
+import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import androidx.test.core.app.ApplicationProvider;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.StrongAuthFlags;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -81,15 +97,19 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
+import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class TrustManagerServiceTest {
@@ -101,9 +121,6 @@
.build();
@Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
- @Rule
public final MockContext mMockContext = new MockContext(
ApplicationProvider.getApplicationContext());
@@ -115,21 +132,28 @@
private static final int PROFILE_USER_ID = 70;
private static final long[] PARENT_BIOMETRIC_SIDS = new long[] { 600L, 601L };
private static final long[] PROFILE_BIOMETRIC_SIDS = new long[] { 700L, 701L };
+ private static final long RENEWABLE_TRUST_DURATION = 10000L;
+ private static final String GRANT_TRUST_MESSAGE = "granted";
+ private static final String TAG = "TrustManagerServiceTest";
private final ArrayList<ResolveInfo> mTrustAgentResolveInfoList = new ArrayList<>();
private final ArrayList<ComponentName> mKnownTrustAgents = new ArrayList<>();
private final ArrayList<ComponentName> mEnabledTrustAgents = new ArrayList<>();
+ private final Map<ComponentName, ITrustAgentService.Stub> mMockTrustAgents = new HashMap<>();
private @Mock ActivityManager mActivityManager;
+ private @Mock AlarmManager mAlarmManager;
private @Mock BiometricManager mBiometricManager;
private @Mock DevicePolicyManager mDevicePolicyManager;
private @Mock FaceManager mFaceManager;
private @Mock FingerprintManager mFingerprintManager;
private @Mock KeyStoreAuthorization mKeyStoreAuthorization;
private @Mock LockPatternUtils mLockPatternUtils;
+ private @Mock LockSettingsInternal mLockSettingsInternal;
private @Mock PackageManager mPackageManager;
private @Mock UserManager mUserManager;
private @Mock IWindowManager mWindowManager;
+ private @Mock ITrustListener mTrustListener;
private HandlerThread mHandlerThread;
private TrustManagerService mService;
@@ -158,6 +182,9 @@
return null;
}).when(mLockPatternUtils).setEnabledTrustAgents(any(), eq(TEST_USER_ID));
+ LocalServices.removeServiceForTest(LockSettingsInternal.class);
+ LocalServices.addService(LockSettingsInternal.class, mLockSettingsInternal);
+
ArgumentMatcher<Intent> trustAgentIntentMatcher = new ArgumentMatcher<Intent>() {
@Override
public boolean matches(Intent argument) {
@@ -176,6 +203,7 @@
when(mWindowManager.isKeyguardLocked()).thenReturn(true);
mMockContext.addMockSystemService(ActivityManager.class, mActivityManager);
+ mMockContext.addMockSystemService(AlarmManager.class, mAlarmManager);
mMockContext.addMockSystemService(BiometricManager.class, mBiometricManager);
mMockContext.addMockSystemService(FaceManager.class, mFaceManager);
mMockContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
@@ -197,6 +225,7 @@
verify(() -> ServiceManager.addService(eq(Context.TRUST_SERVICE),
binderArgumentCaptor.capture(), anyBoolean(), anyInt()));
mTrustManager = ITrustManager.Stub.asInterface(binderArgumentCaptor.getValue());
+ mTrustManager.registerTrustListener(mTrustListener);
}
private class MockInjector extends TrustManagerService.Injector {
@@ -215,6 +244,11 @@
}
@Override
+ AlarmManager getAlarmManager() {
+ return mAlarmManager;
+ }
+
+ @Override
Looper getLooper() {
return mHandlerThread.getLooper();
}
@@ -367,12 +401,10 @@
@Test
public void reportEnabledTrustAgentsChangedInformsListener() throws RemoteException {
- final ITrustListener trustListener = mock(ITrustListener.class);
- mTrustManager.registerTrustListener(trustListener);
mService.waitForIdle();
mTrustManager.reportEnabledTrustAgentsChanged(TEST_USER_ID);
mService.waitForIdle();
- verify(trustListener).onEnabledTrustAgentsChanged(TEST_USER_ID);
+ verify(mTrustListener).onEnabledTrustAgentsChanged(TEST_USER_ID);
}
// Tests that when the device is locked for a managed profile with a *unified* challenge, the
@@ -380,7 +412,6 @@
// user, not the profile. This matches the authentication that is needed to unlock the device
// for the profile again.
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testLockDeviceForManagedProfileWithUnifiedChallenge_usesParentBiometricSids()
throws Exception {
setupMocksForProfile(/* unifiedChallenge= */ true);
@@ -416,7 +447,169 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+ public void testSuccessfulUnlock_bindsTrustAgent() throws Exception {
+ when(mUserManager.getAliveUsers())
+ .thenReturn(List.of(new UserInfo(TEST_USER_ID, "test", UserInfo.FLAG_FULL)));
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(
+ trustAgentName, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ assertThat(getCallback(trustAgentService)).isNotNull();
+ }
+
+ @Test
+ public void testSuccessfulUnlock_notifiesTrustAgent() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(
+ trustAgentName, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(trustAgentService).onUnlockAttempt(/* successful= */ true);
+ }
+
+ @Test
+ public void testSuccessfulUnlock_notifiesTrustListenerOfChangeInManagedTrust()
+ throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+ mService.waitForIdle();
+ Mockito.reset(mTrustListener);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(mTrustListener).onTrustManagedChanged(false, TEST_USER_ID);
+ }
+
+ @Test
+ @Ignore("TODO: b/340891566 - Trustagent always refreshes trustable timer for user 0 on unlock")
+ public void testSuccessfulUnlock_refreshesTrustableTimers() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgent =
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+ setUpRenewableTrust(trustAgent);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ // Idle and hard timeout alarms for first renewable trust granted
+ // Idle timeout alarm refresh for second renewable trust granted
+ // Idle and hard timeout alarms refresh for last report
+ verify(mAlarmManager, times(3))
+ .setExact(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ anyLong(),
+ anyString(),
+ any(AlarmManager.OnAlarmListener.class),
+ any(Handler.class));
+ }
+
+ @Test
+ public void testFailedUnlock_doesNotBindTrustAgent() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(
+ trustAgentName, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ attemptFailedUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(trustAgentService, never()).setCallback(any());
+ }
+
+ @Test
+ public void testFailedUnlock_notifiesTrustAgent() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+
+ attemptFailedUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(trustAgentService).onUnlockAttempt(/* successful= */ false);
+ }
+
+ @Test
+ public void testFailedUnlock_doesNotNotifyTrustListenerOfChangeInManagedTrust()
+ throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+ Mockito.reset(mTrustListener);
+
+ attemptFailedUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(mTrustListener, never()).onTrustManagedChanged(anyBoolean(), anyInt());
+ }
+
+ private void setUpRenewableTrust(ITrustAgentService trustAgent) throws RemoteException {
+ ITrustAgentServiceCallback callback = getCallback(trustAgent);
+ callback.setManagingTrust(true);
+ mService.waitForIdle();
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+ when(mWindowManager.isKeyguardLocked()).thenReturn(false);
+ grantRenewableTrust(callback);
+ }
+
+ private ITrustAgentService setUpTrustAgentWithStrongAuthRequired(
+ ComponentName agentName, @StrongAuthFlags int strongAuthFlags) throws Exception {
+ doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(TEST_USER_ID);
+ addTrustAgent(agentName, true);
+ mLockPatternUtils.setKnownTrustAgents(singleton(agentName), TEST_USER_ID);
+ mLockPatternUtils.setEnabledTrustAgents(singleton(agentName), TEST_USER_ID);
+ when(mUserManager.isUserUnlockingOrUnlocked(TEST_USER_ID)).thenReturn(true);
+ setupStrongAuthTracker(strongAuthFlags, false);
+ mService.waitForIdle();
+ return getOrCreateMockTrustAgent(agentName);
+ }
+
+ private void attemptSuccessfulUnlock(int userId) throws RemoteException {
+ mTrustManager.reportUnlockAttempt(/* successful= */ true, userId);
+ }
+
+ private void attemptFailedUnlock(int userId) throws RemoteException {
+ mTrustManager.reportUnlockAttempt(/* successful= */ false, userId);
+ }
+
+ private void grantRenewableTrust(ITrustAgentServiceCallback callback) throws RemoteException {
+ Log.i(TAG, "Granting trust");
+ AndroidFuture<GrantTrustResult> future = new AndroidFuture<>();
+ callback.grantTrust(
+ GRANT_TRUST_MESSAGE,
+ RENEWABLE_TRUST_DURATION,
+ FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE,
+ future);
+ mService.waitForIdle();
+ }
+
+ /**
+ * Retrieve the ITrustAgentServiceCallback attached to a TrustAgentService after it has been
+ * bound to by the TrustManagerService. Will fail if no binding was established.
+ */
+ private ITrustAgentServiceCallback getCallback(ITrustAgentService trustAgentService)
+ throws RemoteException {
+ ArgumentCaptor<ITrustAgentServiceCallback> callbackCaptor =
+ ArgumentCaptor.forClass(ITrustAgentServiceCallback.class);
+ verify(trustAgentService).setCallback(callbackCaptor.capture());
+ return callbackCaptor.getValue();
+ }
+
+ @Test
public void testKeystoreWeakUnlockEnabled_whenWeakFingerprintIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -425,7 +618,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenWeakFaceIsSetupAndAllowed() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFace(SensorProperties.STRENGTH_WEAK);
@@ -433,7 +625,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenConvenienceFingerprintIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -442,7 +633,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenConvenienceFaceIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -451,7 +641,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenStrongAuthRequired() throws Exception {
setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, true);
setupFace(SensorProperties.STRENGTH_WEAK);
@@ -459,7 +648,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenNonStrongBiometricNotAllowed() throws Exception {
setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED,
/* isNonStrongBiometricAllowed= */ false);
@@ -468,7 +656,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFingerprintSensorIsPresentButNotEnrolled()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -477,7 +664,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFaceSensorIsPresentButNotEnrolled()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -486,7 +672,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void
testKeystoreWeakUnlockDisabled_whenWeakFingerprintIsSetupButForbiddenByDevicePolicy()
throws Exception {
@@ -498,7 +683,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFaceIsSetupButForbiddenByDevicePolicy()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -509,7 +693,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFingerprintIsSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFingerprint(SensorProperties.STRENGTH_STRONG);
@@ -517,7 +700,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFaceIsSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFace(SensorProperties.STRENGTH_STRONG);
@@ -525,7 +707,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenNoBiometricsAreSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
verifyWeakUnlockDisabled();
@@ -637,6 +818,20 @@
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = serviceInfo;
mTrustAgentResolveInfoList.add(resolveInfo);
+ ITrustAgentService.Stub mockService = getOrCreateMockTrustAgent(agentComponentName);
+ mMockContext.addMockService(agentComponentName, mockService);
+ mMockTrustAgents.put(agentComponentName, mockService);
+ }
+
+ private ITrustAgentService.Stub getOrCreateMockTrustAgent(ComponentName agentComponentName) {
+ return mMockTrustAgents.computeIfAbsent(
+ agentComponentName,
+ (componentName) -> {
+ ITrustAgentService.Stub mockTrustAgent = mock(ITrustAgentService.Stub.class);
+ when(mockTrustAgent.queryLocalInterface(anyString()))
+ .thenReturn(mockTrustAgent);
+ return mockTrustAgent;
+ });
}
private void bootService() {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index f9077c4..93fc071a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -196,11 +196,6 @@
}
@Override
- void setKeystorePassword(byte[] password, int userHandle) {
-
- }
-
- @Override
void initKeystoreSuperKeys(int userId, SyntheticPassword sp, boolean allowExisting) {
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index a8a9017..ba33eab 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -33,6 +33,7 @@
import android.util.TimeUtils;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -136,6 +137,7 @@
// The obfuscated packages to tokens mappings file
private final File mPackageMappingsFile;
// Holds all of the data related to the obfuscated packages and their token mappings.
+ @GuardedBy("mLock")
final PackagesTokenData mPackagesTokenData = new PackagesTokenData();
/**
@@ -771,27 +773,30 @@
* all of the stats at once has an amortized cost for future calls.
*/
void filterStats(IntervalStats stats) {
- if (mPackagesTokenData.removedPackagesMap.isEmpty()) {
- return;
- }
- final ArrayMap<String, Long> removedPackagesMap = mPackagesTokenData.removedPackagesMap;
-
- // filter out package usage stats
- final int removedPackagesSize = removedPackagesMap.size();
- for (int i = 0; i < removedPackagesSize; i++) {
- final String removedPackage = removedPackagesMap.keyAt(i);
- final UsageStats usageStats = stats.packageStats.get(removedPackage);
- if (usageStats != null && usageStats.mEndTimeStamp < removedPackagesMap.valueAt(i)) {
- stats.packageStats.remove(removedPackage);
+ synchronized (mLock) {
+ if (mPackagesTokenData.removedPackagesMap.isEmpty()) {
+ return;
}
- }
+ final ArrayMap<String, Long> removedPackagesMap = mPackagesTokenData.removedPackagesMap;
- // filter out events
- for (int i = stats.events.size() - 1; i >= 0; i--) {
- final UsageEvents.Event event = stats.events.get(i);
- final Long timeRemoved = removedPackagesMap.get(event.mPackage);
- if (timeRemoved != null && timeRemoved > event.mTimeStamp) {
- stats.events.remove(i);
+ // filter out package usage stats
+ final int removedPackagesSize = removedPackagesMap.size();
+ for (int i = 0; i < removedPackagesSize; i++) {
+ final String removedPackage = removedPackagesMap.keyAt(i);
+ final UsageStats usageStats = stats.packageStats.get(removedPackage);
+ if (usageStats != null &&
+ usageStats.mEndTimeStamp < removedPackagesMap.valueAt(i)) {
+ stats.packageStats.remove(removedPackage);
+ }
+ }
+
+ // filter out events
+ for (int i = stats.events.size() - 1; i >= 0; i--) {
+ final UsageEvents.Event event = stats.events.get(i);
+ final Long timeRemoved = removedPackagesMap.get(event.mPackage);
+ if (timeRemoved != null && timeRemoved > event.mTimeStamp) {
+ stats.events.remove(i);
+ }
}
}
}
@@ -1226,12 +1231,14 @@
}
void obfuscateCurrentStats(IntervalStats[] currentStats) {
- if (mCurrentVersion < 5) {
- return;
- }
- for (int i = 0; i < currentStats.length; i++) {
- final IntervalStats stats = currentStats[i];
- stats.obfuscateData(mPackagesTokenData);
+ synchronized (mLock) {
+ if (mCurrentVersion < 5) {
+ return;
+ }
+ for (int i = 0; i < currentStats.length; i++) {
+ final IntervalStats stats = currentStats[i];
+ stats.obfuscateData(mPackagesTokenData);
+ }
}
}
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index d0e5626..0c3c7e2 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -17,9 +17,6 @@
package android.trust.test
import android.content.pm.PackageManager
-import android.platform.test.annotations.RequiresFlagsDisabled
-import android.platform.test.annotations.RequiresFlagsEnabled
-import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.service.trust.GrantTrustResult
import android.trust.BaseTrustAgentService
import android.trust.TrustTestActivity
@@ -58,7 +55,6 @@
.around(ScreenLockRule())
.around(lockStateTrackingRule)
.around(trustAgentRule)
- .around(DeviceFlagsValueProvider.createCheckFlagsRule())
@Before
fun manageTrust() {
@@ -93,7 +89,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
fun grantCannotActivelyUnlockDevice() {
// On automotive, trust agents can actively unlock the device.
assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
@@ -120,24 +115,6 @@
}
@Test
- @RequiresFlagsDisabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
- fun grantCouldCauseWrongDeviceLockedStateDueToBug() {
- // On automotive, trust agents can actively unlock the device.
- assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
-
- // Verify that b/296464083 exists. That is, when the device is locked
- // and a trust agent grants trust, the deviceLocked state incorrectly
- // becomes false even though the device correctly remains locked.
- uiDevice.sleep()
- lockStateTrackingRule.assertLocked()
- trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
- uiDevice.wakeUp()
- uiDevice.sleep()
- await()
- lockStateTrackingRule.assertUnlockedButNotReally()
- }
-
- @Test
fun grantDoesNotCallBack() {
val callback = mock<(GrantTrustResult) -> Unit>()
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0, callback)
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 0121809..80d7947 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -64,13 +64,6 @@
wait("not trusted") { trustState.trusted == false }
}
- // TODO(b/299298338) remove this when removing FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2
- fun assertUnlockedButNotReally() {
- wait("device unlocked") { !keyguardManager.isDeviceLocked }
- wait("not trusted") { trustState.trusted == false }
- wait("keyguard locked") { windowManager.isKeyguardLocked }
- }
-
fun assertUnlockedAndTrusted() {
wait("device unlocked") { !keyguardManager.isDeviceLocked }
wait("trusted") { trustState.trusted == true }