blob: b742cc9e75bb8146568e9c47a73b137f44b45394 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.cts;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.Instrumentation;
import android.app.WallpaperManager;
import android.content.ActivityNotFoundException;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextParams;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.sqlite.SQLiteCursorDriver;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQuery;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.AppModeFull;
import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.Suppress;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import android.view.WindowManager;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
import com.android.cts.IBinderPermissionTestService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@AppModeFull // TODO(Instant) Figure out which APIs should work.
public class ContextTest extends AndroidTestCase {
private static final String TAG = "ContextTest";
private static final String ACTUAL_RESULT = "ResultSetByReceiver";
private static final String INTIAL_RESULT = "IntialResult";
private static final String VALUE_ADDED = "ValueAdded";
private static final String KEY_ADDED = "AddedByReceiver";
private static final String VALUE_REMOVED = "ValueWillBeRemove";
private static final String KEY_REMOVED = "ToBeRemoved";
private static final String VALUE_KEPT = "ValueKept";
private static final String KEY_KEPT = "ToBeKept";
private static final String MOCK_STICKY_ACTION = "android.content.cts.ContextTest."
+ "STICKY_BROADCAST_RESULT";
private static final String ACTION_BROADCAST_TESTORDER =
"android.content.cts.ContextTest.BROADCAST_TESTORDER";
private final static String MOCK_ACTION1 = ACTION_BROADCAST_TESTORDER + "1";
private final static String MOCK_ACTION2 = ACTION_BROADCAST_TESTORDER + "2";
// Note: keep these constants in sync with the permissions used by BinderPermissionTestService.
//
// A permission that's granted to this test package.
public static final String GRANTED_PERMISSION = "android.permission.USE_CREDENTIALS";
// A permission that's not granted to this test package.
public static final String NOT_GRANTED_PERMISSION = "android.permission.HARDWARE_TEST";
private static final int BROADCAST_TIMEOUT = 10000;
private static final int ROOT_UID = 0;
/**
* Shell command to broadcast {@link ResultReceiver#MOCK_ACTION} as an external app.
*/
private static final String EXTERNAL_APP_BROADCAST_COMMAND =
"am broadcast -a " + ResultReceiver.MOCK_ACTION + " -f "
+ Intent.FLAG_RECEIVER_FOREGROUND;
private Object mLockObj;
private ArrayList<BroadcastReceiver> mRegisteredReceiverList;
private boolean mWallpaperChanged;
private BitmapDrawable mOriginalWallpaper;
private volatile IBinderPermissionTestService mBinderPermissionTestService;
private ServiceConnection mBinderPermissionTestConnection;
protected Context mContext;
/**
* Returns the Context object that's being tested.
*/
protected Context getContextUnderTest() {
return getContext();
}
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = getContextUnderTest();
mContext.setTheme(R.style.Test_Theme);
mLockObj = new Object();
mRegisteredReceiverList = new ArrayList<BroadcastReceiver>();
mOriginalWallpaper = (BitmapDrawable) mContext.getWallpaper();
}
@Override
protected void tearDown() throws Exception {
if (mWallpaperChanged) {
mContext.setWallpaper(mOriginalWallpaper.getBitmap());
}
for (BroadcastReceiver receiver : mRegisteredReceiverList) {
mContext.unregisterReceiver(receiver);
}
super.tearDown();
}
public void testGetString() {
String testString = mContext.getString(R.string.context_test_string1);
assertEquals("This is %s string.", testString);
testString = mContext.getString(R.string.context_test_string1, "expected");
assertEquals("This is expected string.", testString);
testString = mContext.getString(R.string.context_test_string2);
assertEquals("This is test string.", testString);
// Test wrong resource id
try {
testString = mContext.getString(0, "expected");
fail("Wrong resource id should not be accepted.");
} catch (NotFoundException e) {
}
// Test wrong resource id
try {
testString = mContext.getString(0);
fail("Wrong resource id should not be accepted.");
} catch (NotFoundException e) {
}
}
public void testGetText() {
CharSequence testCharSequence = mContext.getText(R.string.context_test_string2);
assertEquals("This is test string.", testCharSequence.toString());
// Test wrong resource id
try {
testCharSequence = mContext.getText(0);
fail("Wrong resource id should not be accepted.");
} catch (NotFoundException e) {
}
}
public void testCreateAttributionContext() throws Exception {
final String tag = "testCreateAttributionContext";
final Context attrib = mContext.createAttributionContext(tag);
assertEquals(tag, attrib.getAttributionTag());
assertEquals(null, mContext.getAttributionTag());
}
public void testCreateAttributionContextFromParams() throws Exception {
final ContextParams params = new ContextParams.Builder()
.setAttributionTag("foo")
.setNextAttributionSource(new AttributionSource.Builder(1)
.setPackageName("bar")
.setAttributionTag("baz")
.build())
.build();
final Context attributionContext = getContext().createContext(params);
assertEquals(params, attributionContext.getParams());
assertEquals(params.getNextAttributionSource(),
attributionContext.getAttributionSource().getNext());
assertEquals(params.getAttributionTag(),
attributionContext.getAttributionSource().getAttributionTag());
}
public void testContextParams() throws Exception {
final ContextParams params = new ContextParams.Builder()
.setAttributionTag("foo")
.setNextAttributionSource(new AttributionSource.Builder(1)
.setPackageName("bar")
.setAttributionTag("baz")
.build())
.build();
assertEquals("foo", params.getAttributionTag());
assertEquals(1, params.getNextAttributionSource().getUid());
assertEquals("bar", params.getNextAttributionSource().getPackageName());
assertEquals("baz", params.getNextAttributionSource().getAttributionTag());
}
public void testAttributionSourceSetNext() throws Exception {
final AttributionSource next = new AttributionSource.Builder(2)
.setPackageName("nextBar")
.setAttributionTag("nextBaz")
.build();
final ContextParams params = new ContextParams.Builder()
.setAttributionTag("foo")
.setNextAttributionSource(new AttributionSource.Builder(1)
.setPackageName("bar")
.setAttributionTag("baz")
.setNext(next)
.build())
.build();
// Setting a 'next' should not affect prev.
assertEquals("foo", params.getAttributionTag());
assertEquals(1, params.getNextAttributionSource().getUid());
assertEquals("bar", params.getNextAttributionSource().getPackageName());
assertEquals("baz", params.getNextAttributionSource().getAttributionTag());
final AttributionSource check =
params.getNextAttributionSource().getNext();
assertEquals(2, check.getUid());
assertEquals("nextBar", check.getPackageName());
assertEquals("nextBaz", check.getAttributionTag());
}
public void testContextParams_Inherit() throws Exception {
final ContextParams orig = new ContextParams.Builder()
.setAttributionTag("foo").build();
{
final ContextParams params = new ContextParams.Builder(orig).build();
assertEquals("foo", params.getAttributionTag());
}
{
final ContextParams params = new ContextParams.Builder(orig)
.setAttributionTag("bar").build();
assertEquals("bar", params.getAttributionTag());
}
{
final ContextParams params = new ContextParams.Builder(orig)
.setAttributionTag(null).build();
assertEquals(null, params.getAttributionTag());
}
}
/**
* Ensure that default and device encrypted storage areas are stored
* separately on disk. All devices must support these storage areas, even if
* they don't have file-based encryption, so that apps can go through a
* backup/restore cycle between FBE and non-FBE devices.
*/
public void testCreateDeviceProtectedStorageContext() throws Exception {
final Context deviceContext = mContext.createDeviceProtectedStorageContext();
assertFalse(mContext.isDeviceProtectedStorage());
assertTrue(deviceContext.isDeviceProtectedStorage());
final File defaultFile = new File(mContext.getFilesDir(), "test");
final File deviceFile = new File(deviceContext.getFilesDir(), "test");
assertFalse(deviceFile.equals(defaultFile));
deviceFile.createNewFile();
// Make sure storage areas are mutually exclusive
assertFalse(defaultFile.exists());
assertTrue(deviceFile.exists());
}
public void testMoveSharedPreferencesFrom() throws Exception {
final Context deviceContext = mContext.createDeviceProtectedStorageContext();
mContext.getSharedPreferences("test", Context.MODE_PRIVATE).edit().putInt("answer", 42)
.commit();
// Verify that we can migrate
assertTrue(deviceContext.moveSharedPreferencesFrom(mContext, "test"));
assertEquals(0, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
assertEquals(42, deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
// Trying to migrate again when already done is a no-op
assertTrue(deviceContext.moveSharedPreferencesFrom(mContext, "test"));
assertEquals(0, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
assertEquals(42, deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
// Add a new value and verify that we can migrate back
deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE).edit()
.putInt("question", 24).commit();
assertTrue(mContext.moveSharedPreferencesFrom(deviceContext, "test"));
assertEquals(42, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
assertEquals(24, mContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("question", 0));
assertEquals(0, deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("answer", 0));
assertEquals(0, deviceContext.getSharedPreferences("test", Context.MODE_PRIVATE)
.getInt("question", 0));
}
public void testMoveDatabaseFrom() throws Exception {
final Context deviceContext = mContext.createDeviceProtectedStorageContext();
SQLiteDatabase db = mContext.openOrCreateDatabase("test.db",
Context.MODE_PRIVATE | Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, null);
db.execSQL("CREATE TABLE list(item TEXT);");
db.execSQL("INSERT INTO list VALUES ('cat')");
db.execSQL("INSERT INTO list VALUES ('dog')");
db.close();
// Verify that we can migrate
assertTrue(deviceContext.moveDatabaseFrom(mContext, "test.db"));
db = deviceContext.openOrCreateDatabase("test.db",
Context.MODE_PRIVATE | Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, null);
Cursor c = db.query("list", null, null, null, null, null, null);
assertEquals(2, c.getCount());
assertTrue(c.moveToFirst());
assertEquals("cat", c.getString(0));
assertTrue(c.moveToNext());
assertEquals("dog", c.getString(0));
c.close();
db.execSQL("INSERT INTO list VALUES ('mouse')");
db.close();
// Trying to migrate again when already done is a no-op
assertTrue(deviceContext.moveDatabaseFrom(mContext, "test.db"));
// Verify that we can migrate back
assertTrue(mContext.moveDatabaseFrom(deviceContext, "test.db"));
db = mContext.openOrCreateDatabase("test.db",
Context.MODE_PRIVATE | Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, null);
c = db.query("list", null, null, null, null, null, null);
assertEquals(3, c.getCount());
assertTrue(c.moveToFirst());
assertEquals("cat", c.getString(0));
assertTrue(c.moveToNext());
assertEquals("dog", c.getString(0));
assertTrue(c.moveToNext());
assertEquals("mouse", c.getString(0));
c.close();
db.close();
}
public void testAccessTheme() {
mContext.setTheme(R.style.Test_Theme);
final Theme testTheme = mContext.getTheme();
assertNotNull(testTheme);
int[] attrs = {
android.R.attr.windowNoTitle,
android.R.attr.panelColorForeground,
android.R.attr.panelColorBackground
};
TypedArray attrArray = null;
try {
attrArray = testTheme.obtainStyledAttributes(attrs);
assertTrue(attrArray.getBoolean(0, false));
assertEquals(0xff000000, attrArray.getColor(1, 0));
assertEquals(0xffffffff, attrArray.getColor(2, 0));
} finally {
if (attrArray != null) {
attrArray.recycle();
attrArray = null;
}
}
// setTheme only works for the first time
mContext.setTheme(android.R.style.Theme_Black);
assertSame(testTheme, mContext.getTheme());
}
public void testObtainStyledAttributes() {
// Test obtainStyledAttributes(int[])
TypedArray testTypedArray = mContext
.obtainStyledAttributes(android.R.styleable.View);
assertNotNull(testTypedArray);
assertTrue(testTypedArray.length() > 2);
assertTrue(testTypedArray.length() > 0);
testTypedArray.recycle();
// Test obtainStyledAttributes(int, int[])
testTypedArray = mContext.obtainStyledAttributes(android.R.style.TextAppearance_Small,
android.R.styleable.TextAppearance);
assertNotNull(testTypedArray);
assertTrue(testTypedArray.length() > 2);
testTypedArray.recycle();
// Test wrong null array pointer
try {
testTypedArray = mContext.obtainStyledAttributes(-1, null);
fail("obtainStyledAttributes will throw a NullPointerException here.");
} catch (NullPointerException e) {
}
// Test obtainStyledAttributes(AttributeSet, int[]) with unavailable resource id.
int testInt[] = { 0, 0 };
testTypedArray = mContext.obtainStyledAttributes(-1, testInt);
// fail("Wrong resource id should not be accepted.");
assertNotNull(testTypedArray);
assertEquals(2, testTypedArray.length());
testTypedArray.recycle();
// Test obtainStyledAttributes(AttributeSet, int[])
int[] attrs = android.R.styleable.DatePicker;
testTypedArray = mContext.obtainStyledAttributes(getAttributeSet(R.layout.context_layout),
attrs);
assertNotNull(testTypedArray);
assertEquals(attrs.length, testTypedArray.length());
testTypedArray.recycle();
// Test obtainStyledAttributes(AttributeSet, int[], int, int)
testTypedArray = mContext.obtainStyledAttributes(getAttributeSet(R.layout.context_layout),
attrs, 0, 0);
assertNotNull(testTypedArray);
assertEquals(attrs.length, testTypedArray.length());
testTypedArray.recycle();
}
public void testGetSystemService() {
// Test invalid service name
assertNull(mContext.getSystemService("invalid"));
// Test valid service name
assertNotNull(mContext.getSystemService(Context.WINDOW_SERVICE));
}
public void testGetSystemServiceByClass() {
// Test invalid service class
assertNull(mContext.getSystemService(Object.class));
// Test valid service name
assertNotNull(mContext.getSystemService(WindowManager.class));
assertEquals(mContext.getSystemService(Context.WINDOW_SERVICE),
mContext.getSystemService(WindowManager.class));
}
public void testGetColorStateList() {
try {
mContext.getColorStateList(0);
fail("Failed at testGetColorStateList");
} catch (NotFoundException e) {
//expected
}
final ColorStateList colorStateList = mContext.getColorStateList(R.color.color2);
final int[] focusedState = {android.R.attr.state_focused};
final int focusColor = colorStateList.getColorForState(focusedState, R.color.failColor);
assertEquals(0xffff0000, focusColor);
}
public void testGetColor() {
try {
mContext.getColor(0);
fail("Failed at testGetColor");
} catch (NotFoundException e) {
//expected
}
final int color = mContext.getColor(R.color.color2);
assertEquals(0xffffff00, color);
}
/**
* Developers have come to expect at least ext4-style filename behavior, so
* verify that the underlying filesystem supports them.
*/
public void testFilenames() throws Exception {
final File base = mContext.getFilesDir();
assertValidFile(new File(base, "foo"));
assertValidFile(new File(base, ".bar"));
assertValidFile(new File(base, "foo.bar"));
assertValidFile(new File(base, "\u2603"));
assertValidFile(new File(base, "\uD83D\uDCA9"));
final int pid = android.os.Process.myPid();
final StringBuilder sb = new StringBuilder(255);
while (sb.length() <= 255) {
sb.append(pid);
sb.append(mContext.getPackageName());
}
sb.setLength(255);
final String longName = sb.toString();
final File longDir = new File(base, longName);
assertValidFile(longDir);
longDir.mkdir();
final File longFile = new File(longDir, longName);
assertValidFile(longFile);
}
public void testMainLooper() throws Exception {
final Thread mainThread = Looper.getMainLooper().getThread();
final Handler handler = new Handler(mContext.getMainLooper());
handler.post(() -> {
assertEquals(mainThread, Thread.currentThread());
});
}
public void testMainExecutor() throws Exception {
final Thread mainThread = Looper.getMainLooper().getThread();
mContext.getMainExecutor().execute(() -> {
assertEquals(mainThread, Thread.currentThread());
});
}
private void assertValidFile(File file) throws Exception {
Log.d(TAG, "Checking " + file);
if (file.exists()) {
assertTrue("File already exists and couldn't be deleted before test: " + file,
file.delete());
}
assertTrue("Failed to create " + file, file.createNewFile());
assertTrue("Doesn't exist after create " + file, file.exists());
assertTrue("Failed to delete after create " + file, file.delete());
new FileOutputStream(file).close();
assertTrue("Doesn't exist after stream " + file, file.exists());
assertTrue("Failed to delete after stream " + file, file.delete());
}
static void beginDocument(XmlPullParser parser, String firstElementName)
throws XmlPullParserException, IOException
{
int type;
while ((type=parser.next()) != parser.START_TAG
&& type != parser.END_DOCUMENT) {
;
}
if (type != parser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
if (!parser.getName().equals(firstElementName)) {
throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
", expected " + firstElementName);
}
}
private AttributeSet getAttributeSet(int resourceId) {
final XmlResourceParser parser = mContext.getResources().getXml(
resourceId);
try {
beginDocument(parser, "RelativeLayout");
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
final AttributeSet attr = Xml.asAttributeSet(parser);
assertNotNull(attr);
return attr;
}
private void registerBroadcastReceiver(BroadcastReceiver receiver, IntentFilter filter) {
// All of the broadcasts for tests that use this method are sent by the local app, so by
// default all receivers can be registered as not exported.
registerBroadcastReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED);
}
private void registerBroadcastReceiver(BroadcastReceiver receiver, IntentFilter filter,
int flags) {
mContext.registerReceiver(receiver, filter, flags);
mRegisteredReceiverList.add(receiver);
}
public void testSendOrderedBroadcast1() throws InterruptedException {
final HighPriorityBroadcastReceiver highPriorityReceiver =
new HighPriorityBroadcastReceiver();
final LowPriorityBroadcastReceiver lowPriorityReceiver =
new LowPriorityBroadcastReceiver();
final IntentFilter filterHighPriority = new IntentFilter(ResultReceiver.MOCK_ACTION);
filterHighPriority.setPriority(1);
final IntentFilter filterLowPriority = new IntentFilter(ResultReceiver.MOCK_ACTION);
registerBroadcastReceiver(highPriorityReceiver, filterHighPriority);
registerBroadcastReceiver(lowPriorityReceiver, filterLowPriority);
final Intent broadcastIntent = new Intent(ResultReceiver.MOCK_ACTION);
broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcast(broadcastIntent, null);
new PollingCheck(BROADCAST_TIMEOUT) {
@Override
protected boolean check() {
return highPriorityReceiver.hasReceivedBroadCast()
&& !lowPriorityReceiver.hasReceivedBroadCast();
}
}.run();
synchronized (highPriorityReceiver) {
highPriorityReceiver.notify();
}
new PollingCheck(BROADCAST_TIMEOUT) {
@Override
protected boolean check() {
return highPriorityReceiver.hasReceivedBroadCast()
&& lowPriorityReceiver.hasReceivedBroadCast();
}
}.run();
}
public void testSendOrderedBroadcast2() throws InterruptedException {
final TestBroadcastReceiver broadcastReceiver = new TestBroadcastReceiver();
broadcastReceiver.mIsOrderedBroadcasts = true;
Bundle bundle = new Bundle();
bundle.putString(KEY_KEPT, VALUE_KEPT);
bundle.putString(KEY_REMOVED, VALUE_REMOVED);
Intent intent = new Intent(ResultReceiver.MOCK_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcast(intent, null, broadcastReceiver, null, 1,
INTIAL_RESULT, bundle);
synchronized (mLockObj) {
try {
mLockObj.wait(BROADCAST_TIMEOUT);
} catch (InterruptedException e) {
fail("unexpected InterruptedException.");
}
}
assertTrue("Receiver didn't make any response.", broadcastReceiver.hadReceivedBroadCast());
assertEquals("Incorrect code: " + broadcastReceiver.getResultCode(), 3,
broadcastReceiver.getResultCode());
assertEquals(ACTUAL_RESULT, broadcastReceiver.getResultData());
Bundle resultExtras = broadcastReceiver.getResultExtras(false);
assertEquals(VALUE_ADDED, resultExtras.getString(KEY_ADDED));
assertEquals(VALUE_KEPT, resultExtras.getString(KEY_KEPT));
assertNull(resultExtras.getString(KEY_REMOVED));
}
public void testSendOrderedBroadcastWithAppOp() {
// we use a HighPriorityBroadcastReceiver because the final receiver should get the
// broadcast only at the end.
final ResultReceiver receiver = new HighPriorityBroadcastReceiver();
final ResultReceiver finalReceiver = new ResultReceiver();
AppOpsManager aom =
(AppOpsManager) getContextUnderTest().getSystemService(Context.APP_OPS_SERVICE);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(aom,
(appOpsMan) -> appOpsMan.setUidMode(AppOpsManager.OPSTR_READ_CELL_BROADCASTS,
Process.myUid(), AppOpsManager.MODE_ALLOWED));
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
mContext.sendOrderedBroadcast(
new Intent(ResultReceiver.MOCK_ACTION),
null, // permission
AppOpsManager.OPSTR_READ_CELL_BROADCASTS,
finalReceiver,
null, // scheduler
0, // initial code
null, //initial data
null); // initial extras
new PollingCheck(BROADCAST_TIMEOUT){
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast()
&& !finalReceiver.hasReceivedBroadCast();
}
}.run();
synchronized (receiver) {
receiver.notify();
}
new PollingCheck(BROADCAST_TIMEOUT){
@Override
protected boolean check() {
// ensure that first receiver has received broadcast before final receiver
return receiver.hasReceivedBroadCast()
&& finalReceiver.hasReceivedBroadCast();
}
}.run();
}
public void testSendOrderedBroadcastWithAppOp_NotGranted() {
final ResultReceiver receiver = new ResultReceiver();
AppOpsManager aom =
(AppOpsManager) getContextUnderTest().getSystemService(Context.APP_OPS_SERVICE);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(aom,
(appOpsMan) -> appOpsMan.setUidMode(AppOpsManager.OPSTR_READ_CELL_BROADCASTS,
Process.myUid(), AppOpsManager.MODE_ERRORED));
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
mContext.sendOrderedBroadcast(
new Intent(ResultReceiver.MOCK_ACTION),
null, // permission
AppOpsManager.OPSTR_READ_CELL_BROADCASTS,
null, // final receiver
null, // scheduler
0, // initial code
null, //initial data
null); // initial extras
boolean broadcastNeverSent = false;
try {
new PollingCheck(BROADCAST_TIMEOUT) {
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
public void runWithInterruption() throws InterruptedException {
if (check()) {
return;
}
long timeout = BROADCAST_TIMEOUT;
while (timeout > 0) {
try {
Thread.sleep(50 /* time slice */);
} catch (InterruptedException e) {
fail("unexpected InterruptedException");
}
if (check()) {
return;
}
timeout -= 50; // time slice
}
throw new InterruptedException();
}
}.runWithInterruption();
} catch (InterruptedException e) {
broadcastNeverSent = true;
}
assertTrue(broadcastNeverSent);
}
public void testRegisterReceiver1() throws InterruptedException {
final FilteredReceiver broadcastReceiver = new FilteredReceiver();
final IntentFilter filter = new IntentFilter(MOCK_ACTION1);
// Test registerReceiver
mContext.registerReceiver(broadcastReceiver, filter);
// Test unwanted intent(action = MOCK_ACTION2)
broadcastReceiver.reset();
waitForFilteredIntent(mContext, MOCK_ACTION2);
assertFalse(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
// Send wanted intent(action = MOCK_ACTION1)
broadcastReceiver.reset();
waitForFilteredIntent(mContext, MOCK_ACTION1);
assertTrue(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
mContext.unregisterReceiver(broadcastReceiver);
// Test unregisterReceiver
FilteredReceiver broadcastReceiver2 = new FilteredReceiver();
mContext.registerReceiver(broadcastReceiver2, filter);
mContext.unregisterReceiver(broadcastReceiver2);
// Test unwanted intent(action = MOCK_ACTION2)
broadcastReceiver2.reset();
waitForFilteredIntent(mContext, MOCK_ACTION2);
assertFalse(broadcastReceiver2.hadReceivedBroadCast1());
assertFalse(broadcastReceiver2.hadReceivedBroadCast2());
// Send wanted intent(action = MOCK_ACTION1), but the receiver is unregistered.
broadcastReceiver2.reset();
waitForFilteredIntent(mContext, MOCK_ACTION1);
assertFalse(broadcastReceiver2.hadReceivedBroadCast1());
assertFalse(broadcastReceiver2.hadReceivedBroadCast2());
}
public void testRegisterReceiver2() throws InterruptedException {
FilteredReceiver broadcastReceiver = new FilteredReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(MOCK_ACTION1);
// Test registerReceiver
mContext.registerReceiver(broadcastReceiver, filter, null, null);
// Test unwanted intent(action = MOCK_ACTION2)
broadcastReceiver.reset();
waitForFilteredIntent(mContext, MOCK_ACTION2);
assertFalse(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
// Send wanted intent(action = MOCK_ACTION1)
broadcastReceiver.reset();
waitForFilteredIntent(mContext, MOCK_ACTION1);
assertTrue(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
mContext.unregisterReceiver(broadcastReceiver);
}
public void testRegisterReceiverForAllUsers() throws InterruptedException {
FilteredReceiver broadcastReceiver = new FilteredReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(MOCK_ACTION1);
// Test registerReceiverForAllUsers without permission: verify SecurityException.
try {
mContext.registerReceiverForAllUsers(broadcastReceiver, filter, null, null);
fail("testRegisterReceiverForAllUsers: "
+ "SecurityException expected on registerReceiverForAllUsers");
} catch (SecurityException se) {
// expected
}
// Test registerReceiverForAllUsers with permission.
try {
ShellIdentityUtils.invokeMethodWithShellPermissions(
mContext,
(ctx) -> ctx.registerReceiverForAllUsers(broadcastReceiver, filter, null, null)
);
} catch (SecurityException se) {
fail("testRegisterReceiverForAllUsers: SecurityException not expected");
}
// Test unwanted intent(action = MOCK_ACTION2)
broadcastReceiver.reset();
waitForFilteredIntent(mContext, MOCK_ACTION2);
assertFalse(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
// Send wanted intent(action = MOCK_ACTION1)
broadcastReceiver.reset();
waitForFilteredIntent(mContext, MOCK_ACTION1);
assertTrue(broadcastReceiver.hadReceivedBroadCast1());
assertEquals(broadcastReceiver.getSendingUser(), Process.myUserHandle());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
mContext.unregisterReceiver(broadcastReceiver);
}
public void testAccessWallpaper() throws IOException, InterruptedException {
if (!isWallpaperSupported()) return;
// set Wallpaper by context#setWallpaper(Bitmap)
Bitmap bitmap = Bitmap.createBitmap(20, 30, Bitmap.Config.RGB_565);
// Test getWallpaper
Drawable testDrawable = mContext.getWallpaper();
// Test peekWallpaper
Drawable testDrawable2 = mContext.peekWallpaper();
mContext.setWallpaper(bitmap);
mWallpaperChanged = true;
synchronized(this) {
wait(500);
}
assertNotSame(testDrawable, mContext.peekWallpaper());
assertNotNull(mContext.getWallpaper());
assertNotSame(testDrawable2, mContext.peekWallpaper());
assertNotNull(mContext.peekWallpaper());
// set Wallpaper by context#setWallpaper(InputStream)
mContext.clearWallpaper();
testDrawable = mContext.getWallpaper();
InputStream stream = mContext.getResources().openRawResource(R.drawable.scenery);
mContext.setWallpaper(stream);
synchronized (this) {
wait(1000);
}
assertNotSame(testDrawable, mContext.peekWallpaper());
}
public void testAccessDatabase() {
String DATABASE_NAME = "databasetest";
String DATABASE_NAME1 = DATABASE_NAME + "1";
String DATABASE_NAME2 = DATABASE_NAME + "2";
SQLiteDatabase mDatabase;
File mDatabaseFile;
SQLiteDatabase.CursorFactory factory = new SQLiteDatabase.CursorFactory() {
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
String editTable, SQLiteQuery query) {
return new android.database.sqlite.SQLiteCursor(db, masterQuery, editTable, query) {
@Override
public boolean requery() {
setSelectionArguments(new String[] { "2" });
return super.requery();
}
};
}
};
// FIXME: Move cleanup into tearDown()
for (String db : mContext.databaseList()) {
File f = mContext.getDatabasePath(db);
if (f.exists()) {
mContext.deleteDatabase(db);
}
}
// Test openOrCreateDatabase with null and actual factory
mDatabase = mContext.openOrCreateDatabase(DATABASE_NAME1,
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, factory);
assertNotNull(mDatabase);
mDatabase.close();
mDatabase = mContext.openOrCreateDatabase(DATABASE_NAME2,
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING, factory);
assertNotNull(mDatabase);
mDatabase.close();
// Test getDatabasePath
File actualDBPath = mContext.getDatabasePath(DATABASE_NAME1);
// Test databaseList()
List<String> list = Arrays.asList(mContext.databaseList());
assertTrue("1) database list: " + list, list.contains(DATABASE_NAME1));
assertTrue("2) database list: " + list, list.contains(DATABASE_NAME2));
// Test deleteDatabase()
for (int i = 1; i < 3; i++) {
mDatabaseFile = mContext.getDatabasePath(DATABASE_NAME + i);
assertTrue(mDatabaseFile.exists());
mContext.deleteDatabase(DATABASE_NAME + i);
mDatabaseFile = new File(actualDBPath, DATABASE_NAME + i);
assertFalse(mDatabaseFile.exists());
}
}
public void testEnforceUriPermission1() {
try {
Uri uri = Uri.parse("content://ctstest");
mContext.enforceUriPermission(uri, Binder.getCallingPid(),
Binder.getCallingUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
"enforceUriPermission is not working without possessing an IPC.");
fail("enforceUriPermission is not working without possessing an IPC.");
} catch (SecurityException e) {
// If the function is OK, it should throw a SecurityException here because currently no
// IPC is handled by this process.
}
}
public void testEnforceUriPermission2() {
Uri uri = Uri.parse("content://ctstest");
try {
mContext.enforceUriPermission(uri, NOT_GRANTED_PERMISSION,
NOT_GRANTED_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(),
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
"enforceUriPermission is not working without possessing an IPC.");
fail("enforceUriPermission is not working without possessing an IPC.");
} catch (SecurityException e) {
// If the function is ok, it should throw a SecurityException here because currently no
// IPC is handled by this process.
}
}
public void testGetPackageResourcePath() {
assertNotNull(mContext.getPackageResourcePath());
}
public void testStartActivityWithActivityNotFound() {
Intent intent = new Intent(mContext, ContextCtsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
mContext.startActivity(intent);
fail("Test startActivity should throw a ActivityNotFoundException here.");
} catch (ActivityNotFoundException e) {
// Because ContextWrapper is a wrapper class, so no need to test
// the details of the function's performance. Getting a result
// from the wrapped class is enough for testing.
}
}
public void testStartActivities() throws Exception {
final Intent[] intents = {
new Intent().setComponent(new ComponentName(mContext,
AvailableIntentsActivity.class)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
new Intent().setComponent(new ComponentName(mContext,
ImageCaptureActivity.class)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
};
final Instrumentation.ActivityMonitor firstMonitor = getInstrumentation()
.addMonitor(AvailableIntentsActivity.class.getName(), null /* result */,
false /* block */);
final Instrumentation.ActivityMonitor secondMonitor = getInstrumentation()
.addMonitor(ImageCaptureActivity.class.getName(), null /* result */,
false /* block */);
mContext.startActivities(intents);
Activity firstActivity = getInstrumentation().waitForMonitorWithTimeout(firstMonitor, 5000);
assertNotNull(firstActivity);
Activity secondActivity = getInstrumentation().waitForMonitorWithTimeout(secondMonitor,
5000);
assertNotNull(secondActivity);
}
public void testStartActivityAsUser() {
try (ActivitySession activitySession = new ActivitySession()) {
Intent intent = new Intent(mContext, AvailableIntentsActivity.class);
activitySession.assertActivityLaunched(intent.getComponent().getClassName(),
() -> SystemUtil.runWithShellPermissionIdentity(() ->
mContext.startActivityAsUser(intent, UserHandle.CURRENT)));
}
}
public void testStartActivity() {
try (ActivitySession activitySession = new ActivitySession()) {
Intent intent = new Intent(mContext, AvailableIntentsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activitySession.assertActivityLaunched(intent.getComponent().getClassName(),
() -> mContext.startActivity(intent));
}
}
/**
* Helper class to launch / close test activity.
*/
private class ActivitySession implements AutoCloseable {
private Activity mTestActivity;
private static final int ACTIVITY_LAUNCH_TIMEOUT = 5000;
void assertActivityLaunched(String activityClassName, Runnable activityStarter) {
final Instrumentation.ActivityMonitor monitor = getInstrumentation()
.addMonitor(activityClassName, null /* result */,
false /* block */);
activityStarter.run();
// Wait for activity launch with timeout.
mTestActivity = getInstrumentation().waitForMonitorWithTimeout(monitor,
ACTIVITY_LAUNCH_TIMEOUT);
assertNotNull(mTestActivity);
}
@Override
public void close() {
if (mTestActivity != null) {
mTestActivity.finishAndRemoveTask();
}
}
}
public void testCreatePackageContext() throws PackageManager.NameNotFoundException {
Context actualContext = mContext.createPackageContext("com.android.shell",
Context.CONTEXT_IGNORE_SECURITY);
assertNotNull(actualContext);
}
public void testCreatePackageContextAsUser() throws Exception {
for (UserHandle user : new UserHandle[] {
android.os.Process.myUserHandle(),
UserHandle.ALL, UserHandle.CURRENT, UserHandle.SYSTEM
}) {
assertEquals(user, mContext
.createPackageContextAsUser("com.android.shell", 0, user).getUser());
}
}
public void testCreateContextAsUser() throws Exception {
for (UserHandle user : new UserHandle[] {
android.os.Process.myUserHandle(),
UserHandle.ALL, UserHandle.CURRENT, UserHandle.SYSTEM
}) {
assertEquals(user, mContext.createContextAsUser(user, 0).getUser());
}
}
public void testGetMainLooper() {
assertNotNull(mContext.getMainLooper());
}
public void testGetApplicationContext() {
assertSame(mContext.getApplicationContext(), mContext.getApplicationContext());
}
public void testGetSharedPreferences() {
SharedPreferences sp;
SharedPreferences localSP;
sp = PreferenceManager.getDefaultSharedPreferences(mContext);
String packageName = mContext.getPackageName();
localSP = mContext.getSharedPreferences(packageName + "_preferences",
Context.MODE_PRIVATE);
assertSame(sp, localSP);
}
public void testRevokeUriPermission() {
Uri uri = Uri.parse("contents://ctstest");
mContext.revokeUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
public void testAccessService() throws InterruptedException {
MockContextService.reset();
bindExpectResult(mContext, new Intent(mContext, MockContextService.class));
// Check startService
assertTrue(MockContextService.hadCalledOnStart());
// Check bindService
assertTrue(MockContextService.hadCalledOnBind());
assertTrue(MockContextService.hadCalledOnDestory());
// Check unbinService
assertTrue(MockContextService.hadCalledOnUnbind());
}
public void testGetPackageCodePath() {
assertNotNull(mContext.getPackageCodePath());
}
public void testGetPackageName() {
assertEquals("android.content.cts", mContext.getPackageName());
}
public void testGetCacheDir() {
assertNotNull(mContext.getCacheDir());
}
public void testGetContentResolver() {
assertSame(mContext.getContentResolver(), mContext.getContentResolver());
}
public void testGetFileStreamPath() {
String TEST_FILENAME = "TestGetFileStreamPath";
// Test the path including the input filename
String fileStreamPath = mContext.getFileStreamPath(TEST_FILENAME).toString();
assertTrue(fileStreamPath.indexOf(TEST_FILENAME) >= 0);
}
public void testGetClassLoader() {
assertSame(mContext.getClassLoader(), mContext.getClassLoader());
}
public void testGetWallpaperDesiredMinimumHeightAndWidth() {
if (!isWallpaperSupported()) return;
int height = mContext.getWallpaperDesiredMinimumHeight();
int width = mContext.getWallpaperDesiredMinimumWidth();
// returned value is <= 0, the caller should use the height of the
// default display instead.
// That is to say, the return values of desired minimumHeight and
// minimunWidth are at the same side of 0-dividing line.
assertTrue((height > 0 && width > 0) || (height <= 0 && width <= 0));
}
public void testAccessStickyBroadcast() throws InterruptedException {
ResultReceiver resultReceiver = new ResultReceiver();
Intent intent = new Intent(MOCK_STICKY_ACTION);
TestBroadcastReceiver stickyReceiver = new TestBroadcastReceiver();
mContext.sendStickyBroadcast(intent);
waitForReceiveBroadCast(resultReceiver);
assertEquals(intent.getAction(), mContext.registerReceiver(stickyReceiver,
new IntentFilter(MOCK_STICKY_ACTION)).getAction());
synchronized (mLockObj) {
mLockObj.wait(BROADCAST_TIMEOUT);
}
assertTrue("Receiver didn't make any response.", stickyReceiver.hadReceivedBroadCast());
mContext.unregisterReceiver(stickyReceiver);
mContext.removeStickyBroadcast(intent);
assertNull(mContext.registerReceiver(stickyReceiver,
new IntentFilter(MOCK_STICKY_ACTION)));
mContext.unregisterReceiver(stickyReceiver);
}
public void testCheckCallingOrSelfUriPermissions() {
List<Uri> uris = new ArrayList<>();
Uri uri1 = Uri.parse("content://ctstest1");
uris.add(uri1);
Uri uri2 = Uri.parse("content://ctstest2");
uris.add(uri2);
int[] retValue = mContext.checkCallingOrSelfUriPermissions(uris,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(retValue.length, 2);
// This package does not have access to the given URIs
assertEquals(PERMISSION_DENIED, retValue[0]);
assertEquals(PERMISSION_DENIED, retValue[1]);
}
public void testCheckCallingOrSelfUriPermission() {
Uri uri = Uri.parse("content://ctstest");
int retValue = mContext.checkCallingOrSelfUriPermission(uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, retValue);
}
public void testGrantUriPermission() {
mContext.grantUriPermission("com.android.mms", Uri.parse("contents://ctstest"),
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
public void testCheckPermissionGranted() {
int returnValue = mContext.checkPermission(
GRANTED_PERMISSION, Process.myPid(), Process.myUid());
assertEquals(PackageManager.PERMISSION_GRANTED, returnValue);
}
public void testCheckPermissionNotGranted() {
int returnValue = mContext.checkPermission(
NOT_GRANTED_PERMISSION, Process.myPid(), Process.myUid());
assertEquals(PackageManager.PERMISSION_DENIED, returnValue);
}
public void testCheckPermissionRootUser() {
// Test with root user, everything will be granted.
int returnValue = mContext.checkPermission(NOT_GRANTED_PERMISSION, 1, ROOT_UID);
assertEquals(PackageManager.PERMISSION_GRANTED, returnValue);
}
public void testCheckPermissionInvalidRequest() {
// Test with null permission.
try {
int returnValue = mContext.checkPermission(null, 0, ROOT_UID);
fail("checkPermission should not accept null permission");
} catch (IllegalArgumentException e) {
}
// Test with invalid uid and included granted permission.
int returnValue = mContext.checkPermission(GRANTED_PERMISSION, 1, -11);
assertEquals(PackageManager.PERMISSION_DENIED, returnValue);
}
public void testCheckSelfPermissionGranted() {
int returnValue = mContext.checkSelfPermission(GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_GRANTED, returnValue);
}
public void testCheckSelfPermissionNotGranted() {
int returnValue = mContext.checkSelfPermission(NOT_GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, returnValue);
}
public void testEnforcePermissionGranted() {
mContext.enforcePermission(
GRANTED_PERMISSION, Process.myPid(), Process.myUid(),
"permission isn't granted");
}
public void testEnforcePermissionNotGranted() {
try {
mContext.enforcePermission(
NOT_GRANTED_PERMISSION, Process.myPid(), Process.myUid(),
"permission isn't granted");
fail("Permission shouldn't be granted.");
} catch (SecurityException expected) {
}
}
public void testCheckCallingOrSelfPermission_noIpc() {
// There's no ongoing Binder call, so this package's permissions are checked.
int retValue = mContext.checkCallingOrSelfPermission(GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_GRANTED, retValue);
retValue = mContext.checkCallingOrSelfPermission(NOT_GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, retValue);
}
public void testCheckCallingOrSelfPermission_ipc() throws Exception {
bindBinderPermissionTestService();
try {
int retValue = mBinderPermissionTestService.doCheckCallingOrSelfPermission(
GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_GRANTED, retValue);
retValue = mBinderPermissionTestService.doCheckCallingOrSelfPermission(
NOT_GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, retValue);
} finally {
mContext.unbindService(mBinderPermissionTestConnection);
}
}
public void testEnforceCallingOrSelfPermission_noIpc() {
// There's no ongoing Binder call, so this package's permissions are checked.
mContext.enforceCallingOrSelfPermission(
GRANTED_PERMISSION, "permission isn't granted");
try {
mContext.enforceCallingOrSelfPermission(
NOT_GRANTED_PERMISSION, "permission isn't granted");
fail("Permission shouldn't be granted.");
} catch (SecurityException expected) {
}
}
public void testEnforceCallingOrSelfPermission_ipc() throws Exception {
bindBinderPermissionTestService();
try {
mBinderPermissionTestService.doEnforceCallingOrSelfPermission(GRANTED_PERMISSION);
try {
mBinderPermissionTestService.doEnforceCallingOrSelfPermission(
NOT_GRANTED_PERMISSION);
fail("Permission shouldn't be granted.");
} catch (SecurityException expected) {
}
} finally {
mContext.unbindService(mBinderPermissionTestConnection);
}
}
public void testCheckCallingPermission_noIpc() {
// Denied because no IPC is active.
int retValue = mContext.checkCallingPermission(GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, retValue);
}
public void testEnforceCallingPermission_noIpc() {
try {
mContext.enforceCallingPermission(
GRANTED_PERMISSION,
"enforceCallingPermission is not working without possessing an IPC.");
fail("enforceCallingPermission is not working without possessing an IPC.");
} catch (SecurityException e) {
// Currently no IPC is handled by this process, this exception is expected
}
}
public void testEnforceCallingPermission_ipc() throws Exception {
bindBinderPermissionTestService();
try {
mBinderPermissionTestService.doEnforceCallingPermission(GRANTED_PERMISSION);
try {
mBinderPermissionTestService.doEnforceCallingPermission(NOT_GRANTED_PERMISSION);
fail("Permission shouldn't be granted.");
} catch (SecurityException expected) {
}
} finally {
mContext.unbindService(mBinderPermissionTestConnection);
}
}
public void testCheckCallingPermission_ipc() throws Exception {
bindBinderPermissionTestService();
try {
int returnValue = mBinderPermissionTestService.doCheckCallingPermission(
GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_GRANTED, returnValue);
returnValue = mBinderPermissionTestService.doCheckCallingPermission(
NOT_GRANTED_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, returnValue);
} finally {
mContext.unbindService(mBinderPermissionTestConnection);
}
}
private void bindBinderPermissionTestService() {
Intent intent = new Intent(mContext, IBinderPermissionTestService.class);
intent.setComponent(new ComponentName(
"com.android.cts", "com.android.cts.BinderPermissionTestService"));
mBinderPermissionTestConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBinderPermissionTestService =
IBinderPermissionTestService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
assertTrue("Service not bound", mContext.bindService(
intent, mBinderPermissionTestConnection, Context.BIND_AUTO_CREATE));
new PollingCheck(15 * 1000) {
protected boolean check() {
return mBinderPermissionTestService != null; // Service was bound.
}
}.run();
}
public void testCheckUriPermissions() {
List<Uri> uris = new ArrayList<>();
Uri uri1 = Uri.parse("content://ctstest1");
uris.add(uri1);
Uri uri2 = Uri.parse("content://ctstest2");
uris.add(uri2);
// Root has access to all URIs
int[] retValue = mContext.checkUriPermissions(uris, Binder.getCallingPid(), 0,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(retValue.length, 2);
assertEquals(PERMISSION_GRANTED, retValue[0]);
assertEquals(PERMISSION_GRANTED, retValue[1]);
retValue = mContext.checkUriPermissions(uris, Binder.getCallingPid(),
Binder.getCallingUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(retValue.length, 2);
// This package does not have access to the given URIs
assertEquals(PERMISSION_DENIED, retValue[0]);
assertEquals(PERMISSION_DENIED, retValue[1]);
}
public void testCheckUriPermission1() {
Uri uri = Uri.parse("content://ctstest");
int retValue = mContext.checkUriPermission(uri, Binder.getCallingPid(), 0,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(PackageManager.PERMISSION_GRANTED, retValue);
retValue = mContext.checkUriPermission(uri, Binder.getCallingPid(),
Binder.getCallingUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, retValue);
}
public void testCheckUriPermission2() {
Uri uri = Uri.parse("content://ctstest");
int retValue = mContext.checkUriPermission(uri, NOT_GRANTED_PERMISSION,
NOT_GRANTED_PERMISSION, Binder.getCallingPid(), 0,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(PackageManager.PERMISSION_GRANTED, retValue);
retValue = mContext.checkUriPermission(uri, NOT_GRANTED_PERMISSION,
NOT_GRANTED_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(),
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, retValue);
}
public void testCheckCallingUriPermissions() {
List<Uri> uris = new ArrayList<>();
Uri uri1 = Uri.parse("content://ctstest1");
uris.add(uri1);
Uri uri2 = Uri.parse("content://ctstest2");
uris.add(uri2);
int[] retValue = mContext.checkCallingUriPermissions(uris,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(retValue.length, 2);
// This package does not have access to the given URIs
assertEquals(PERMISSION_DENIED, retValue[0]);
assertEquals(PERMISSION_DENIED, retValue[1]);
}
public void testCheckCallingUriPermission() {
Uri uri = Uri.parse("content://ctstest");
int retValue = mContext.checkCallingUriPermission(uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
assertEquals(PackageManager.PERMISSION_DENIED, retValue);
}
public void testEnforceCallingUriPermission() {
try {
Uri uri = Uri.parse("content://ctstest");
mContext.enforceCallingUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
"enforceCallingUriPermission is not working without possessing an IPC.");
fail("enforceCallingUriPermission is not working without possessing an IPC.");
} catch (SecurityException e) {
// If the function is OK, it should throw a SecurityException here because currently no
// IPC is handled by this process.
}
}
public void testGetDir() {
File dir = mContext.getDir("testpath", Context.MODE_PRIVATE);
assertNotNull(dir);
dir.delete();
}
public void testGetPackageManager() {
assertSame(mContext.getPackageManager(), mContext.getPackageManager());
}
public void testSendBroadcast1() throws InterruptedException {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
mContext.sendBroadcast(new Intent(ResultReceiver.MOCK_ACTION));
new PollingCheck(BROADCAST_TIMEOUT){
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
}.run();
}
public void testSendBroadcast2() throws InterruptedException {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
mContext.sendBroadcast(new Intent(ResultReceiver.MOCK_ACTION), null);
new PollingCheck(BROADCAST_TIMEOUT){
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
}.run();
}
/**
* Verify the receiver should get the broadcast since it has all of the required permissions.
*/
public void testSendBroadcastRequireAllOfPermissions_receiverHasAllPermissions()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setRequireAllOfPermissions(
new String[] { // this test APK has both these permissions
android.Manifest.permission.ACCESS_WIFI_STATE,
android.Manifest.permission.ACCESS_NETWORK_STATE
});
mContext.sendBroadcast(new Intent(ResultReceiver.MOCK_ACTION), null,
options.toBundle());
new PollingCheck(BROADCAST_TIMEOUT) {
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
}.run();
}
/** The receiver should not get the broadcast if it does not have all the permissions. */
public void testSendBroadcastRequireAllOfPermissions_receiverHasSomePermissions()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setRequireAllOfPermissions(
new String[] { // this test APK only has ACCESS_WIFI_STATE
android.Manifest.permission.ACCESS_WIFI_STATE,
android.Manifest.permission.NETWORK_STACK,
});
mContext.sendBroadcast(
new Intent(ResultReceiver.MOCK_ACTION), null,
options.toBundle());
Thread.sleep(BROADCAST_TIMEOUT);
assertFalse(receiver.hasReceivedBroadCast());
}
/**
* Verify the receiver will get the broadcast since it has none of the excluded permissions.
*/
public void testSendBroadcastRequireNoneOfPermissions_receiverHasNoneOfExcludedPermissions()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setRequireAllOfPermissions(
new String[] { // this test APK has both these permissions
android.Manifest.permission.ACCESS_WIFI_STATE,
android.Manifest.permission.ACCESS_NETWORK_STATE
});
options.setRequireNoneOfPermissions(
new String[] { // test package does not have NETWORK_STACK
android.Manifest.permission.NETWORK_STACK
});
mContext.sendBroadcast(new Intent(ResultReceiver.MOCK_ACTION), null,
options.toBundle());
new PollingCheck(BROADCAST_TIMEOUT) {
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
}.run();
}
/**
* Verify the receiver will not get the broadcast since it has one of the excluded permissions.
*/
public void testSendBroadcastRequireNoneOfPermissions_receiverHasExcludedPermissions()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setRequireAllOfPermissions(
new String[] { // this test APK has ACCESS_WIFI_STATE
android.Manifest.permission.ACCESS_WIFI_STATE
});
options.setRequireNoneOfPermissions(
new String[] { // test package has ACCESS_NETWORK_STATE
android.Manifest.permission.ACCESS_NETWORK_STATE
});
mContext.sendBroadcast(new Intent(ResultReceiver.MOCK_ACTION), null,
options.toBundle());
Thread.sleep(BROADCAST_TIMEOUT);
assertFalse(receiver.hasReceivedBroadCast());
}
/** The receiver should get the broadcast if it has all the permissions. */
public void testSendBroadcastWithMultiplePermissions_receiverHasAllPermissions()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
mContext.sendBroadcastWithMultiplePermissions(
new Intent(ResultReceiver.MOCK_ACTION),
new String[] { // this test APK has both these permissions
android.Manifest.permission.ACCESS_WIFI_STATE,
android.Manifest.permission.ACCESS_NETWORK_STATE,
});
new PollingCheck(BROADCAST_TIMEOUT) {
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
}.run();
}
/** The receiver should not get the broadcast if it does not have all the permissions. */
public void testSendBroadcastWithMultiplePermissions_receiverHasSomePermissions()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
mContext.sendBroadcastWithMultiplePermissions(
new Intent(ResultReceiver.MOCK_ACTION),
new String[] { // this test APK only has ACCESS_WIFI_STATE
android.Manifest.permission.ACCESS_WIFI_STATE,
android.Manifest.permission.NETWORK_STACK,
});
Thread.sleep(BROADCAST_TIMEOUT);
assertFalse(receiver.hasReceivedBroadCast());
}
/** The receiver should not get the broadcast if it has none of the permissions. */
public void testSendBroadcastWithMultiplePermissions_receiverHasNoPermissions()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION));
mContext.sendBroadcastWithMultiplePermissions(
new Intent(ResultReceiver.MOCK_ACTION),
new String[] { // this test APK has neither of these permissions
android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_STACK,
});
Thread.sleep(BROADCAST_TIMEOUT);
assertFalse(receiver.hasReceivedBroadCast());
}
/**
* Starting from Android 13, a SecurityException is thrown for apps targeting this
* release or later that do not specify {@link Context#RECEIVER_EXPORTED} or {@link
* Context#RECEIVER_NOT_EXPORTED} when registering for non-system broadcasts.
*/
// TODO(b/206699109): Re-enable test when instrumentation workaround is removed; without a flag
// specified the instrumentation workaround automatically adds RECEIVER_EXPORTED.
@Suppress
public void testRegisterReceiver_noFlags_exceptionThrown() throws Exception {
try {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION), 0);
fail("An app targeting Android 13 and registering a dynamic receiver for a "
+ "non-system broadcast must receive a SecurityException if "
+ "RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED is not specified");
} catch (SecurityException expected) {
}
}
/**
* An app targeting Android 13 or later can register for system broadcasts without specifying
* {@link Context#RECEIVER_EXPORTED} or {@link Context@RECEIVER_NOT_EXPORTED}.
*/
public void testRegisterReceiver_noFlagsProtectedBroadcast_noExceptionThrown()
throws Exception {
final ResultReceiver receiver = new ResultReceiver();
// Intent.ACTION_SCREEN_OFF is a system broadcast and thus should not require a flag
// indicating whether the receiver is exported.
registerBroadcastReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF), 0);
}
/**
* An app targeting Android 13 or later can request a sticky broadcast via
* {@code Context#registerReceiver} without specifying {@link Context#RECEIVER_EXPORTED} or
* {@link Context#RECEIVER_NOT_EXPORTED}.
*/
public void testRegisterReceiver_noFlagsStickyBroadcast_noExceptionThrown() throws Exception {
// If a null receiver is specified to Context#registerReceiver, it indicates the caller
// is requesting a sticky broadcast without actually registering a receiver; a flag
// must not be required in this case.
mContext.registerReceiver(null, new IntentFilter(ResultReceiver.MOCK_ACTION), 0);
}
/**
* Starting from Android 13, an app targeting this release or later must specify one of either
* {@link Context#RECEIVER_EXPORTED} or {@link Context#RECEIVER_NOT_EXPORTED} when registering
* a receiver for non-system broadcasts; however if both are specified then an
* {@link IllegalArgumentException} should be thrown.
*/
public void testRegisterReceiver_bothFlags_exceptionThrown() throws Exception {
try {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION),
Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED);
fail("An app invoke invoking Context#registerReceiver with both RECEIVER_EXPORTED and"
+ " RECEIVER_NOT_EXPORTED set must receive an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
}
/**
* Verifies a receiver registered with {@link Context#RECEIVER_EXPORTED} can receive a
* broadcast from an external app.
*
* <p>The broadcast is sent as a shell command since this most closely simulates sending a
* broadcast from an external app; sending the broadcast via {@code
* ShellIdentityUtils#invokeMethodWithShellPermissionsNoReturn} is still delivered even to
* apps that use {@link Context#RECEIVER_NOT_EXPORTED}.
*/
public void testRegisterReceiver_exported_broadcastReceived() throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION),
Context.RECEIVER_EXPORTED);
SystemUtil.runShellCommand(EXTERNAL_APP_BROADCAST_COMMAND);
new PollingCheck(BROADCAST_TIMEOUT, "The broadcast to the exported receiver"
+ " was not received within the timeout window") {
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
}.run();
}
/**
* Verifies a receiver registered with {@link Context#RECEIVER_EXPORTED_UNAUDITED} can receive
* a broadcast from an external app.
*
* <p>{@code Context#RECEIVER_EXPORTED_UNAUDITED} is only intended to be applied to receivers
* that have not yet been audited to determine their intended exported state; this test ensures
* this flag maintains the existing behavior of exporting the receiver until it can be
* evaluated.
*/
public void testRegisterReceiver_exportedUnaudited_broadcastReceived() throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION),
Context.RECEIVER_EXPORTED_UNAUDITED);
SystemUtil.runShellCommand(EXTERNAL_APP_BROADCAST_COMMAND);
new PollingCheck(BROADCAST_TIMEOUT, "The broadcast to the exported receiver"
+ " was not received within the timeout window") {
@Override
protected boolean check() {
return receiver.hasReceivedBroadCast();
}
}.run();
}
/**
* Verifies a receiver registered with {@link Context#RECEIVER_NOT_EXPORTED} does not receive
* a broadcast from an external app.
*/
// TODO(b/206699109): Re-enable this test once the skip for an external app sending a broadcast
// to an unexported receiver is restored in BroadcastQueue.
@Suppress
public void testRegisterReceiver_notExported_broadcastNotReceived() throws Exception {
final ResultReceiver receiver = new ResultReceiver();
registerBroadcastReceiver(receiver, new IntentFilter(ResultReceiver.MOCK_ACTION),
Context.RECEIVER_NOT_EXPORTED);
SystemUtil.runShellCommand(EXTERNAL_APP_BROADCAST_COMMAND);
Thread.sleep(BROADCAST_TIMEOUT);
assertFalse(
"An external app must not be able to send a broadcast to a dynamic receiver "
+ "registered with RECEIVER_NOT_EXPORTED",
receiver.hasReceivedBroadCast());
}
public void testEnforceCallingOrSelfUriPermission() {
try {
Uri uri = Uri.parse("content://ctstest");
mContext.enforceCallingOrSelfUriPermission(uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
"enforceCallingOrSelfUriPermission is not working without possessing an IPC.");
fail("enforceCallingOrSelfUriPermission is not working without possessing an IPC.");
} catch (SecurityException e) {
// If the function is OK, it should throw a SecurityException here because currently no
// IPC is handled by this process.
}
}
public void testGetAssets() {
assertSame(mContext.getAssets(), mContext.getAssets());
}
public void testGetResources() {
assertSame(mContext.getResources(), mContext.getResources());
}
public void testStartInstrumentation() {
// Use wrong name
ComponentName cn = new ComponentName("com.android",
"com.android.content.FalseLocalSampleInstrumentation");
assertNotNull(cn);
assertNotNull(mContext);
// If the target instrumentation is wrong, the function should return false.
assertFalse(mContext.startInstrumentation(cn, null, null));
}
private void bindExpectResult(Context context, Intent service)
throws InterruptedException {
if (service == null) {
fail("No service created!");
}
TestConnection conn = new TestConnection(true, false);
context.bindService(service, conn, Context.BIND_AUTO_CREATE);
context.startService(service);
// Wait for a short time, so the service related operations could be
// working.
synchronized (this) {
wait(2500);
}
// Test stop Service
assertTrue(context.stopService(service));
context.unbindService(conn);
synchronized (this) {
wait(1000);
}
}
private interface Condition {
public boolean onCondition();
}
private synchronized void waitForCondition(Condition con) throws InterruptedException {
// check the condition every 1 second until the condition is fulfilled
// and wait for 3 seconds at most
for (int i = 0; !con.onCondition() && i <= 3; i++) {
wait(1000);
}
}
private void waitForReceiveBroadCast(final ResultReceiver receiver)
throws InterruptedException {
Condition con = new Condition() {
public boolean onCondition() {
return receiver.hasReceivedBroadCast();
}
};
waitForCondition(con);
}
private void waitForFilteredIntent(Context context, final String action)
throws InterruptedException {
context.sendBroadcast(new Intent(action), null);
synchronized (mLockObj) {
mLockObj.wait(BROADCAST_TIMEOUT);
}
}
private final class TestBroadcastReceiver extends BroadcastReceiver {
boolean mHadReceivedBroadCast;
boolean mIsOrderedBroadcasts;
@Override
public void onReceive(Context context, Intent intent) {
synchronized (this) {
if (mIsOrderedBroadcasts) {
setResultCode(3);
setResultData(ACTUAL_RESULT);
}
Bundle map = getResultExtras(false);
if (map != null) {
map.remove(KEY_REMOVED);
map.putString(KEY_ADDED, VALUE_ADDED);
}
mHadReceivedBroadCast = true;
this.notifyAll();
}
synchronized (mLockObj) {
mLockObj.notify();
}
}
boolean hadReceivedBroadCast() {
return mHadReceivedBroadCast;
}
void reset(){
mHadReceivedBroadCast = false;
}
}
private class FilteredReceiver extends BroadcastReceiver {
private boolean mHadReceivedBroadCast1 = false;
private boolean mHadReceivedBroadCast2 = false;
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MOCK_ACTION1.equals(action)) {
mHadReceivedBroadCast1 = true;
} else if (MOCK_ACTION2.equals(action)) {
mHadReceivedBroadCast2 = true;
}
synchronized (mLockObj) {
mLockObj.notify();
}
}
public boolean hadReceivedBroadCast1() {
return mHadReceivedBroadCast1;
}
public boolean hadReceivedBroadCast2() {
return mHadReceivedBroadCast2;
}
public void reset(){
mHadReceivedBroadCast1 = false;
mHadReceivedBroadCast2 = false;
}
}
private class TestConnection implements ServiceConnection {
public TestConnection(boolean expectDisconnect, boolean setReporter) {
}
void setMonitor(boolean v) {
}
public void onServiceConnected(ComponentName name, IBinder service) {
}
public void onServiceDisconnected(ComponentName name) {
}
}
public void testOpenFileOutput_mustNotCreateWorldReadableFile() throws Exception {
try {
mContext.openFileOutput("test.txt", Context.MODE_WORLD_READABLE);
fail("Exception expected");
} catch (SecurityException expected) {
}
}
public void testOpenFileOutput_mustNotCreateWorldWriteableFile() throws Exception {
try {
mContext.openFileOutput("test.txt", Context.MODE_WORLD_WRITEABLE);
fail("Exception expected");
} catch (SecurityException expected) {
}
}
public void testOpenFileOutput_mustNotWriteToParentDirectory() throws Exception {
try {
// Created files must be under the application's private directory.
mContext.openFileOutput("../test.txt", Context.MODE_PRIVATE);
fail("Exception expected");
} catch (IllegalArgumentException expected) {
}
}
public void testOpenFileOutput_mustNotUseAbsolutePath() throws Exception {
try {
// Created files must be under the application's private directory.
mContext.openFileOutput("/tmp/test.txt", Context.MODE_PRIVATE);
fail("Exception expected");
} catch (IllegalArgumentException expected) {
}
}
private boolean isWallpaperSupported() {
return WallpaperManager.getInstance(mContext).isWallpaperSupported();
}
}