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.assertEquals; 18 import static org.junit.Assert.assertFalse; 19 import static org.junit.Assert.assertTrue; 20 import static org.mockito.ArgumentMatchers.eq; 21 import static org.mockito.Mockito.clearInvocations; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.verify; 24 25 import android.content.ContentResolver; 26 import android.net.Uri; 27 import android.testing.AndroidTestingRunner; 28 import android.testing.TestableLooper.RunWithLooper; 29 import android.util.Xml.Encoding; 30 31 import androidx.test.filters.SmallTest; 32 33 import com.android.server.UiServiceTestCase; 34 import com.android.server.slice.SliceClientPermissions.SliceAuthority; 35 import com.android.server.slice.SlicePermissionManager.PkgUser; 36 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 import org.xmlpull.v1.XmlPullParser; 40 import org.xmlpull.v1.XmlPullParserException; 41 import org.xmlpull.v1.XmlPullParserFactory; 42 import org.xmlpull.v1.XmlSerializer; 43 44 import java.io.ByteArrayInputStream; 45 import java.io.ByteArrayOutputStream; 46 import java.io.IOException; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.Comparator; 50 51 @SmallTest 52 @RunWith(AndroidTestingRunner.class) 53 @RunWithLooper 54 public class SliceClientPermissionsTest extends UiServiceTestCase { 55 56 @Test testRemoveBasic()57 public void testRemoveBasic() { 58 PkgUser pkg = new PkgUser("com.android.pkg", 0); 59 DirtyTracker tracker = mock(DirtyTracker.class); 60 SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); 61 Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 62 .authority("com.android.pkg.slices").build(); 63 64 PkgUser testPkg = new PkgUser("other", 2); 65 66 client.grantUri(base.buildUpon() 67 .appendPath("first") 68 .build(), testPkg); 69 client.revokeUri(base.buildUpon() 70 .appendPath("first") 71 .build(), testPkg); 72 73 assertFalse(client.hasPermission(base.buildUpon() 74 .appendPath("first") 75 .appendPath("third") 76 .build(), testPkg.getUserId())); 77 78 ArrayList<SliceAuthority> authorities = new ArrayList<>(client.getAuthorities()); 79 assertEquals(0, authorities.get(0).getPaths().size()); 80 } 81 82 @Test testRemoveSubtrees()83 public void testRemoveSubtrees() { 84 PkgUser pkg = new PkgUser("com.android.pkg", 0); 85 DirtyTracker tracker = mock(DirtyTracker.class); 86 SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); 87 Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 88 .authority("com.android.pkg.slices").build(); 89 90 PkgUser testPkg = new PkgUser("other", 2); 91 92 client.grantUri(base.buildUpon() 93 .appendPath("first") 94 .appendPath("second") 95 .build(), testPkg); 96 client.grantUri(base.buildUpon() 97 .appendPath("first") 98 .appendPath("third") 99 .build(), testPkg); 100 client.revokeUri(base.buildUpon() 101 .appendPath("first") 102 .build(), testPkg); 103 104 assertFalse(client.hasPermission(base.buildUpon() 105 .appendPath("first") 106 .appendPath("fourth") 107 .build(), testPkg.getUserId())); 108 109 ArrayList<SliceAuthority> authorities = new ArrayList<>(client.getAuthorities()); 110 assertEquals(0, authorities.get(0).getPaths().size()); 111 } 112 113 @Test testAddConsolidate_addFirst()114 public void testAddConsolidate_addFirst() { 115 PkgUser pkg = new PkgUser("com.android.pkg", 0); 116 DirtyTracker tracker = mock(DirtyTracker.class); 117 SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); 118 Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 119 .authority("com.android.pkg.slices").build(); 120 121 PkgUser testPkg = new PkgUser("other", 2); 122 123 client.grantUri(base.buildUpon() 124 .appendPath("first") 125 .build(), testPkg); 126 client.grantUri(base.buildUpon() 127 .appendPath("first") 128 .appendPath("second") 129 .build(), testPkg); 130 131 assertTrue(client.hasPermission(base.buildUpon() 132 .appendPath("first") 133 .appendPath("third") 134 .build(), testPkg.getUserId())); 135 136 ArrayList<SliceAuthority> authorities = new ArrayList<>(client.getAuthorities()); 137 assertEquals(1, authorities.get(0).getPaths().size()); 138 } 139 140 @Test testAddConsolidate_addSecond()141 public void testAddConsolidate_addSecond() { 142 PkgUser pkg = new PkgUser("com.android.pkg", 0); 143 DirtyTracker tracker = mock(DirtyTracker.class); 144 SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); 145 Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 146 .authority("com.android.pkg.slices").build(); 147 148 PkgUser testPkg = new PkgUser("other", 2); 149 150 client.grantUri(base.buildUpon() 151 .appendPath("first") 152 .appendPath("second") 153 .build(), testPkg); 154 client.grantUri(base.buildUpon() 155 .appendPath("first") 156 .build(), testPkg); 157 158 assertTrue(client.hasPermission(base.buildUpon() 159 .appendPath("first") 160 .appendPath("third") 161 .build(), testPkg.getUserId())); 162 163 ArrayList<SliceAuthority> authorities = new ArrayList<>(client.getAuthorities()); 164 assertEquals(1, authorities.get(0).getPaths().size()); 165 } 166 167 @Test testDirty_addAuthority()168 public void testDirty_addAuthority() { 169 PkgUser pkg = new PkgUser("com.android.pkg", 0); 170 DirtyTracker tracker = mock(DirtyTracker.class); 171 SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); 172 173 client.getOrCreateAuthority(new PkgUser("some_auth", 2), new PkgUser("com.pkg", 2)); 174 175 verify(tracker).onPersistableDirty(eq(client)); 176 } 177 178 @Test testDirty_addPkg()179 public void testDirty_addPkg() { 180 PkgUser pkg = new PkgUser("com.android.pkg", 0); 181 DirtyTracker tracker = mock(DirtyTracker.class); 182 SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); 183 184 SliceAuthority auth = client.getOrCreateAuthority( 185 new PkgUser("some_auth", 2), 186 new PkgUser("com.pkg", 2)); 187 clearInvocations(tracker); 188 189 auth.addPath(Arrays.asList("/something/")); 190 191 verify(tracker).onPersistableDirty(eq(client)); 192 } 193 194 @Test testCreation()195 public void testCreation() { 196 SliceClientPermissions client = createClient(); 197 ArrayList<SliceAuthority> authorities = new ArrayList<>(client.getAuthorities()); 198 authorities.sort(Comparator.comparing(SliceAuthority::getAuthority)); 199 200 assertEquals(2, authorities.size()); 201 assertEquals("com.android.pkg", authorities.get(0).getAuthority()); 202 assertEquals("com.android.pkg.slices", authorities.get(1).getAuthority()); 203 204 assertEquals(1, authorities.get(0).getPaths().size()); 205 assertEquals(2, authorities.get(1).getPaths().size()); 206 } 207 208 @Test testSerialization()209 public void testSerialization() throws XmlPullParserException, IOException { 210 SliceClientPermissions client = createClient(); 211 client.setHasFullAccess(true); 212 213 ByteArrayOutputStream output = new ByteArrayOutputStream(); 214 XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer(); 215 serializer.setOutput(output, Encoding.UTF_8.name()); 216 217 client.writeTo(serializer); 218 serializer.flush(); 219 220 ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); 221 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); 222 parser.setInput(input, Encoding.UTF_8.name()); 223 224 SliceClientPermissions deser = SliceClientPermissions.createFrom(parser, 225 mock(DirtyTracker.class)); 226 227 assertEquivalent(client, deser); 228 } 229 230 @Test(expected = XmlPullParserException.class) testReadEmptyFile_ThrowException()231 public void testReadEmptyFile_ThrowException() throws XmlPullParserException, IOException { 232 ByteArrayOutputStream output = new ByteArrayOutputStream(); 233 XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer(); 234 serializer.setOutput(output, Encoding.UTF_8.name()); 235 // create empty xml document 236 serializer.startDocument(null, true); 237 serializer.endDocument(); 238 serializer.flush(); 239 240 ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); 241 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); 242 parser.setInput(input, Encoding.UTF_8.name()); 243 SliceClientPermissions.createFrom(parser, mock(DirtyTracker.class)); 244 // Should throw exception since the xml is empty 245 } 246 assertEquivalent(SliceClientPermissions o1, SliceClientPermissions o2)247 private void assertEquivalent(SliceClientPermissions o1, SliceClientPermissions o2) { 248 assertEquals(o1.getPkg(), o2.getPkg()); 249 ArrayList<SliceAuthority> a1 = new ArrayList<>(o1.getAuthorities()); 250 ArrayList<SliceAuthority> a2 = new ArrayList<>(o2.getAuthorities()); 251 a1.sort(Comparator.comparing(SliceAuthority::getAuthority)); 252 a2.sort(Comparator.comparing(SliceAuthority::getAuthority)); 253 assertEquals(a1, a2); 254 } 255 createClient()256 private static SliceClientPermissions createClient() { 257 PkgUser pkg = new PkgUser("com.android.pkg", 2); 258 DirtyTracker tracker = mock(DirtyTracker.class); 259 SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); 260 261 SliceAuthority auth = client.getOrCreateAuthority( 262 new PkgUser("com.android.pkg.slices", 3), 263 new PkgUser("com.android.pkg", 3)); 264 auth.addPath(Arrays.asList("/something/")); 265 auth.addPath(Arrays.asList("/something/else")); 266 267 auth = client.getOrCreateAuthority( 268 new PkgUser("com.android.pkg", 3), 269 new PkgUser("com.pkg", 1)); 270 auth.addPath(Arrays.asList("/somewhere")); 271 return client; 272 } 273 274 }