1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.server.slice; 16 17 import static org.junit.Assert.assertFalse; 18 import static org.junit.Assert.assertTrue; 19 import static org.junit.Assert.fail; 20 21 import android.content.ContentProvider; 22 import android.content.ContentResolver; 23 import android.net.Uri; 24 import android.net.Uri.Builder; 25 import android.os.FileUtils; 26 import android.testing.AndroidTestingRunner; 27 import android.testing.TestableLooper; 28 import android.testing.TestableLooper.RunWithLooper; 29 import android.util.Log; 30 import android.util.Xml.Encoding; 31 32 import androidx.test.filters.SmallTest; 33 34 import com.android.server.UiServiceTestCase; 35 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 import org.xmlpull.v1.XmlPullParser; 39 import org.xmlpull.v1.XmlPullParserException; 40 import org.xmlpull.v1.XmlPullParserFactory; 41 import org.xmlpull.v1.XmlSerializer; 42 43 import java.io.ByteArrayInputStream; 44 import java.io.ByteArrayOutputStream; 45 import java.io.File; 46 import java.io.IOException; 47 48 @SmallTest 49 @RunWith(AndroidTestingRunner.class) 50 @RunWithLooper 51 public class SlicePermissionManagerTest extends UiServiceTestCase { 52 private static final String TAG = "SlicePerManTest"; 53 54 @Test testGrant()55 public void testGrant() { 56 File sliceDir = new File(mContext.getCacheDir(), "testGrantSlices"); 57 Log.v(TAG, "testGrant: slice permissions stored in " + sliceDir.getAbsolutePath()); 58 SlicePermissionManager permissions = new SlicePermissionManager(mContext, 59 TestableLooper.get(this).getLooper(), sliceDir); 60 Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT) 61 .authority("authority") 62 .path("something").build(); 63 64 permissions.grantSliceAccess("my.pkg", 0, "provider.pkg", 0, uri); 65 66 assertTrue(permissions.hasPermission("my.pkg", 0, uri)); 67 68 // Cleanup. 69 assertTrue(FileUtils.deleteContentsAndDir(sliceDir)); 70 } 71 72 @Test testBackup()73 public void testBackup() throws XmlPullParserException, IOException { 74 File sliceDir = new File(mContext.getCacheDir(), "testBackupSlices"); 75 Log.v(TAG, "testBackup: slice permissions stored in " + sliceDir.getAbsolutePath()); 76 Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT) 77 .authority("authority") 78 .path("something").build(); 79 SlicePermissionManager permissions = new SlicePermissionManager(mContext, 80 TestableLooper.get(this).getLooper(), sliceDir); 81 82 permissions.grantFullAccess("com.android.mypkg", 10); 83 permissions.grantSliceAccess("com.android.otherpkg", 0, "com.android.lastpkg", 1, uri); 84 85 ByteArrayOutputStream output = new ByteArrayOutputStream(); 86 XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer(); 87 serializer.setOutput(output, Encoding.UTF_8.name()); 88 89 90 TestableLooper.get(this).processAllMessages(); 91 permissions.writeBackup(serializer); 92 serializer.flush(); 93 94 ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); 95 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); 96 parser.setInput(input, Encoding.UTF_8.name()); 97 98 permissions = new SlicePermissionManager(mContext, 99 TestableLooper.get(this).getLooper()); 100 permissions.readRestore(parser); 101 102 if (!permissions.hasFullAccess("com.android.mypkg", 10)) { 103 fail("com.android.mypkg@10 did not have full access. backup file: " 104 + output.toString()); 105 } 106 assertTrue(permissions.hasPermission("com.android.otherpkg", 0, 107 ContentProvider.maybeAddUserId(uri, 1))); 108 permissions.removePkg("com.android.lastpkg", 1); 109 assertFalse(permissions.hasPermission("com.android.otherpkg", 0, 110 ContentProvider.maybeAddUserId(uri, 1))); 111 112 // Cleanup. 113 assertTrue(FileUtils.deleteContentsAndDir(sliceDir)); 114 } 115 116 @Test testInvalid()117 public void testInvalid() { 118 File sliceDir = new File(mContext.getCacheDir(), "testInvalidSlices"); 119 Log.v(TAG, "testInvalid: slice permissions stored in " + sliceDir.getAbsolutePath()); 120 if (!sliceDir.exists()) { 121 sliceDir.mkdir(); 122 } 123 SlicePermissionManager permissions = new SlicePermissionManager(mContext, 124 TestableLooper.get(this).getLooper(), sliceDir); 125 126 DirtyTracker.Persistable junk = new DirtyTracker.Persistable() { 127 @Override 128 public String getFileName() { 129 return "invalidData"; 130 } 131 132 @Override 133 public void writeTo(XmlSerializer out) throws IOException { 134 throw new RuntimeException("this RuntimeException inside junk.writeTo() " 135 + "should be caught and suppressed by surrounding code"); 136 } 137 }; 138 139 // let's put something bad in here 140 permissions.addDirtyImmediate(junk); 141 // force a persist. if this throws, it would take down system_server 142 permissions.handlePersist(); 143 144 // Cleanup. 145 assertTrue(FileUtils.deleteContentsAndDir(sliceDir)); 146 } 147 148 } 149