Skip empty slice permissions files during backup

Test: adb shell bmgr backupnow --monitor-verbose android
  (make sure this finishes quickly & does not get stuck
  in an infinite loop)
Test: atest frameworks/base/services/tests/uiservicestests/src/com/android/server/slice
Change-Id: Ieb701c7ed764c005c8a8517a9411edd8c36023f0
Fixes: 120904478
(cherry picked from commit e731681f4f1d013bfcca6158d69b67c1ad455572)
diff --git a/services/core/java/com/android/server/slice/SlicePermissionManager.java b/services/core/java/com/android/server/slice/SlicePermissionManager.java
index 315d5e3..1d1c28f 100644
--- a/services/core/java/com/android/server/slice/SlicePermissionManager.java
+++ b/services/core/java/com/android/server/slice/SlicePermissionManager.java
@@ -175,18 +175,24 @@
                 handlePersist();
             }
             for (String file : new File(mSliceDir.getAbsolutePath()).list()) {
-                if (file.isEmpty()) continue;
                 try (ParserHolder parser = getParser(file)) {
-                    Persistable p;
-                    while (parser.parser.getEventType() != XmlPullParser.START_TAG) {
+                    Persistable p = null;
+                    while (parser.parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                        if (parser.parser.getEventType() == XmlPullParser.START_TAG) {
+                            if (SliceClientPermissions.TAG_CLIENT.equals(parser.parser.getName())) {
+                                p = SliceClientPermissions.createFrom(parser.parser, tracker);
+                            } else {
+                                p = SliceProviderPermissions.createFrom(parser.parser, tracker);
+                            }
+                            break;
+                        }
                         parser.parser.next();
                     }
-                    if (SliceClientPermissions.TAG_CLIENT.equals(parser.parser.getName())) {
-                        p = SliceClientPermissions.createFrom(parser.parser, tracker);
+                    if (p != null) {
+                        p.writeTo(out);
                     } else {
-                        p = SliceProviderPermissions.createFrom(parser.parser, tracker);
+                        Slog.w(TAG, "Invalid or empty slice permissions file: " + file);
                     }
-                    p.writeTo(out);
                 }
             }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
index b315e51..efefee1 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
@@ -16,6 +16,7 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -26,6 +27,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
+import android.util.Log;
 import android.util.Xml.Encoding;
 
 import com.android.server.UiServiceTestCase;
@@ -46,10 +48,12 @@
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 public class SlicePermissionManagerTest extends UiServiceTestCase {
+    private static final String TAG = "SlicePerManTest";
 
     @Test
     public void testGrant() {
-        File sliceDir = new File(mContext.getDataDir(), "system/slices");
+        File sliceDir = new File(mContext.getCacheDir(), "testGrantSlices");
+        Log.v(TAG, "testGrant: slice permissions stored in " + sliceDir.getAbsolutePath());
         SlicePermissionManager permissions = new SlicePermissionManager(mContext,
                 TestableLooper.get(this).getLooper(), sliceDir);
         Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
@@ -59,11 +63,15 @@
         permissions.grantSliceAccess("my.pkg", 0, "provider.pkg", 0, uri);
 
         assertTrue(permissions.hasPermission("my.pkg", 0, uri));
+
+        // Cleanup.
+        assertTrue(FileUtils.deleteContentsAndDir(sliceDir));
     }
 
     @Test
     public void testBackup() throws XmlPullParserException, IOException {
-        File sliceDir = new File(mContext.getDataDir(), "system/slices");
+        File sliceDir = new File(mContext.getCacheDir(), "testBackupSlices");
+        Log.v(TAG, "testBackup: slice permissions stored in " + sliceDir.getAbsolutePath());
         Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
                 .authority("authority")
                 .path("something").build();
@@ -90,7 +98,10 @@
                 TestableLooper.get(this).getLooper());
         permissions.readRestore(parser);
 
-        assertTrue(permissions.hasFullAccess("com.android.mypkg", 10));
+        if (!permissions.hasFullAccess("com.android.mypkg", 10)) {
+            fail("com.android.mypkg@10 did not have full access. backup file: "
+                    + output.toString());
+        }
         assertTrue(permissions.hasPermission("com.android.otherpkg", 0,
                 ContentProvider.maybeAddUserId(uri, 1)));
         permissions.removePkg("com.android.lastpkg", 1);
@@ -102,8 +113,9 @@
     }
 
     @Test
-    public void testInvalid() throws Exception {
-        File sliceDir = new File(mContext.getCacheDir(), "slices-test");
+    public void testInvalid() {
+        File sliceDir = new File(mContext.getCacheDir(), "testInvalidSlices");
+        Log.v(TAG, "testInvalid: slice permissions stored in " + sliceDir.getAbsolutePath());
         if (!sliceDir.exists()) {
             sliceDir.mkdir();
         }
@@ -118,7 +130,8 @@
 
             @Override
             public void writeTo(XmlSerializer out) throws IOException {
-                throw new RuntimeException("this doesn't work");
+                throw new RuntimeException("this RuntimeException inside junk.writeTo() "
+                        + "should be caught and suppressed by surrounding code");
             }
         };