diff options
author | Xin Li <delphij@google.com> | 2023-10-05 15:37:36 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2023-10-05 15:37:36 -0700 |
commit | b82ab9e8037d8492f0118185b6109aa7f1c5efa9 (patch) | |
tree | cdfdec510b7b431b4dccfafe6461a844a58577b9 | |
parent | 2067f2a64659376c0f5d125ec5e2dea033ac1c57 (diff) | |
parent | 1ce79dfbac3fffd4bb10a9aa108df96cd53af0f8 (diff) | |
download | connectedappssdk-b82ab9e8037d8492f0118185b6109aa7f1c5efa9.tar.gz |
Merge Android 14
Bug: 298295554
Merged-In: I52ebfa22d61ba8fdf2af481d034a07d37429dd43
Change-Id: Ie3be18dbfafff720bcc54255c79f0d1766ff04ec
15 files changed, 40 insertions, 1078 deletions
@@ -92,3 +92,43 @@ android_library { manifest: "testing/sdk/src/main/AndroidManifest.xml", min_sdk_version: "28", } + +android_library { + name: "ConnectedAppsSDK_SharedTestApp", + sdk_version: "test_current", + srcs: [ + "tests/shared/src/main/java/**/*.java" + ], + manifest: "tests/shared/src/main/AndroidManifest.xml", + min_sdk_version: "28", + static_libs: [ + "ConnectedAppsSDK_Annotations", + "ConnectedAppsSDK", + "guava", + "truth-prebuilt" + ], + plugins: ["ConnectedAppsSDK_Processor"], +} + +// We only run instrumented tests in AOSP +android_test { + name: "ConnectedAppsSDKTest", + srcs: [ + "tests/instrumented/src/main/java/**/*.java" + ], + test_suites: [ + "general-tests", + ], + static_libs: [ + "ConnectedAppsSDK", + "ConnectedAppsSDK_Annotations", + "ConnectedAppsSDK_SharedTestApp", + "ConnectedAppsSDK_Testing", + "androidx.test.ext.junit", + "ctstestrunner-axt", + "truth-prebuilt", + "testng", // for assertThrows + ], + manifest: "tests/instrumented/src/AndroidManifest.xml", + min_sdk_version: "28" +} diff --git a/connectedappssdk.iml b/connectedappssdk.iml deleted file mode 100644 index 5fa0513..0000000 --- a/connectedappssdk.iml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module type="JAVA_MODULE" version="4"> - <component name="NewModuleRootManager" inherit-compiler-output="true"> - <exclude-output /> - <content url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk"> - <sourceFolder url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk/annotations/src/main/java" isTestSource="false" /> - <sourceFolder url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk/processor/src/main/java" isTestSource="false" /> - <sourceFolder url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk/sdk/src/main/java" isTestSource="false" /> - <sourceFolder url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk/testing/annotations/src/main/java" isTestSource="false" /> - <sourceFolder url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk/testing/sdk/src/main/java" isTestSource="false" /> - <sourceFolder url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk/tests/instrumented/src/main/java" isTestSource="true" /> - <sourceFolder url="file:///usr/local/google/home/scottjonathan/android-master/external/connectedappssdk/tests/shared/src/main/java" isTestSource="true" /> - </content> - <orderEntry type="sourceFolder" forTests="false" /> - <orderEntry type="module" module-name="framework_srcjars" /> - <orderEntry type="module" module-name="base" /> - <orderEntry type="module" module-name="cts" /> - <orderEntry type="module" module-name="dependencies" /> - <orderEntry type="inheritedJdk" /> - </component> -</module> diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/BackgroundExceptionThrower.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/BackgroundExceptionThrower.java deleted file mode 100644 index 9511e19..0000000 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/BackgroundExceptionThrower.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.internal; - -import android.os.Handler; -import android.os.Looper; - -/** Utility class for throwing an exception in the background after a delay. */ -public final class BackgroundExceptionThrower { - - private BackgroundExceptionThrower() {} - - private static class ThrowingRunnable implements Runnable { - RuntimeException runtimeException; - Error error; - - ThrowingRunnable(RuntimeException runtimeException) { - this.runtimeException = runtimeException; - } - - ThrowingRunnable(Error error) { - this.error = error; - } - - @Override - public void run() { - if (error != null) { - throw error; - } - throw runtimeException; - } - } - - /** Throw the given {@link Throwable} after a delay on the main looper. */ - public static void throwInBackground(RuntimeException throwable) { - // We add a small delay to ensure that the return can be completed before crashing - new Handler(Looper.getMainLooper()).postDelayed(new ThrowingRunnable(throwable), 1000); - } - - /** Throw the given {@link Error} after a delay on the main looper. */ - public static void throwInBackground(Error throwable) { - // We add a small delay to ensure that the return can be completed before crashing - new Handler(Looper.getMainLooper()).postDelayed(new ThrowingRunnable(throwable), 1000); - } -} diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileCallbackExceptionParcelCallSender.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileCallbackExceptionParcelCallSender.java deleted file mode 100644 index cf63fd7..0000000 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileCallbackExceptionParcelCallSender.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.internal; - -import android.os.RemoteException; -import com.google.android.enterprise.connectedapps.ICrossProfileCallback; - -/** Implementation of {@link ParcelCallSender} used when passing a callback exception. */ -public class CrossProfileCallbackExceptionParcelCallSender extends ParcelCallSender { - - private final ICrossProfileCallback callback; - - public CrossProfileCallbackExceptionParcelCallSender(ICrossProfileCallback callback) { - if (callback == null) { - throw new NullPointerException("callback must not be null"); - } - this.callback = callback; - } - - /** Relays to {@link ICrossProfileCallback#prepareResult(long, int, int, byte[])} */ - @Override - void prepareCall(long callId, int blockId, int totalBytes, byte[] bytes) throws RemoteException { - callback.prepareResult(callId, blockId, totalBytes, bytes); - } - - /** - * Relays to {@link ICrossProfileCallback#onException(long, int, byte[])}}. - * - * <p>Always returns empty byte array. - */ - @Override - byte[] call(long callId, int blockId, byte[] bytes) throws RemoteException { - callback.onException(callId, blockId, bytes); - return new byte[0]; - } - - /** - * Callbacks cannot themselves return values, so this method will always throw an {@link - * IllegalStateException}. - */ - @Override - byte[] fetchResponse(long callId, int blockId) throws RemoteException { - throw new IllegalStateException(); - } -} diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileCallbackParcelCallSender.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileCallbackParcelCallSender.java deleted file mode 100644 index 5bd4b65..0000000 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileCallbackParcelCallSender.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.internal; - -import android.os.RemoteException; -import com.google.android.enterprise.connectedapps.ICrossProfileCallback; - -/** Implementation of {@link ParcelCallSender} used when passing a callback return value. */ -public class CrossProfileCallbackParcelCallSender extends ParcelCallSender { - - private final ICrossProfileCallback callback; - private final int methodIdentifier; - - public CrossProfileCallbackParcelCallSender( - ICrossProfileCallback callback, int methodIdentifier) { - if (callback == null) { - throw new NullPointerException("callback must not be null"); - } - this.callback = callback; - this.methodIdentifier = methodIdentifier; - } - - /** Relays to {@link ICrossProfileCallback#prepareResult(long, int, int, byte[])} */ - @Override - void prepareCall(long callId, int blockId, int totalBytes, byte[] bytes) throws RemoteException { - callback.prepareResult(callId, blockId, totalBytes, bytes); - } - - /** - * Relays to {@link ICrossProfileCallback#onResult(long, int, int, byte[])}. - * - * <p>Always returns empty byte array. - */ - @Override - byte[] call(long callId, int blockId, byte[] bytes) throws RemoteException { - callback.onResult(callId, blockId, methodIdentifier, bytes); - return new byte[0]; - } - - /** - * Callbacks cannot themselves return values, so this method will always throw an {@link - * IllegalStateException}. - */ - @Override - byte[] fetchResponse(long callId, int blockId) throws RemoteException { - throw new IllegalStateException(); - } -} diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileParcelCallSender.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileParcelCallSender.java deleted file mode 100644 index 3d66792..0000000 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/CrossProfileParcelCallSender.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.internal; - -import android.os.RemoteException; -import com.google.android.enterprise.connectedapps.ICrossProfileCallback; -import com.google.android.enterprise.connectedapps.ICrossProfileService; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * Implementation of {@link ParcelCallSender} used when making synchronous or asynchronous - * cross-profile calls. - */ -public final class CrossProfileParcelCallSender extends ParcelCallSender { - - private final ICrossProfileService wrappedService; - private final long crossProfileTypeIdentifier; - private final int methodIdentifier; - private final @Nullable ICrossProfileCallback callback; - - public CrossProfileParcelCallSender( - ICrossProfileService service, - long crossProfileTypeIdentifier, - int methodIdentifier, - @Nullable ICrossProfileCallback callback) { - if (service == null) { - throw new NullPointerException("service must not be null"); - } - - wrappedService = service; - this.crossProfileTypeIdentifier = crossProfileTypeIdentifier; - this.methodIdentifier = methodIdentifier; - this.callback = callback; - } - - @Override - void prepareCall(long callId, int blockId, int numBytes, byte[] params) throws RemoteException { - wrappedService.prepareCall(callId, blockId, numBytes, params); - } - - @Override - byte[] call(long callId, int blockId, byte[] params) throws RemoteException { - return wrappedService.call( - callId, blockId, crossProfileTypeIdentifier, methodIdentifier, params, callback); - } - - @Override - byte[] fetchResponse(long callId, int blockId) throws RemoteException { - return wrappedService.fetchResponse(callId, blockId); - } -} diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/ParcelCallReceiver.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/ParcelCallReceiver.java deleted file mode 100644 index e52386f..0000000 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/ParcelCallReceiver.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.internal; - -import android.os.Parcel; -import com.google.android.enterprise.connectedapps.CrossProfileSender; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -/** - * Build up parcels over multiple calls and prepare responses. - * - * <p>This is the counterpart to {@link ParcelCallSender}. Calls by the {@link ParcelCallSender} - * should be relayed to an instance of this class. - */ -public final class ParcelCallReceiver { - private final Map<Long, byte[]> preparedCalls = new HashMap<>(); - private final Map<Long, Integer> preparedCallParts = new HashMap<>(); - private final Map<Long, byte[]> preparedResponses = new HashMap<>(); - - /** - * Prepare a response to be returned by calls to {@link #getPreparedResponse(long, int)}. - * - * <p>The {@code byte[]} returned will begin with a 0 if all can be contained in a single call and - * 1 if further calls to {@link #getPreparedResponse(long, int)} are required. If the first byte - * is a 1, then the following 4 bytes will be an {@link Integer} representing the total number of - * bytes in the response. - * - * <p>The @{link Parcel} will not be recycled.</p> - */ - public byte[] prepareResponse(long callId, Parcel responseParcel) { - byte[] responseBytes = responseParcel.marshall(); - - if (responseBytes.length <= CrossProfileSender.MAX_BYTES_PER_BLOCK) { - // Prepend with 0 to indicate the bytes are complete - return ByteUtilities.joinByteArrays(new byte[] {0}, responseBytes); - } - // Record the bytes to be sent and send the first block - preparedResponses.put(callId, responseBytes); - byte[] response = new byte[CrossProfileSender.MAX_BYTES_PER_BLOCK + 5]; - // 1 = has additional content - response[0] = 1; - byte[] sizeBytes = ByteBuffer.allocate(4).putInt(responseBytes.length).array(); - System.arraycopy(sizeBytes, /* srcPos= */ 0, response, /* destPos= */ 1, /* length= */ 4); - System.arraycopy( - responseBytes, - /* srcPos= */ 0, - response, - /* destPos= */ 5, - /* length= */ CrossProfileSender.MAX_BYTES_PER_BLOCK); - return response; - } - - /** - * Prepare a call, storing one block of bytes for a call which will be completed with a call to - * {@link #getPreparedCall(long, int, byte[])}. - */ - public void prepareCall(long callId, int blockId, int numBytes, byte[] paramBytes) { - if (!preparedCalls.containsKey(callId)) { - preparedCalls.put(callId, new byte[numBytes]); - preparedCallParts.put(callId, 0); - } - System.arraycopy( - paramBytes, - /* srcPos= */ 0, - preparedCalls.get(callId), - /* destPos= */ blockId * CrossProfileSender.MAX_BYTES_PER_BLOCK, - /* length= */ CrossProfileSender.MAX_BYTES_PER_BLOCK); - preparedCallParts.put( - callId, - preparedCallParts.get(callId) - + 1 - + blockId); // +1 to have a difference when preparing the 0th block - } - - /** - * Fetch the full {@link Parcel using bytes previously stored by calls to - * {@link #prepareCall(long, int, int, byte[])}. - * - * <p>If this is the only block, then the {@code paramBytes} will be unmarshalled directly into a - * {@link Parcel}. - * - * <p>The returned {@link Parcel} must be recycled after use. - * - * @throws IllegalStateException If this is not the only block, and any previous blocks are - * missing. - */ - public Parcel getPreparedCall(long callId, int blockId, byte[] paramBytes) { - if (blockId > 0) { - int expectedBlocks = 0; - for (int i = 0; i < blockId; i++) { - expectedBlocks += 1 + i; - } - if (!preparedCallParts.containsKey(callId) - || expectedBlocks != preparedCallParts.get(callId)) { - throw new IllegalStateException("Call " + callId + " not prepared"); - } - byte[] fullParamBytes = preparedCalls.get(callId); - System.arraycopy( - paramBytes, - /* srcPos= */ 0, - fullParamBytes, - /* destPos= */ blockId * CrossProfileSender.MAX_BYTES_PER_BLOCK, - /* length= */ paramBytes.length); - paramBytes = fullParamBytes; - preparedCalls.remove(callId); - preparedCallParts.remove(callId); - } - - Parcel parcel = Parcel.obtain(); // Recycled by caller - parcel.unmarshall(paramBytes, 0, paramBytes.length); - parcel.setDataPosition(0); - return parcel; - } - - /** - * Get a block from a response previously prepared with {@link #prepareResponse(long, Parcel)}. - * - * <p>If this is the final block, then the prepared blocks will be dropped, and future calls to - * this method will fail. - */ - public byte[] getPreparedResponse(long callId, int blockId) { - byte[] preparedBytes = preparedResponses.get(callId); - byte[] response = - Arrays.copyOfRange( - preparedBytes, - /* from= */ blockId * CrossProfileSender.MAX_BYTES_PER_BLOCK, - /* to= */ Math.min( - preparedBytes.length, (blockId + 1) * CrossProfileSender.MAX_BYTES_PER_BLOCK)); - int numberOfBlocks = - (int) Math.ceil(preparedBytes.length * 1.0 / CrossProfileSender.MAX_BYTES_PER_BLOCK); - if (blockId == numberOfBlocks - 1) { - preparedResponses.remove(callId); - } - return response; - } -} diff --git a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/ParcelCallSender.java b/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/ParcelCallSender.java deleted file mode 100644 index a5b729a..0000000 --- a/sdk/src/main/java/com/google/android/enterprise/connectedapps/internal/ParcelCallSender.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.internal; - -import static com.google.android.enterprise.connectedapps.CrossProfileSender.MAX_BYTES_PER_BLOCK; - -import android.os.Parcel; -import android.os.RemoteException; -import android.os.TransactionTooLargeException; -import android.util.Log; -import com.google.android.enterprise.connectedapps.exceptions.UnavailableProfileException; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.UUID; - -/** - * This represents a single action of (sending a {@link Parcel} and possibly fetching a response, - * which may be split up over many calls (if the payload is large). - * - * <p>The receiver should relay calls to a {@link ParcelCallReceiver}. - */ -abstract class ParcelCallSender { - - private static final long RETRY_DELAY_MILLIS = 10; - private static final int MAX_RETRIES = 10; - - /** - * The arguments passed to this should be passed to {@link ParcelCallReceiver#prepareCall(long, - * int, int, byte[])}. - */ - abstract void prepareCall(long callId, int blockId, int totalBytes, byte[] bytes) - throws RemoteException; - - private void prepareCallAndRetry( - long callId, int blockId, int totalBytes, byte[] bytes, int retries) throws RemoteException { - while (true) { - try { - prepareCall(callId, blockId, totalBytes, bytes); - break; - } catch (TransactionTooLargeException e) { - if (retries-- <= 0) { - throw e; - } - - try { - Thread.sleep(RETRY_DELAY_MILLIS); - } catch (InterruptedException ex) { - Log.w("ParcelCallSender", "Interrupted on prepare retry", ex); - // If we can't sleep we'll just try again immediately - } - } - } - } - - /** - * The arguments passed to this should be passed to {@link - * ParcelCallReceiver#getPreparedCall(long, int, byte[])} and used to complete the call. - */ - abstract byte[] call(long callId, int blockId, byte[] bytes) throws RemoteException; - - private byte[] callAndRetry(long callId, int blockId, byte[] bytes, int retries) - throws RemoteException { - while (true) { - try { - return call(callId, blockId, bytes); - } catch (TransactionTooLargeException e) { - if (retries-- <= 0) { - throw e; - } - - try { - Thread.sleep(RETRY_DELAY_MILLIS); - } catch (InterruptedException ex) { - Log.w("ParcelCallSender", "Interrupted on prepare retry", ex); - // If we can't sleep we'll just try again immediately - } - } - } - } - - /** - * The arguments passed to this should be passed to {@link - * ParcelCallReceiver#getPreparedResponse(long, int)}. - */ - abstract byte[] fetchResponse(long callId, int blockId) throws RemoteException; - - private byte[] fetchResponseAndRetry(long callId, int blockId, int retries) - throws RemoteException { - while (true) { - try { - return fetchResponse(callId, blockId); - } catch (TransactionTooLargeException e) { - if (retries-- <= 0) { - throw e; - } - - try { - Thread.sleep(RETRY_DELAY_MILLIS); - } catch (InterruptedException ex) { - Log.w("ParcelCallSender", "Interrupted on prepare retry", ex); - // If we can't sleep we'll just try again immediately - } - } - } - } - - /** - * Use the prepareCall(long, int, int, byte[])} and {@link #call(long, int, byte[])} methods to - * make a call. - * - * <p>The returned {@link Parcel} must be recycled after use. - * - * <p>Returns {@code null} if the call does not return anything - * - * @throws UnavailableProfileException if any call fails - */ - public Parcel makeParcelCall(Parcel parcel) throws UnavailableProfileException { - long callIdentifier = UUID.randomUUID().getMostSignificantBits(); - byte[] bytes = parcel.marshall(); - try { - int numberOfBlocks = (int) Math.ceil(bytes.length * 1.0 / MAX_BYTES_PER_BLOCK); - int blockIdentifier = 0; - - if (numberOfBlocks > 1) { - byte[] block = new byte[MAX_BYTES_PER_BLOCK]; - - // Loop through all but the last one and send them over to be cached (retrying any failures) - while (blockIdentifier < numberOfBlocks - 1) { - System.arraycopy( - bytes, blockIdentifier * MAX_BYTES_PER_BLOCK, block, 0, MAX_BYTES_PER_BLOCK); - - // Since we know block size is below the limit any errors will be temporary so we should - // retry - prepareCallAndRetry(callIdentifier, blockIdentifier, bytes.length, block, MAX_RETRIES); - blockIdentifier++; - } - - bytes = Arrays.copyOfRange(bytes, blockIdentifier * MAX_BYTES_PER_BLOCK, bytes.length); - } - - // Since we know block size is below the limit any errors will be temporary so we should retry - byte[] returnBytes = callAndRetry(callIdentifier, blockIdentifier, bytes, MAX_RETRIES); - - if (returnBytes.length == 0) { - return null; - } - - return fetchResponseParcel(callIdentifier, returnBytes); - } catch (RemoteException e) { - throw new UnavailableProfileException("Could not access other profile", e); - } - } - - /** - * Use the {@link ParcelCallSender#prepareCall(long, int, int, byte[])} and {@link - * ParcelCallSender#fetchResponse(long, int)} methods to fetch a prepared response. - * - * <p>The returned {@link Parcel} must be recycled after use. - * - * @throws UnavailableProfileException if any call fails - */ - private Parcel fetchResponseParcel(long callIdentifier, byte[] returnBytes) - throws UnavailableProfileException { - - // returnBytes[0] is 0 if the bytes are complete, or 1 if we need to fetch more - int byteOffset = 1; - if (returnBytes[0] == 1) { - // returnBytes[1] - returnBytes[4] are an int representing the total size of the return - // value - int totalBytes = ByteBuffer.wrap(returnBytes).getInt(/* index= */ 1); - - try { - returnBytes = fetchReturnBytes(totalBytes, callIdentifier, returnBytes); - } catch (RemoteException e) { - throw new UnavailableProfileException("Could not access other profile", e); - } - byteOffset = 0; - } - Parcel p = Parcel.obtain(); // Recycled by caller - p.unmarshall( - returnBytes, /* offset= */ byteOffset, /* length= */ returnBytes.length - byteOffset); - p.setDataPosition(0); - return p; - } - - private byte[] fetchReturnBytes(int totalBytes, long callId, byte[] initialBytes) - throws RemoteException { - byte[] returnBytes = new byte[totalBytes]; - - // Skip the first 5 bytes which are used for status - System.arraycopy( - initialBytes, - /* srcPos= */ 5, - returnBytes, - /* destPos= */ 0, - /* length= */ MAX_BYTES_PER_BLOCK); - - int numberOfBlocks = (int) Math.ceil(totalBytes * 1.0 / MAX_BYTES_PER_BLOCK); - - for (int block = 1; block < numberOfBlocks; block++) { // Skip 0 as we already have it - // Since we know block size is below the limit any errors will be temporary so we should retry - byte[] bytes = fetchResponseAndRetry(callId, block, MAX_RETRIES); - System.arraycopy( - bytes, - /* srcPos= */ 0, - returnBytes, - /* destPos= */ block * MAX_BYTES_PER_BLOCK, - /* length= */ bytes.length); - } - return returnBytes; - } -} diff --git a/testing/sdk/src/main/java/com/google/android/enterprise/connectedapps/testing/FakePermissions.java b/testing/sdk/src/main/java/com/google/android/enterprise/connectedapps/testing/FakePermissions.java deleted file mode 100644 index 763b67c..0000000 --- a/testing/sdk/src/main/java/com/google/android/enterprise/connectedapps/testing/FakePermissions.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.testing; - -import com.google.android.enterprise.connectedapps.Permissions; - -class FakePermissions implements Permissions { - - private final AbstractFakeProfileConnector fakeProfileConnector; - - FakePermissions(AbstractFakeProfileConnector fakeProfileConnector) { - this.fakeProfileConnector = fakeProfileConnector; - } - - @Override - public boolean canMakeCrossProfileCalls() { - return fakeProfileConnector.hasPermissionToMakeCrossProfileCalls(); - } -} diff --git a/tests/instrumented/src/main/java/com/google/android/enterprise/connectedapps/instrumented/tests/BothProfilesTest.java b/tests/instrumented/src/main/java/com/google/android/enterprise/connectedapps/instrumented/tests/BothProfilesTest.java deleted file mode 100644 index 8b15d35..0000000 --- a/tests/instrumented/src/main/java/com/google/android/enterprise/connectedapps/instrumented/tests/BothProfilesTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.instrumented.tests; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Application; -import androidx.test.core.app.ApplicationProvider; -import com.google.android.enterprise.connectedapps.Profile; -import com.google.android.enterprise.connectedapps.instrumented.utils.BlockingStringCallbackListenerMulti; -import com.google.android.enterprise.connectedapps.instrumented.utils.InstrumentedTestUtilities; -import com.google.android.enterprise.connectedapps.testapp.connector.TestProfileConnector; -import com.google.android.enterprise.connectedapps.testapp.types.ProfileTestCrossProfileTypeWhichNeedsContext; -import java.util.Map; -import java.util.concurrent.ExecutionException; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests regarding calling a method on both profiles. */ -@RunWith(JUnit4.class) -public class BothProfilesTest { - private static final int FIVE_SECONDS = 5000; - private static final String STRING = "String"; - - private static final Application context = ApplicationProvider.getApplicationContext(); - - private static final TestProfileConnector connector = TestProfileConnector.create(context); - private static final InstrumentedTestUtilities utilities = - new InstrumentedTestUtilities(context, connector); - - private final ProfileTestCrossProfileTypeWhichNeedsContext type = - ProfileTestCrossProfileTypeWhichNeedsContext.create(connector); - - @Before - public void setup() { - utilities.ensureReadyForCrossProfileCalls(); - } - - @AfterClass - public static void teardown() { - utilities.ensureNoWorkProfile(); - } - - /** This test could not be covered by Robolectric. */ - @Test - public void both_synchronous_timesOutOnWorkProfile_timeoutNotEnforcedOnSynchronousCalls() { - utilities.manuallyConnectAndWait(); - - Map<Profile, String> result = - type.both() - .timeout(FIVE_SECONDS) - .identityStringMethodWhichDelays10SecondsOnWorkProfile(STRING); - - assertThat(result).containsKey(connector.utils().getPersonalProfile()); - assertThat(result).containsKey(connector.utils().getWorkProfile()); - } - - /** This test could not be covered by Robolectric. */ - @Test - public void both_async_timesOutOnWorkProfile_onlyIncludesPersonalProfile() - throws InterruptedException { - - BlockingStringCallbackListenerMulti callbackListener = - new BlockingStringCallbackListenerMulti(); - - type.both() - .timeout(FIVE_SECONDS) - .asyncIdentityStringMethodWhichDelays10SecondsOnWorkProfile(STRING, callbackListener); - Map<Profile, String> result = callbackListener.await(); - - assertThat(result).containsKey(connector.utils().getPersonalProfile()); - assertThat(result).doesNotContainKey(connector.utils().getWorkProfile()); - } - - /** This test could not be covered by Robolectric. */ - @Test - public void both_future_timesOutOnWorkProfile_onlyIncludesPersonalProfile() - throws InterruptedException, ExecutionException { - Map<Profile, String> result = - type.both() - .timeout(FIVE_SECONDS) - .futureIdentityStringMethodWhichDelays10SecondsOnWorkProfile(STRING) - .get(); - - assertThat(result).containsKey(connector.utils().getPersonalProfile()); - assertThat(result).doesNotContainKey(connector.utils().getWorkProfile()); - } -} diff --git a/tests/robotests/src/test/java/com/google/android/enterprise/connectedapps/internal/ParcelCallSenderTest.java b/tests/robotests/src/test/java/com/google/android/enterprise/connectedapps/internal/ParcelCallSenderTest.java deleted file mode 100644 index dd39fa1..0000000 --- a/tests/robotests/src/test/java/com/google/android/enterprise/connectedapps/internal/ParcelCallSenderTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.internal; - -import static com.google.android.enterprise.connectedapps.StringUtilities.randomString; -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertThrows; - -import android.os.Parcel; -import android.os.RemoteException; -import android.os.TransactionTooLargeException; -import com.google.android.enterprise.connectedapps.exceptions.UnavailableProfileException; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -public class ParcelCallSenderTest { - - static class TestParcelCallSender extends ParcelCallSender { - - int failPrepareCalls = 0; - int failCalls = 0; - int failFetchResponse = 0; - - private final ParcelCallReceiver parcelCallReceiver = new ParcelCallReceiver(); - - @Override - void prepareCall(long callId, int blockId, int totalBytes, byte[] bytes) - throws RemoteException { - if (failPrepareCalls-- > 0) { - throw new TransactionTooLargeException(); - } - - parcelCallReceiver.prepareCall(callId, blockId, totalBytes, bytes); - } - - @Override - byte[] call(long callId, int blockId, byte[] bytes) throws RemoteException { - if (failCalls-- > 0) { - throw new TransactionTooLargeException(); - } - - return parcelCallReceiver.prepareResponse( - callId, parcelCallReceiver.getPreparedCall(callId, blockId, bytes)); - } - - @Override - byte[] fetchResponse(long callId, int blockId) throws RemoteException { - if (failFetchResponse-- > 0) { - throw new TransactionTooLargeException(); - } - - return parcelCallReceiver.getPreparedResponse(callId, blockId); - } - } - - private final TestParcelCallSender parcelCallSender = new TestParcelCallSender(); - private static final String LARGE_STRING = randomString(1500000); // 3Mb - private static final Parcel LARGE_PARCEL = Parcel.obtain(); - - static { - LARGE_PARCEL.writeString(LARGE_STRING); - } - - @Test - public void makeParcelCall_prepareCallHasError_retriesUntilSuccess() - throws UnavailableProfileException { - parcelCallSender.failPrepareCalls = 5; - - assertThat(parcelCallSender.makeParcelCall(LARGE_PARCEL).readString()).isEqualTo(LARGE_STRING); - } - - @Test - public void makeParcelCall_prepareCallHasError_failsAfter10Retries() { - parcelCallSender.failPrepareCalls = 11; - - assertThrows( - UnavailableProfileException.class, () -> parcelCallSender.makeParcelCall(LARGE_PARCEL)); - } - - @Test - public void makeParcelCall_callHasError_retriesUntilSuccess() throws UnavailableProfileException { - parcelCallSender.failCalls = 5; - - assertThat(parcelCallSender.makeParcelCall(LARGE_PARCEL).readString()).isEqualTo(LARGE_STRING); - } - - @Test - public void makeParcelCall_callHasError_failsAfter10Retries() { - parcelCallSender.failCalls = 11; - - assertThrows( - UnavailableProfileException.class, () -> parcelCallSender.makeParcelCall(LARGE_PARCEL)); - } - - @Test - public void makeParcelCall_fetchResponseHasError_retriesUntilSuccess() - throws UnavailableProfileException { - parcelCallSender.failFetchResponse = 5; - - assertThat(parcelCallSender.makeParcelCall(LARGE_PARCEL).readString()).isEqualTo(LARGE_STRING); - } - - @Test - public void makeParcelCall_fetchResponseHasError_failsAfter10Retries() { - parcelCallSender.failFetchResponse = 11; - - assertThrows( - UnavailableProfileException.class, () -> parcelCallSender.makeParcelCall(LARGE_PARCEL)); - } -} diff --git a/tests/robotests/src/test/java/com/google/android/enterprise/connectedapps/robotests/CrossUserTest.java b/tests/robotests/src/test/java/com/google/android/enterprise/connectedapps/robotests/CrossUserTest.java deleted file mode 100644 index 10b7d1f..0000000 --- a/tests/robotests/src/test/java/com/google/android/enterprise/connectedapps/robotests/CrossUserTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.robotests; - -import static com.google.android.enterprise.connectedapps.SharedTestUtilities.INTERACT_ACROSS_USERS; -import static com.google.common.truth.Truth.assertThat; - -import android.app.Application; -import android.app.Service; -import android.os.Build.VERSION_CODES; -import android.os.IBinder; -import androidx.test.core.app.ApplicationProvider; -import com.google.android.enterprise.connectedapps.RobolectricTestUtilities; -import com.google.android.enterprise.connectedapps.TestScheduledExecutorService; -import com.google.android.enterprise.connectedapps.testapp.crossuser.ProfileTestCrossUserType; -import com.google.android.enterprise.connectedapps.testapp.crossuser.TestCrossUserConfiguration; -import com.google.android.enterprise.connectedapps.testapp.crossuser.TestCrossUserConnector; -import com.google.android.enterprise.connectedapps.testapp.crossuser.TestCrossUserStringCallbackListenerImpl; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -@Config(minSdk = VERSION_CODES.O) -public class CrossUserTest { - - private static final String STRING = "String"; - - private final Application context = ApplicationProvider.getApplicationContext(); - private final TestScheduledExecutorService scheduledExecutorService = - new TestScheduledExecutorService(); - private final TestCrossUserConnector testCrossUserConnector = - TestCrossUserConnector.create(context, scheduledExecutorService); - private final RobolectricTestUtilities testUtilities = - new RobolectricTestUtilities(testCrossUserConnector, scheduledExecutorService); - private final ProfileTestCrossUserType profileCrossUserType = - ProfileTestCrossUserType.create(testCrossUserConnector); - private final TestCrossUserStringCallbackListenerImpl crossUserStringCallback = - new TestCrossUserStringCallbackListenerImpl(); - - @Before - public void setUp() { - Service profileAwareService = Robolectric.setupService(TestCrossUserConfiguration.getService()); - testUtilities.initTests(); - IBinder binder = profileAwareService.onBind(/* intent= */ null); - testUtilities.setBinding(binder, TestCrossUserConnector.class.getName()); - testUtilities.createWorkUser(); - testUtilities.turnOnWorkProfile(); - testUtilities.setRunningOnPersonalProfile(); - testUtilities.setRequestsPermissions(INTERACT_ACROSS_USERS); - testUtilities.grantPermissions(INTERACT_ACROSS_USERS); - testCrossUserConnector.stopManualConnectionManagement(); - } - - @Test - // This test covers all CrossUser annotations - public void passArgumentToCallback_works() { - testUtilities.turnOnWorkProfile(); - testUtilities.startConnectingAndWait(); - - profileCrossUserType.current().passString(STRING, crossUserStringCallback); - - assertThat(crossUserStringCallback.stringCallbackValue).isEqualTo(STRING); - } -} diff --git a/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/crossuser/TestCrossUserConfiguration.java b/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/crossuser/TestCrossUserConfiguration.java deleted file mode 100644 index f8ac4e8..0000000 --- a/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/crossuser/TestCrossUserConfiguration.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.testapp.crossuser; - -import android.app.Service; -import com.google.android.enterprise.connectedapps.annotations.CrossUserConfiguration; -import com.google.android.enterprise.connectedapps.annotations.CrossUserConfigurations; - -@CrossUserConfigurations(@CrossUserConfiguration(providers = TestCrossUserProvider.class)) -public abstract class TestCrossUserConfiguration { - - // This is available so the test targets can access the generated Service class. - public static Class<? extends Service> getService() { - return TestCrossUserConnector_Service.class; - } - - private TestCrossUserConfiguration() {} -} diff --git a/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/crossuser/TestCrossUserConnector.java b/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/crossuser/TestCrossUserConnector.java deleted file mode 100644 index 72c3a8c..0000000 --- a/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/crossuser/TestCrossUserConnector.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.testapp.crossuser; - -import android.content.Context; -import com.google.android.enterprise.connectedapps.ProfileConnector; -import com.google.android.enterprise.connectedapps.annotations.CustomProfileConnector; -import com.google.android.enterprise.connectedapps.annotations.CustomProfileConnector.ProfileType; -import com.google.android.enterprise.connectedapps.annotations.GeneratedProfileConnector; -import java.util.concurrent.ScheduledExecutorService; - -@GeneratedProfileConnector -@CustomProfileConnector(primaryProfile = ProfileType.WORK) -public interface TestCrossUserConnector extends ProfileConnector { - static TestCrossUserConnector create(Context context) { - return GeneratedTestCrossUserConnector.builder(context).build(); - } - - static TestCrossUserConnector create( - Context context, ScheduledExecutorService scheduledExecutorService) { - return GeneratedTestCrossUserConnector.builder(context) - .setScheduledExecutorService(scheduledExecutorService) - .build(); - } -} diff --git a/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/types/TestInterfaceProvider.java b/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/types/TestInterfaceProvider.java deleted file mode 100644 index 06c01ba..0000000 --- a/tests/shared/src/main/java/com/google/android/enterprise/connectedapps/testapp/types/TestInterfaceProvider.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.enterprise.connectedapps.testapp.types; - -import com.google.android.enterprise.connectedapps.annotations.CrossProfileProvider; - -public class TestInterfaceProvider { - - @CrossProfileProvider - public TestCrossProfileInterface provideCrossProfileInterface() { - return s -> s; - } -} |