1 /* 2 * Copyright (C) 2009 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.providers.downloads.public_api_access_tests; 18 19 import android.app.DownloadManager; 20 import android.content.ContentResolver; 21 import android.content.ContentValues; 22 import android.net.Uri; 23 import android.provider.Downloads; 24 import android.test.AndroidTestCase; 25 import android.test.suitebuilder.annotation.MediumTest; 26 27 /** 28 * DownloadProvider allows apps without permission ACCESS_DOWNLOAD_MANAGER to access it -- this is 29 * how the public API works. But such access is subject to strict constraints on what can be 30 * inserted. This test suite checks those constraints. 31 */ 32 @MediumTest 33 public class PublicApiAccessTest extends AndroidTestCase { 34 private static final String[] DISALLOWED_COLUMNS = new String[] { 35 Downloads.Impl.COLUMN_COOKIE_DATA, 36 Downloads.Impl.COLUMN_REFERER, 37 Downloads.Impl.COLUMN_USER_AGENT, 38 Downloads.Impl.COLUMN_NO_INTEGRITY, 39 Downloads.Impl.COLUMN_NOTIFICATION_CLASS, 40 Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS, 41 Downloads.Impl.COLUMN_OTHER_UID, 42 Downloads.Impl.COLUMN_APP_DATA, 43 Downloads.Impl.COLUMN_CONTROL, 44 Downloads.Impl.COLUMN_STATUS, 45 }; 46 47 private ContentResolver mContentResolver; 48 private DownloadManager mManager; 49 50 @Override setUp()51 protected void setUp() throws Exception { 52 super.setUp(); 53 mContentResolver = getContext().getContentResolver(); 54 mManager = new DownloadManager(getContext()); 55 } 56 57 @Override tearDown()58 protected void tearDown() throws Exception { 59 if (mContentResolver != null) { 60 mContentResolver.delete(Downloads.Impl.CONTENT_URI, null, null); 61 } 62 super.tearDown(); 63 } 64 testMinimalValidWrite()65 public void testMinimalValidWrite() { 66 mContentResolver.insert(Downloads.Impl.CONTENT_URI, buildValidValues()); 67 } 68 testMaximalValidWrite()69 public void testMaximalValidWrite() { 70 ContentValues values = buildValidValues(); 71 values.put(Downloads.Impl.COLUMN_TITLE, "foo"); 72 values.put(Downloads.Impl.COLUMN_DESCRIPTION, "foo"); 73 values.put(Downloads.Impl.COLUMN_MIME_TYPE, "foo"); 74 values.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, "foo"); 75 values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, 0); 76 values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, true); 77 values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX + "0", "X-Some-Header: value"); 78 mContentResolver.insert(Downloads.Impl.CONTENT_URI, values); 79 } 80 buildValidValues()81 private ContentValues buildValidValues() { 82 ContentValues values = new ContentValues(); 83 values.put(Downloads.Impl.COLUMN_URI, "foo"); 84 values.put(Downloads.Impl.COLUMN_DESTINATION, 85 Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE); 86 values.put(Downloads.Impl.COLUMN_VISIBILITY, Downloads.Impl.VISIBILITY_VISIBLE); 87 values.put(Downloads.Impl.COLUMN_IS_PUBLIC_API, true); 88 return values; 89 } 90 testNoPublicApi()91 public void testNoPublicApi() { 92 ContentValues values = buildValidValues(); 93 values.remove(Downloads.Impl.COLUMN_IS_PUBLIC_API); 94 testInvalidValues(values); 95 } 96 testInvalidDestination()97 public void testInvalidDestination() { 98 ContentValues values = buildValidValues(); 99 values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_EXTERNAL); 100 testInvalidValues(values); 101 values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_CACHE_PARTITION); 102 testInvalidValues(values); 103 } 104 testInvalidVisibility()105 public void testInvalidVisibility() { 106 ContentValues values = buildValidValues(); 107 values.put(Downloads.Impl.COLUMN_VISIBILITY, 108 Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); 109 testInvalidValues(values); 110 111 values.put(Downloads.Impl.COLUMN_VISIBILITY, Downloads.Impl.VISIBILITY_HIDDEN); 112 testInvalidValues(values); 113 114 values.remove(Downloads.Impl.COLUMN_VISIBILITY); 115 testInvalidValues(values); 116 } 117 testDisallowedColumns()118 public void testDisallowedColumns() { 119 for (String column : DISALLOWED_COLUMNS) { 120 ContentValues values = buildValidValues(); 121 values.put(column, 1); 122 testInvalidValues(values); 123 } 124 } 125 testFileUriWithoutExternalPermission()126 public void testFileUriWithoutExternalPermission() { 127 ContentValues values = buildValidValues(); 128 values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_FILE_URI); 129 values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, "file:///sdcard/foo"); 130 testInvalidValues(values); 131 } 132 testInvalidValues(ContentValues values)133 private void testInvalidValues(ContentValues values) { 134 try { 135 mContentResolver.insert(Downloads.Impl.CONTENT_URI, values); 136 fail("Didn't get SecurityException as expected"); 137 } catch (SecurityException exc) { 138 // expected 139 } 140 } 141 testDownloadManagerRequest()142 public void testDownloadManagerRequest() { 143 // first try a minimal request 144 DownloadManager.Request request = new DownloadManager.Request(Uri.parse("http://localhost/path")); 145 mManager.enqueue(request); 146 147 // now set everything we can, save for external destintion (for which we lack permission) 148 request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); 149 request.setAllowedOverRoaming(false); 150 request.setTitle("test"); 151 request.setDescription("test"); 152 request.setMimeType("text/html"); 153 request.addRequestHeader("X-Some-Header", "value"); 154 mManager.enqueue(request); 155 } 156 } 157