diff --git a/services/CHANGELOG.md b/services/CHANGELOG.md index 5f06775b0..a0a81195e 100644 --- a/services/CHANGELOG.md +++ b/services/CHANGELOG.md @@ -2,14 +2,21 @@ {{date}} + `androidx.test.services:test-services:{version}` `androidx.test.services:storage:{version}` are released. **Bug Fixes** +* Ensure TestStorage library is multi-linux-user compatible. + **New Features** **Breaking Changes** +* The location where TestStorage stores files has changed. This is non-breaking +if using the TestStorage API, but breaking if tests depended on the explicit +location of the files (e.g., by reading them without using TestStorage). + **API Changes** * Update to minSdkVersion 23 and remove all related logic for SDKs < 23 diff --git a/services/storage/java/androidx/test/services/storage/file/BUILD b/services/storage/java/androidx/test/services/storage/file/BUILD index 3100f6ee4..b8b498637 100644 --- a/services/storage/java/androidx/test/services/storage/file/BUILD +++ b/services/storage/java/androidx/test/services/storage/file/BUILD @@ -15,7 +15,6 @@ android_library( name = "file", srcs = glob(["*.java"]), deps = [ - "//opensource/androidx:annotation", "//runner/monitor", "//services/storage/java/androidx/test/services/storage:test_storage_constants", ], diff --git a/services/storage/java/androidx/test/services/storage/file/HostedFile.java b/services/storage/java/androidx/test/services/storage/file/HostedFile.java index 2f331a290..459adecc7 100644 --- a/services/storage/java/androidx/test/services/storage/file/HostedFile.java +++ b/services/storage/java/androidx/test/services/storage/file/HostedFile.java @@ -17,13 +17,11 @@ import android.content.Context; import android.net.Uri; +import android.os.Build; import android.os.Environment; -import android.os.UserManager; import android.provider.OpenableColumns; -import android.util.Log; import androidx.test.services.storage.TestStorageConstants; import java.io.File; -import java.util.concurrent.atomic.AtomicBoolean; import androidx.annotation.RestrictTo; import androidx.annotation.RestrictTo.Scope; @@ -38,8 +36,6 @@ public final class HostedFile { private static final String TAG = "HostedFile"; - private static final AtomicBoolean loggedOutputDir = new AtomicBoolean(false); - /** An enum of the columns returned by the hosted file service. */ public enum HostedFileColumn { NAME("name", String.class, 3 /* Cursor.FIELD_TYPE_STRING since api 11 */, 0), @@ -152,20 +148,11 @@ public static File getInputRootDirectory(Context context) { } public static File getOutputRootDirectory(Context context) { - UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); - if (userManager.isSystemUser()) { - return Environment.getExternalStorageDirectory(); + // Use a reliably self-writable directory. + if (Build.VERSION.SDK_INT >= 29) { + return context.getExternalFilesDir(null); } else { - // using legacy external storage for output in automotive devices where tests run as - // a secondary user has been flaky. So use local storage instead. - if (!loggedOutputDir.getAndSet(true)) { - // limit log spam by only logging choice once - Log.d( - TAG, - "Secondary user detected. Choosing local storage as output root dir: " - + context.getCacheDir().getAbsolutePath()); - } - return context.getCacheDir(); + return Environment.getExternalStorageDirectory(); } } diff --git a/services/storage/java/androidx/test/services/storage/provider/BUILD b/services/storage/java/androidx/test/services/storage/provider/BUILD index 4bb3cc8ca..e76da53a8 100644 --- a/services/storage/java/androidx/test/services/storage/provider/BUILD +++ b/services/storage/java/androidx/test/services/storage/provider/BUILD @@ -15,6 +15,7 @@ android_library( manifest = "AndroidManifest.xml", deps = [ "//runner/monitor", + "//services/storage", "//services/storage/java/androidx/test/services/storage:storage_service_pb_java_proto_lite", "//services/storage/java/androidx/test/services/storage:test_storage_constants", "//services/storage/java/androidx/test/services/storage/file", diff --git a/services/storage/java/androidx/test/services/storage/provider/InternalUseOnlyFilesContentProvider.java b/services/storage/java/androidx/test/services/storage/provider/InternalUseOnlyFilesContentProvider.java index eab13bbb1..2c47761f6 100644 --- a/services/storage/java/androidx/test/services/storage/provider/InternalUseOnlyFilesContentProvider.java +++ b/services/storage/java/androidx/test/services/storage/provider/InternalUseOnlyFilesContentProvider.java @@ -25,9 +25,10 @@ public final class InternalUseOnlyFilesContentProvider extends AbstractFileConte @Override protected File getHostedDirectory(Context context) { - // use input root directory here, as TestArgsContentProvider also uses this directory + // Uses the output root directory since the provider is Read/Write and only the output directory + // is guaranteed to be writable. return new File( - HostedFile.getInputRootDirectory(context), + HostedFile.getOutputRootDirectory(context), TestStorageConstants.ON_DEVICE_PATH_INTERNAL_USE); } diff --git a/services/storage/java/androidx/test/services/storage/provider/TestArgsContentProvider.java b/services/storage/java/androidx/test/services/storage/provider/TestArgsContentProvider.java index c3add1ad7..6d809ad0c 100644 --- a/services/storage/java/androidx/test/services/storage/provider/TestArgsContentProvider.java +++ b/services/storage/java/androidx/test/services/storage/provider/TestArgsContentProvider.java @@ -25,15 +25,18 @@ import android.net.Uri; import android.util.Log; import androidx.test.services.storage.TestStorageConstants; +import androidx.test.services.storage.TestStorageException; import androidx.test.services.storage.TestStorageServiceProto.TestArgument; import androidx.test.services.storage.TestStorageServiceProto.TestArguments; import androidx.test.services.storage.file.HostedFile; +import androidx.test.services.storage.file.HostedFile.FileHost; import androidx.test.services.storage.file.PropertyFile; import androidx.test.services.storage.file.PropertyFile.Authority; +import androidx.test.services.storage.internal.TestStorageUtil; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.lang.reflect.Method; +import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -48,17 +51,6 @@ public final class TestArgsContentProvider extends ContentProvider { private static final String TAG = "TestArgCP"; - private static final String ANDROID_TEST_SERVER_SPEC_FORMAT = "_server_address"; - - private static final String SYSTEM_PROPERTY_CLAZZ = "android.os.SystemProperties"; - private static final String GET_METHOD = "get"; - - private String systemPropertyClassName; - private Method getString; - - void setSystemPropertyClassNameForTest(String className) { - this.systemPropertyClassName = className; - } @Override public int delete(Uri arg0, String arg1, String[] arg2) { @@ -119,13 +111,28 @@ private Map buildArgMapFromFile() { } private static TestArguments readProtoFromFile(Context context) { + // File written by the InternalUseOnlyFilesContentProvider + Uri testArgsProtoUri = + HostedFile.buildUri(FileHost.INTERNAL_USE_ONLY, TestStorageConstants.TEST_ARGS_FILE_NAME); + + try (InputStream testArgsProtoInputStream = + TestStorageUtil.getInputStream(testArgsProtoUri, context.getContentResolver())) { + Log.i(TAG, "Parsing test args from URI: " + testArgsProtoUri); + return TestArguments.parseFrom(testArgsProtoInputStream); + } catch (IOException | TestStorageException e) { + Log.i( + TAG, + "Test args file not found via URI: " + testArgsProtoUri + ". Checking file system..."); + } + + // File written directly to /sdcard/ File testArgsFile = new File( HostedFile.getInputRootDirectory(context), TestStorageConstants.ON_DEVICE_PATH_INTERNAL_USE + TestStorageConstants.TEST_ARGS_FILE_NAME); if (!testArgsFile.exists()) { - Log.i(TAG, "Test args file not found at " + testArgsFile.getAbsolutePath()); + Log.i(TAG, "Test args file also not found at " + testArgsFile.getAbsolutePath()); return TestArguments.getDefaultInstance(); } try { diff --git a/services/storage/javatests/androidx/test/services/storage/BUILD b/services/storage/javatests/androidx/test/services/storage/BUILD index b817713a5..24b05f73a 100644 --- a/services/storage/javatests/androidx/test/services/storage/BUILD +++ b/services/storage/javatests/androidx/test/services/storage/BUILD @@ -30,7 +30,6 @@ axt_android_library_test( ], deps = [ "//core/java/androidx/test/core", - "//runner/monitor/java/androidx/test:monitor", "//services/storage/java/androidx/test/services/storage", "//services/storage/java/androidx/test/services/storage/file", "@maven//:com_google_truth_truth", diff --git a/services/storage/javatests/androidx/test/services/storage/TestStorageTest.java b/services/storage/javatests/androidx/test/services/storage/TestStorageTest.java index 3b3e1d49b..66d7935f1 100644 --- a/services/storage/javatests/androidx/test/services/storage/TestStorageTest.java +++ b/services/storage/javatests/androidx/test/services/storage/TestStorageTest.java @@ -19,11 +19,8 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.TestCase.fail; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeTrue; -import android.content.Context; import android.net.Uri; -import android.os.UserManager; import androidx.test.services.storage.file.HostedFile; import androidx.test.services.storage.internal.TestStorageUtil; import java.io.BufferedReader; @@ -113,19 +110,11 @@ public void addOutputProperties() throws Exception { @Test public void writeInternalFile() throws IOException { - // known not to work in multi-user mode - assumeTrue(isSystemUser()); try (OutputStream output = testStorage.openInternalOutputFile("path/to/file")) { output.write(new byte[] {'h', 'e', 'l', 'l', 'o'}); } } - private static boolean isSystemUser() { - - UserManager um = ((UserManager) getApplicationContext().getSystemService(Context.USER_SERVICE)); - return um.isSystemUser(); - } - @Test public void readWriteOverwriteReadFile() throws IOException { try (OutputStream output = testStorage.openOutputFile("path/to/file")) { diff --git a/services/storage/javatests/androidx/test/services/storage/provider/TestArgsContentProviderTest.java b/services/storage/javatests/androidx/test/services/storage/provider/TestArgsContentProviderTest.java index 70cb7e78e..5284747b6 100644 --- a/services/storage/javatests/androidx/test/services/storage/provider/TestArgsContentProviderTest.java +++ b/services/storage/javatests/androidx/test/services/storage/provider/TestArgsContentProviderTest.java @@ -31,11 +31,7 @@ import java.util.HashMap; import java.util.Map; -/** - * Unit tests for {@link TestArgsContentProvider}. - * - * TODO(b/145236542): Converts the tests to JUnit4. - */ +/** Unit tests for {@link TestArgsContentProvider}. */ public class TestArgsContentProviderTest extends ProviderTestCase2 { private static final String[] ARGS = {"arg1", "arg2", "arg3", "someth_server_address"}; @@ -50,7 +46,6 @@ public TestArgsContentProviderTest() { @Override public void setUp() throws Exception { super.setUp(); - getProvider().setSystemPropertyClassNameForTest(FakeSystemProperties.class.getName()); } @Override