Home | History | Annotate | Download | only in externalstorageapp
      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 com.android.cts.externalstorageapp;
     18 
     19 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
     20 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
     21 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
     22 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
     23 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
     24 
     25 import android.app.DownloadManager;
     26 import android.app.DownloadManager.Query;
     27 import android.app.DownloadManager.Request;
     28 import android.content.BroadcastReceiver;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.content.IntentFilter;
     32 import android.database.Cursor;
     33 import android.net.Uri;
     34 import android.os.Environment;
     35 import android.os.SystemClock;
     36 import android.test.AndroidTestCase;
     37 import android.text.format.DateUtils;
     38 
     39 import java.io.BufferedReader;
     40 import java.io.File;
     41 import java.io.FileReader;
     42 import java.util.Arrays;
     43 import java.util.HashSet;
     44 import java.util.List;
     45 
     46 /**
     47  * Test external storage from an application that has no external storage
     48  * permissions.
     49  */
     50 public class ExternalStorageTest extends AndroidTestCase {
     51 
     52     public void testPrimaryNoAccess() throws Exception {
     53         assertDirNoAccess(Environment.getExternalStorageDirectory());
     54     }
     55 
     56     /**
     57      * Verify that above our package directories we always have no access.
     58      */
     59     public void testAllWalkingUpTreeNoAccess() throws Exception {
     60         final List<File> paths = getAllPackageSpecificPaths(getContext());
     61         final String packageName = getContext().getPackageName();
     62 
     63         for (File path : paths) {
     64             if (path == null) continue;
     65 
     66             assertTrue(path.getAbsolutePath().contains(packageName));
     67 
     68             // Walk up until we drop our package
     69             while (path.getAbsolutePath().contains(packageName)) {
     70                 assertDirReadWriteAccess(path);
     71                 path = path.getParentFile();
     72             }
     73 
     74             // Keep walking up until we leave device
     75             while (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
     76                 assertDirNoAccess(path);
     77                 path = path.getParentFile();
     78             }
     79         }
     80     }
     81 
     82     /**
     83      * Verify that we don't have read access to any storage mountpoints.
     84      */
     85     public void testMountPointsNotReadable() throws Exception {
     86         final String userId = Integer.toString(android.os.Process.myUid() / 100000);
     87         final List<File> mountPaths = getMountPaths();
     88         for (File path : mountPaths) {
     89             if (path.getAbsolutePath().startsWith("/mnt/")
     90                     || path.getAbsolutePath().startsWith("/storage/")) {
     91                 // Mount points could be multi-user aware, so try probing both
     92                 // top level and user-specific directory.
     93                 final File userPath = new File(path, userId);
     94 
     95                 assertDirNoAccess(path);
     96                 assertDirNoAccess(userPath);
     97             }
     98         }
     99     }
    100 
    101     /**
    102      * Verify that we can't download things outside package directory.
    103      */
    104     public void testDownloadManager() throws Exception {
    105         final DownloadManager dm = getContext().getSystemService(DownloadManager.class);
    106         try {
    107             final Uri source = Uri.parse("http://www.example.com");
    108             final File target = new File(
    109                     Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "meow");
    110             dm.enqueue(new Request(source).setDestinationUri(Uri.fromFile(target)));
    111             fail("Unexpected success writing outside package directory");
    112         } catch (SecurityException expected) {
    113         }
    114     }
    115 
    116     /**
    117      * Verify that we can download things into our package directory.
    118      */
    119     public void testDownloadManagerPackage() throws Exception {
    120         final DownloadManager dm = getContext().getSystemService(DownloadManager.class);
    121         final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
    122         try {
    123             IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
    124             mContext.registerReceiver(receiver, intentFilter);
    125 
    126             final Uri source = Uri.parse("http://www.example.com");
    127             final File target = new File(
    128                     getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "meow");
    129 
    130             final long id = dm.enqueue(new Request(source).setDestinationUri(Uri.fromFile(target)));
    131             try {
    132                 receiver.waitForDownloadComplete(30 * DateUtils.SECOND_IN_MILLIS, id);
    133                 assertSuccessfulDownload(id, target);
    134             } finally {
    135                 dm.remove(id);
    136             }
    137         } finally {
    138             mContext.unregisterReceiver(receiver);
    139         }
    140     }
    141 
    142     /**
    143      * Shamelessly borrowed from DownloadManagerTest.java
    144      */
    145     private static class DownloadCompleteReceiver extends BroadcastReceiver {
    146         private HashSet<Long> mCompleteIds = new HashSet<>();
    147 
    148         public DownloadCompleteReceiver() {
    149         }
    150 
    151         @Override
    152         public void onReceive(Context context, Intent intent) {
    153             synchronized (mCompleteIds) {
    154                 mCompleteIds.add(intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1));
    155                 mCompleteIds.notifyAll();
    156             }
    157         }
    158 
    159         private boolean isCompleteLocked(long... ids) {
    160             for (long id : ids) {
    161                 if (!mCompleteIds.contains(id)) {
    162                     return false;
    163                 }
    164             }
    165             return true;
    166         }
    167 
    168         public void waitForDownloadComplete(long timeoutMillis, long... waitForIds)
    169                 throws InterruptedException {
    170             if (waitForIds.length == 0) {
    171                 throw new IllegalArgumentException("Missing IDs to wait for");
    172             }
    173 
    174             final long startTime = SystemClock.elapsedRealtime();
    175             do {
    176                 synchronized (mCompleteIds) {
    177                     mCompleteIds.wait(timeoutMillis);
    178                     if (isCompleteLocked(waitForIds)) return;
    179                 }
    180             } while ((SystemClock.elapsedRealtime() - startTime) < timeoutMillis);
    181 
    182             throw new InterruptedException("Timeout waiting for IDs " + Arrays.toString(waitForIds)
    183                     + "; received " + mCompleteIds.toString()
    184                     + ".  Make sure you have WiFi or some other connectivity for this test.");
    185         }
    186     }
    187 
    188     private void assertSuccessfulDownload(long id, File location) {
    189         final DownloadManager dm = getContext().getSystemService(DownloadManager.class);
    190 
    191         Cursor cursor = null;
    192         try {
    193             cursor = dm.query(new Query().setFilterById(id));
    194             assertTrue(cursor.moveToNext());
    195             assertEquals(DownloadManager.STATUS_SUCCESSFUL, cursor.getInt(
    196                     cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)));
    197             assertEquals(Uri.fromFile(location).toString(),
    198                     cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)));
    199             assertTrue(location.exists());
    200         } finally {
    201             if (cursor != null) {
    202                 cursor.close();
    203             }
    204         }
    205     }
    206 }
    207