1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.appdataisolation.common;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertTrue;
22 import static org.testng.Assert.assertEquals;
23 import static org.testng.Assert.fail;
24 import static org.testng.Assert.expectThrows;
25 
26 import android.system.ErrnoException;
27 import android.system.Os;
28 import android.system.OsConstants;
29 
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.FileNotFoundException;
33 import java.io.IOException;
34 
35 /*
36  * This class is a helper class for test app file operations.
37  */
38 public class FileUtils {
39 
40     public static final String APPA_PKG = "com.android.cts.appdataisolation.appa";
41     public static final String APPB_PKG = "com.android.cts.appdataisolation.appb";
42     public static final String NOT_INSTALLED_PKG = "com.android.cts.appdataisolation.not_installed_pkg";
43 
44     public static final String CE_DATA_FILE_NAME = "ce_data_file";
45     public static final String DE_DATA_FILE_NAME = "de_data_file";
46     public final static String EXTERNAL_DATA_FILE_NAME = "external_data_file";
47     public final static String OBB_FILE_NAME = "obb_file";
48 
49     private static final String JAVA_FILE_PERMISSION_DENIED_MSG =
50             "open failed: EACCES (Permission denied)";
51     private static final String JAVA_FILE_NOT_FOUND_MSG =
52             "open failed: ENOENT (No such file or directory)";
53 
assertDirIsNotAccessible(String path)54     public static void assertDirIsNotAccessible(String path) {
55         // Trying to access a file that does not exist in that directory, it should return
56         // permission denied not file not found.
57         Exception exception = expectThrows(FileNotFoundException.class, () -> {
58             new FileInputStream(new File(path, "FILE_DOES_NOT_EXIST"));
59         });
60         assertThat(exception.getMessage()).contains(JAVA_FILE_PERMISSION_DENIED_MSG);
61         assertThat(exception.getMessage()).doesNotContain(JAVA_FILE_NOT_FOUND_MSG);
62 
63         assertThat(new File(path).canExecute()).isFalse();
64     }
65 
assertDirDoesNotExist(String path)66     public static void assertDirDoesNotExist(String path) {
67         File directory = new File(path);
68         // Trying to access a file/directory that does exist, but is not visible to the caller, it
69         // should return file not found.
70         Exception exception = expectThrows(FileNotFoundException.class, () -> {
71             new FileInputStream(directory);
72         });
73         assertThat(exception.getMessage()).contains(JAVA_FILE_NOT_FOUND_MSG);
74         assertThat(exception.getMessage()).doesNotContain(JAVA_FILE_PERMISSION_DENIED_MSG);
75 
76         File parent = directory.getParentFile();
77         if (parent != null && !parent.exists()) {
78             // If the parent directory doesn't exist then we can be confident this
79             // directory is entirely invisible.
80             return;
81         }
82         // Try to create a directory here, and it should return permission denied not directory
83         // exists.
84         try {
85             Os.mkdir(path, 0700);
86             fail("Should not able to mkdir() on " + path);
87         } catch (ErrnoException e) {
88             assertEquals(e.errno, OsConstants.EACCES, "Error on path: " + path);
89         }
90 
91         assertThat(directory.exists()).isFalse();
92     }
93 
assertDirIsAccessible(String path)94     public static void assertDirIsAccessible(String path) {
95         // This can ensure directory path exists, and by trying to access a file doesn't exist,
96         // if app has search permission to that directory, it should return file not found
97         // and not security exception.
98         assertFileDoesNotExist(path, "FILE_DOES_NOT_EXIST");
99 
100         assertThat(new File(path).canExecute()).isTrue();
101     }
102 
assertFileIsAccessible(String path)103     public static void assertFileIsAccessible(String path) {
104         try (FileInputStream is = new FileInputStream(path)) {
105             is.read();
106         } catch (IOException e) {
107             fail("Could not read file: " + path, e);
108         }
109     }
110 
assertFileDoesNotExist(String path, String name)111     public static void assertFileDoesNotExist(String path, String name) {
112         // Make sure parent dir exists
113         File directory = new File(path);
114         assertTrue(directory.exists());
115 
116         Exception exception = expectThrows(FileNotFoundException.class, () -> {
117             new FileInputStream(new File(path, name));
118         });
119         assertThat(exception.getMessage()).contains(JAVA_FILE_NOT_FOUND_MSG);
120         assertThat(exception.getMessage()).doesNotContain(JAVA_FILE_PERMISSION_DENIED_MSG);
121     }
122 
assertFileExists(String path, String name)123     public static void assertFileExists(String path, String name) {
124         File file = new File(path, name);
125         assertTrue(file.exists());
126     }
127 
touchFile(String path, String name)128     public static void touchFile(String path, String name) throws IOException {
129         File file = new File(path, name);
130         file.createNewFile();
131     }
132 
replacePackageAWithPackageB(String path)133     public static String replacePackageAWithPackageB(String path) {
134         return path.replace(APPA_PKG, APPB_PKG);
135     }
136 
replacePackageAWithNotInstalledPkg(String path)137     public static String replacePackageAWithNotInstalledPkg(String path) {
138         return path.replace(APPA_PKG, NOT_INSTALLED_PKG);
139     }
140 }
141