/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.android.server.slice; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.content.ContentResolver; import android.net.Uri; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.util.Xml.Encoding; import com.android.server.UiServiceTestCase; import com.android.server.slice.SlicePermissionManager.PkgUser; import com.android.server.slice.SliceClientPermissions.SliceAuthority; import org.junit.Test; import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper public class SliceClientPermissionsTest extends UiServiceTestCase { @Test public void testRemoveBasic() { PkgUser pkg = new PkgUser("com.android.pkg", 0); DirtyTracker tracker = mock(DirtyTracker.class); SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority("com.android.pkg.slices").build(); PkgUser testPkg = new PkgUser("other", 2); client.grantUri(base.buildUpon() .appendPath("first") .build(), testPkg); client.revokeUri(base.buildUpon() .appendPath("first") .build(), testPkg); assertFalse(client.hasPermission(base.buildUpon() .appendPath("first") .appendPath("third") .build(), testPkg.getUserId())); ArrayList authorities = new ArrayList<>(client.getAuthorities()); assertEquals(0, authorities.get(0).getPaths().size()); } @Test public void testRemoveSubtrees() { PkgUser pkg = new PkgUser("com.android.pkg", 0); DirtyTracker tracker = mock(DirtyTracker.class); SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority("com.android.pkg.slices").build(); PkgUser testPkg = new PkgUser("other", 2); client.grantUri(base.buildUpon() .appendPath("first") .appendPath("second") .build(), testPkg); client.grantUri(base.buildUpon() .appendPath("first") .appendPath("third") .build(), testPkg); client.revokeUri(base.buildUpon() .appendPath("first") .build(), testPkg); assertFalse(client.hasPermission(base.buildUpon() .appendPath("first") .appendPath("fourth") .build(), testPkg.getUserId())); ArrayList authorities = new ArrayList<>(client.getAuthorities()); assertEquals(0, authorities.get(0).getPaths().size()); } @Test public void testAddConsolidate_addFirst() { PkgUser pkg = new PkgUser("com.android.pkg", 0); DirtyTracker tracker = mock(DirtyTracker.class); SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority("com.android.pkg.slices").build(); PkgUser testPkg = new PkgUser("other", 2); client.grantUri(base.buildUpon() .appendPath("first") .build(), testPkg); client.grantUri(base.buildUpon() .appendPath("first") .appendPath("second") .build(), testPkg); assertTrue(client.hasPermission(base.buildUpon() .appendPath("first") .appendPath("third") .build(), testPkg.getUserId())); ArrayList authorities = new ArrayList<>(client.getAuthorities()); assertEquals(1, authorities.get(0).getPaths().size()); } @Test public void testAddConsolidate_addSecond() { PkgUser pkg = new PkgUser("com.android.pkg", 0); DirtyTracker tracker = mock(DirtyTracker.class); SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); Uri base = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority("com.android.pkg.slices").build(); PkgUser testPkg = new PkgUser("other", 2); client.grantUri(base.buildUpon() .appendPath("first") .appendPath("second") .build(), testPkg); client.grantUri(base.buildUpon() .appendPath("first") .build(), testPkg); assertTrue(client.hasPermission(base.buildUpon() .appendPath("first") .appendPath("third") .build(), testPkg.getUserId())); ArrayList authorities = new ArrayList<>(client.getAuthorities()); assertEquals(1, authorities.get(0).getPaths().size()); } @Test public void testDirty_addAuthority() { PkgUser pkg = new PkgUser("com.android.pkg", 0); DirtyTracker tracker = mock(DirtyTracker.class); SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); client.getOrCreateAuthority(new PkgUser("some_auth", 2), new PkgUser("com.pkg", 2)); verify(tracker).onPersistableDirty(eq(client)); } @Test public void testDirty_addPkg() { PkgUser pkg = new PkgUser("com.android.pkg", 0); DirtyTracker tracker = mock(DirtyTracker.class); SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); SliceAuthority auth = client.getOrCreateAuthority( new PkgUser("some_auth", 2), new PkgUser("com.pkg", 2)); clearInvocations(tracker); auth.addPath(Arrays.asList("/something/")); verify(tracker).onPersistableDirty(eq(client)); } @Test public void testCreation() { SliceClientPermissions client = createClient(); ArrayList authorities = new ArrayList<>(client.getAuthorities()); authorities.sort(Comparator.comparing(SliceAuthority::getAuthority)); assertEquals(2, authorities.size()); assertEquals("com.android.pkg", authorities.get(0).getAuthority()); assertEquals("com.android.pkg.slices", authorities.get(1).getAuthority()); assertEquals(1, authorities.get(0).getPaths().size()); assertEquals(2, authorities.get(1).getPaths().size()); } @Test public void testSerialization() throws XmlPullParserException, IOException { SliceClientPermissions client = createClient(); client.setHasFullAccess(true); ByteArrayOutputStream output = new ByteArrayOutputStream(); XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer(); serializer.setOutput(output, Encoding.UTF_8.name()); client.writeTo(serializer); serializer.flush(); ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); parser.setInput(input, Encoding.UTF_8.name()); SliceClientPermissions deser = SliceClientPermissions.createFrom(parser, mock(DirtyTracker.class)); assertEquivalent(client, deser); } private void assertEquivalent(SliceClientPermissions o1, SliceClientPermissions o2) { assertEquals(o1.getPkg(), o2.getPkg()); ArrayList a1 = new ArrayList<>(o1.getAuthorities()); ArrayList a2 = new ArrayList<>(o2.getAuthorities()); a1.sort(Comparator.comparing(SliceAuthority::getAuthority)); a2.sort(Comparator.comparing(SliceAuthority::getAuthority)); assertEquals(a1, a2); } private static SliceClientPermissions createClient() { PkgUser pkg = new PkgUser("com.android.pkg", 2); DirtyTracker tracker = mock(DirtyTracker.class); SliceClientPermissions client = new SliceClientPermissions(pkg, tracker); SliceAuthority auth = client.getOrCreateAuthority( new PkgUser("com.android.pkg.slices", 3), new PkgUser("com.android.pkg", 3)); auth.addPath(Arrays.asList("/something/")); auth.addPath(Arrays.asList("/something/else")); auth = client.getOrCreateAuthority( new PkgUser("com.android.pkg", 3), new PkgUser("com.pkg", 1)); auth.addPath(Arrays.asList("/somewhere")); return client; } }