Ensure Content Provider is functional

Content provider can only really be used at API 28 and
above.
Also check stdout for [ERROR] to avoid reporting success
when it's not.

Bug: 123529934
Test: unit tests
Bug: 130131891
Change-Id: I676f677f596e2080e2ae155b2e46e11e7b4003e8
Merged-In: I676f677f596e2080e2ae155b2e46e11e7b4003e8
diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java
index 184dfd5..8857952 100644
--- a/src/com/android/tradefed/device/NativeDevice.java
+++ b/src/com/android/tradefed/device/NativeDevice.java
@@ -4191,8 +4191,9 @@
         if (!getOptions().shouldUseContentProvider()) {
             return null;
         }
-        // Prevent usage of content provider before API 25 as it would not work well.
-        if (getApiLevel() < 25) {
+        // Prevent usage of content provider before API 28 as it would not work well since content
+        // tool is not working before P.
+        if (getApiLevel() < 28) {
             return null;
         }
         if (mContentProvider == null) {
diff --git a/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java b/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java
index 4c966a6..e061ab2 100644
--- a/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java
+++ b/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java
@@ -49,6 +49,7 @@
     public static final String CONTENT_PROVIDER_URI = "content://android.tradefed.contentprovider";
     private static final String APK_NAME = "TradefedContentProvider.apk";
     private static final String CONTENT_PROVIDER_APK_RES = "/apks/contentprovider/" + APK_NAME;
+    private static final String ERROR_MESSAGE_TAG = "[ERROR]";
 
     private ITestDevice mDevice;
     private File mContentProviderApk = null;
@@ -113,7 +114,7 @@
                         "content delete --user %d --uri %s", mDevice.getCurrentUser(), contentUri);
         CommandResult deleteResult = mDevice.executeShellV2Command(deleteCommand);
 
-        if (CommandStatus.SUCCESS.equals(deleteResult.getStatus())) {
+        if (isSuccessful(deleteResult)) {
             return true;
         }
         CLog.e(
@@ -199,8 +200,15 @@
 
     /** Returns true if {@link CommandStatus} is successful and there is no error message. */
     private boolean isSuccessful(CommandResult result) {
+        if (!CommandStatus.SUCCESS.equals(result.getStatus())) {
+            return false;
+        }
+        String stdout = result.getStdout();
+        if (stdout.contains(ERROR_MESSAGE_TAG)) {
+            return false;
+        }
         String stderr = result.getStderr();
-        return CommandStatus.SUCCESS.equals(result.getStatus()) && Strings.isNullOrEmpty(stderr);
+        return Strings.isNullOrEmpty(stderr);
     }
 
     /** Helper method to extract the content provider apk. */
diff --git a/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java b/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java
index 6532a5f..9e9c463 100644
--- a/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java
+++ b/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java
@@ -109,6 +109,7 @@
     public void testDeleteFile_fail() throws Exception {
         String devicePath = "path/somewhere/file.txt";
         CommandResult result = new CommandResult(CommandStatus.FAILED);
+        result.setStdout("");
         result.setStderr("couldn't find the file");
         doReturn(99).when(mMockDevice).getCurrentUser();
         doReturn(result)
@@ -121,6 +122,23 @@
         assertFalse(mProvider.deleteFile(devicePath));
     }
 
+    /** Test {@link ContentProviderHandler#deleteFile(String)}. */
+    @Test
+    public void testError() throws Exception {
+        String devicePath = "path/somewhere/file.txt";
+        CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+        result.setStdout("[ERROR] Unsupported operation: delete");
+        doReturn(99).when(mMockDevice).getCurrentUser();
+        doReturn(result)
+                .when(mMockDevice)
+                .executeShellV2Command(
+                        eq(
+                                "content delete --user 99 --uri "
+                                        + ContentProviderHandler.createEscapedContentUri(
+                                                devicePath)));
+        assertFalse(mProvider.deleteFile(devicePath));
+    }
+
     /** Test {@link ContentProviderHandler#pushFile(File, String)}. */
     @Test
     public void testPushFile() throws Exception {
@@ -212,6 +230,7 @@
     private CommandResult mockSuccess() {
         CommandResult result = new CommandResult(CommandStatus.SUCCESS);
         result.setStderr("");
+        result.setStdout("");
         return result;
     }