blob: 0fca1fad7b07b7fcf506cfc696bea0977d39e307 [file] [log] [blame]
/*
* Copyright (C) 2016 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.pm.cts.shortcutmanager;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.concatResult;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
import android.content.pm.ShortcutManager;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
@SmallTest
public class ShortcutManagerNegativeTest extends ShortcutManagerCtsTestsBase {
private static final String TAG = "ShortcutNegativeCTS";
/**
* If true, reflection errors such as "field not found" will be a failure. This is useful
* during development, but should be turned off in the actual code, since these fields/methods
* don't have to exist.
*/
private static final boolean DISALLOW_REFLECTION_ERROR = false; // don't submit with true
private static Object readField(Object instance, String field)
throws NoSuchFieldException, IllegalAccessException {
final Field f = instance.getClass().getDeclaredField(field);
f.setAccessible(true);
final Object ret = f.get(instance);
if (ret == null) {
throw new NoSuchFieldError();
}
return ret;
}
private static void callMethodExpectingSecurityException(Object instance, String name,
String expectedMessage, Object... args)
throws NoSuchMethodException, IllegalAccessException {
Method m = null;
for (Method method : instance.getClass().getDeclaredMethods()) {
if (method.getName().equals(name)) {
m = method;
break;
}
}
if (m == null) {
throw new NoSuchMethodError();
}
m.setAccessible(true);
try {
m.invoke(instance, args);
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof SecurityException) {
MoreAsserts.assertContainsRegex(expectedMessage,
e.getTargetException().getMessage());
return; // Pass
}
}
fail("Didn't throw exception");
}
private void checkAidlCall(String method, String expectedMessage, Object... args)
throws IllegalAccessException {
final ShortcutManager manager = getTestContext().getSystemService(ShortcutManager.class);
try {
callMethodExpectingSecurityException(readField(manager, "mService"), method,
expectedMessage, args);
} catch (NoSuchFieldException|NoSuchMethodException e) {
if (DISALLOW_REFLECTION_ERROR) {
throw new RuntimeException(e);
} else {
Log.w(TAG, "Reflection failed, which is okay", e);
}
}
}
/**
* Make sure the internal AIDL methods are protected.
*/
public void testDirectAidlCalls() throws IllegalAccessException {
checkAidlCall("resetThrottling", "Caller must be");
checkAidlCall("onApplicationActive", "does not have",
"package", getTestContext().getUserId());
checkAidlCall("getBackupPayload", "Caller must be", getTestContext().getUserId());
checkAidlCall("applyRestore", "Caller must be", null, getTestContext().getUserId());
}
private String runCommand(String command) throws IOException, InterruptedException {
final Process p = Runtime.getRuntime().exec(command);
final ArrayList<String> ret = new ArrayList<>();
try (BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while ((line = r.readLine()) != null) {
ret.add(line);
}
};
p.waitFor();
return concatResult(ret);
}
/**
* Make sure cmd shortcut can't be called.
*/
@Suppress // calling "cmd shortcut" from this UID seems to hang now.
public void testCommand() throws Exception {
runWithCaller(mPackageContext1, () -> {
assertTrue(getManager().setDynamicShortcuts(list(
makeShortcut("s1"))));
});
// cmd shortcut will fail silently, with no error outputs.
MoreAsserts.assertNotContainsRegex("Success", runCommand("cmd shortcut clear-shortcuts " +
mPackageContext1.getPackageName()));
// Shortcuts shouldn't be cleared.
runWithCaller(mPackageContext1, () -> {
assertWith(getManager().getDynamicShortcuts())
.haveIds("s1");
});
}
/**
* Make sure AIDL methods can't be called for other users.
*/
public void testUserIdSpoofing() throws IllegalAccessException {
checkAidlCall("getDynamicShortcuts", "Invalid user-ID",
mPackageContext1.getPackageName(), /* user-id*/ 10);
}
}