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