1 /* 2 * Copyright (C) 2012 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 android.uidisolation.cts; 18 19 import android.app.Service; 20 import android.content.Intent; 21 import android.os.AsyncTask; 22 import android.os.Handler; 23 import android.os.IBinder; 24 import android.os.Message; 25 import android.os.Messenger; 26 import android.os.RemoteException; 27 import android.util.Log; 28 import android.webkit.cts.CtsTestServer; 29 30 import java.io.File; 31 import java.io.FileInputStream; 32 import java.io.FileNotFoundException; 33 import java.io.FileOutputStream; 34 import java.io.InputStream; 35 import java.io.IOException; 36 import java.net.MalformedURLException; 37 import java.net.URL; 38 39 public class PermissionTestService extends Service { 40 private static String TAG = PermissionTestService.class.getName(); 41 42 static final String FILE_NAME = "test_file"; 43 44 // Message receieved from the client. 45 static final int MSG_START_TEST = 1; 46 47 // Messages sent to the client. 48 static final int MSG_NOTIFY_TEST_SUCCESS = 2; 49 static final int MSG_NOTIFY_TEST_FAILURE = 3; 50 51 // The different tests types we run. 52 static final int FILE_READ_TEST = 1; 53 static final int FILE_WRITE_TEST = 2; 54 static final int NETWORK_ACCESS_TEST = 3; 55 56 private Messenger mClient; 57 58 // Whether we expect to have permissions to access files, network... 59 boolean mExpectPermissionsAllowed = true; 60 61 class IncomingHandler extends Handler { 62 private PermissionTestService mService; 63 64 IncomingHandler(PermissionTestService service) { 65 mService = service; 66 } 67 68 @Override 69 public void handleMessage(Message msg) { 70 if (msg.what != MSG_START_TEST) { 71 Log.e(TAG, "PermissionTestService received bad message: " + msg.what); 72 super.handleMessage(msg); 73 return; 74 } 75 mService.mClient = msg.replyTo; 76 mService.startTests(); 77 } 78 } 79 80 final Messenger mMessenger = new Messenger(new IncomingHandler(this)); 81 82 class NetworkTestAsyncTask extends AsyncTask<Void, Void, Boolean> { 83 protected Boolean doInBackground(Void... nothing) { 84 // Instant apps cannot open TCP sockets 85 return getPackageManager().isInstantApp() || testNetworkAccess(); 86 } 87 88 protected void onPostExecute(Boolean success) { 89 testNetworkAccessDone(success); 90 } 91 } 92 93 public PermissionTestService() { 94 this(true); 95 } 96 97 protected PermissionTestService(boolean expectPermissionsAllowed) { 98 mExpectPermissionsAllowed = expectPermissionsAllowed; 99 } 100 101 @Override 102 public IBinder onBind(Intent intent) { 103 return mMessenger.getBinder(); 104 } 105 106 private void notifyClientOfFailure(int failingTest) { 107 try { 108 mClient.send(Message.obtain(null, MSG_NOTIFY_TEST_FAILURE, failingTest, 0, null)); 109 } catch (RemoteException e) { 110 Log.e(TAG, "Failed to send message back to client."); 111 } 112 } 113 114 private void notifyClientOfSuccess() { 115 try { 116 mClient.send(Message.obtain(null, MSG_NOTIFY_TEST_SUCCESS)); 117 } catch (RemoteException e) { 118 Log.e(TAG, "Failed to send message back to client."); 119 } 120 } 121 122 private void startTests() { 123 if (testFileReadAccess() != mExpectPermissionsAllowed) { 124 notifyClientOfFailure(FILE_READ_TEST); 125 return; 126 } 127 if (testFileWriteAccess() != mExpectPermissionsAllowed) { 128 notifyClientOfFailure(FILE_WRITE_TEST); 129 return; 130 } 131 132 // testNetworkAccess is performed asynchronously and calls testNetworkAccessDone. 133 new NetworkTestAsyncTask().execute(); 134 } 135 136 private void testNetworkAccessDone(boolean success) { 137 // Instant apps cannot open TCP sockets. 138 if (!getPackageManager().isInstantApp() && success != mExpectPermissionsAllowed) { 139 notifyClientOfFailure(NETWORK_ACCESS_TEST); 140 return; 141 } 142 notifyClientOfSuccess(); 143 } 144 145 private boolean testFileReadAccess() { 146 File f = getApplication().getFileStreamPath(FILE_NAME); 147 if (!f.exists()) { 148 Log.e(TAG, "testFileReadAccess: test file does not exists."); 149 return false; 150 } 151 if (!f.canRead()) { 152 Log.e(TAG, "testFileReadAccess: no permission to read test file."); 153 return false; 154 } 155 156 FileInputStream fis = null; 157 try { 158 fis = new FileInputStream(f); 159 for (int i = 0; i < 10; i++) { 160 int value; 161 try { 162 value = fis.read(); 163 } catch (IOException ioe) { 164 Log.e(TAG, "testFileReadAccess: failed to read test file, IOException."); 165 return false; 166 } 167 if (value == -1) { 168 Log.e(TAG, "testFileReadAccess: failed to read test file."); 169 return false; 170 } 171 if (value != i) { 172 Log.e(TAG, "testFileReadAccess: wrong data read from test file."); 173 return false; 174 } 175 } 176 } catch (FileNotFoundException fnfe) { 177 Log.e(TAG, "testFileReadAccess: failed to read test file, FileNotFoundException."); 178 return false; 179 } finally { 180 if (fis != null) { 181 try { 182 fis.close(); 183 } catch (IOException ioe) { 184 } 185 } 186 } 187 return true; 188 } 189 190 private boolean testFileWriteAccess() { 191 FileOutputStream fos = null; 192 try { 193 fos = getApplication().openFileOutput("writeable_file", 0); 194 byte[] content = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 195 fos.write(content, 0, content.length); 196 } catch (FileNotFoundException fnfe) { 197 Log.e(TAG, "Failed to open writable file."); 198 return false; 199 } catch (IOException ioe) { 200 Log.e(TAG, "Failed to write to writable file."); 201 return false; 202 } finally { 203 if (fos != null) { 204 try { 205 fos.close(); 206 } catch (IOException ioe) { 207 } 208 } 209 } 210 return true; 211 } 212 213 private boolean testNetworkAccess() { 214 CtsTestServer webServer = null; 215 try { 216 try { 217 webServer = new CtsTestServer(getApplication(), 218 CtsTestServer.SslMode.TRUST_ANY_CLIENT); 219 } catch (Exception e) { 220 Log.e(TAG, "Failed to create CtsTestServer."); 221 return false; 222 } 223 224 URL url; 225 try { 226 url = new URL(webServer.getAssetUrl("hello.html")); 227 } catch (MalformedURLException mue) { 228 Log.e(TAG, "Test is bad, could not create the URL in " 229 + "PermissionTestService.testNetworkAccess()."); 230 return false; 231 } 232 InputStream is = null; 233 try { 234 is = url.openStream(); 235 // Attempt to read some bytes. 236 for (int i = 0; i < 10; i++) { 237 int value = is.read(); 238 if (value == -1) { 239 Log.e(TAG, "Failed to read byte " + i + " from network connection"); 240 return false; 241 } 242 } 243 } catch (IOException ioe) { 244 Log.e(TAG, "Failed to read from network connection: " + ioe); 245 return false; 246 } catch (SecurityException se) { 247 Log.e(TAG, "Failed to read from network connection: " + se); 248 return false; 249 } finally { 250 if (is != null) { 251 try { 252 is.close(); 253 } catch (IOException ioe) { 254 } 255 } 256 } 257 Log.i(TAG, "Successfully accessed network."); 258 return true; 259 } finally { 260 if (webServer != null) { 261 webServer.shutdown(); 262 } 263 } 264 } 265 } 266