/*
* Copyright (C) 2017 Oasis Feng. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 com.oasisfeng.condom;
import android.app.ActivityManager;
import android.app.Application;
import android.content.ComponentName;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.support.test.InstrumentationRegistry;
import android.util.EventLog;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
/**
* Miscellaneous test cases
*
* Created by Oasis on 2017/4/10.
*/
public class CondomMiscTest {
@Test public void testEventLog() throws IOException {
readNewEvents(CondomCore.CondomEvent.CONCERN);
condom.getBaseContext();
Object[] data = readLastEvent(CondomCore.CondomEvent.CONCERN);
assertEquals(condom.getPackageName(), data[0]);
assertEquals(condom.TAG, data[1]);
assertEquals("getBaseContext", data[2]);
assertCallerMatch(data);
((Application) condom.getApplicationContext()).getBaseContext();
data = readLastEvent(CondomCore.CondomEvent.CONCERN);
assertEquals("Application.getBaseContext", data[2]);
assertCallerMatch(data);
condom.getPackageManager().getInstalledApplications(0);
data = readLastEvent(CondomCore.CondomEvent.CONCERN);
assertEquals("PackageManager.getInstalledApplications", data[2]);
assertCallerMatch(data);
condom.getPackageManager().getInstalledPackages(0);
data = readLastEvent(CondomCore.CondomEvent.CONCERN);
assertEquals("PackageManager.getInstalledPackages", data[2]);
assertCallerMatch(data);
final Intent intent = new Intent().setPackage("a.b.c");
condom.bindService(intent, SERVICE_CONNECTION, 0);
data = readLastEvent(CondomCore.CondomEvent.BIND_PASS);
assertEquals(condom.getPackageName(), data[0]);
assertEquals("Condom." + TAG, data[1]);
assertEquals(intent.getPackage(), data[2]);
assertEquals(intent.toString(), data[3]);
condom.startService(intent);
data = readLastEvent(CondomCore.CondomEvent.START_PASS);
assertEquals(condom.getPackageName(), data[0]);
assertEquals("Condom." + TAG, data[1]);
assertEquals(intent.getPackage(), data[2]);
assertEquals(intent.toString(), data[3]);
final List<ResolveInfo> result = condom.getPackageManager().queryIntentServices(intent.setPackage(null).setComponent(null), 0);
assertEquals(1, result.size()); // 1 left: non.bg.service
final List<EventLog.Event> events = readNewEvents(CondomCore.CondomEvent.FILTER_BG_SERVICE);
assertEquals(2, events.size()); // 2 filtered: bg.service.*
data = (Object[]) events.get(0).getData();
assertEquals(condom.getPackageName(), data[0]);
assertEquals("Condom." + TAG, data[1]);
assertEquals("bg.service.1", data[2]);
final String expected_intent = new Intent(intent).toString(); // Flags altered
assertEquals(expected_intent, data[3]);
data = (Object[]) events.get(1).getData();
assertEquals(condom.getPackageName(), data[0]);
assertEquals("Condom." + TAG, data[1]);
assertEquals("bg.service.2", data[2]);
assertEquals(expected_intent, data[3]);
final ResolveInfo resolve = condom.getPackageManager().resolveService(intent, 0);
assertEquals("non.bg.service", resolve.serviceInfo.applicationInfo.packageName);
data = readLastEvent(CondomCore.CondomEvent.FILTER_BG_SERVICE);
assertEquals(condom.getPackageName(), data[0]);
assertEquals("Condom." + TAG, data[1]);
assertEquals("bg.service.1", data[2]);
assertEquals(expected_intent, data[3]);
final CondomContext condom_wo_tag = CondomContext.wrap(new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
@Override public boolean bindService(final Intent service, final ServiceConnection conn, final int flags) { return true; }
@Override public ComponentName startService(final Intent service) {
return service.getComponent() != null ? service.getComponent() : new ComponentName(service.getPackage(), "A");
}
}, null);
final ComponentName component = new ComponentName("x.y.z", "O");
intent.setPackage(null).setComponent(component);
condom_wo_tag.bindService(intent, SERVICE_CONNECTION, 0);
data = readLastEvent(CondomCore.CondomEvent.BIND_PASS);
assertEquals(condom_wo_tag.getPackageName(), data[0]);
assertEquals("Condom", data[1]);
assertEquals(intent.getComponent().getPackageName(), data[2]);
assertEquals(intent.toString(), data[3]);
condom_wo_tag.startService(intent);
data = readLastEvent(CondomCore.CondomEvent.START_PASS);
assertEquals(condom_wo_tag.getPackageName(), data[0]);
assertEquals("Condom", data[1]);
assertEquals(intent.getComponent().getPackageName(), data[2]);
assertEquals(intent.toString(), data[3]);
}
private static void assertCallerMatch(final Object[] data) {
final String string = data[3].toString();
assertTrue(string, string.startsWith(CondomMiscTest.class.getName() + ".testEventLog:"));
}
private static Object[] readLastEvent(final CondomCore.CondomEvent type) throws IOException {
final List<EventLog.Event> events = readNewEvents(type);
assertEquals(1, events.size());
return (Object[]) events.get(0).getData();
}
private static List<EventLog.Event> readNewEvents(final CondomCore.CondomEvent type) throws IOException {
final List<EventLog.Event> events = new ArrayList<>();
EventLog.readEvents(new int[] { EVENT_TAG_MARK, "Condom".hashCode() + type.ordinal() }, events);
if (events.isEmpty()) return Collections.emptyList();
for (int i = events.size() - 1; i >= 0; i --) {
final EventLog.Event event = events.get(i);
if (event.getTag() == EVENT_TAG_MARK) {
EventLog.writeEvent(EVENT_TAG_MARK);
return events.subList(i + 1, events.size());
}
}
EventLog.writeEvent(EVENT_TAG_MARK);
return events;
}
private static final ServiceConnection SERVICE_CONNECTION = new ServiceConnection() {
@Override public void onServiceConnected(final ComponentName name, final IBinder service) {}
@Override public void onServiceDisconnected(final ComponentName name) {}
};
private final CondomContext condom = CondomContext.wrap(new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
@Override public boolean bindService(final Intent service, final ServiceConnection conn, final int flags) { return true; }
@Override public ComponentName startService(final Intent service) {
return service.getComponent() != null ? service.getComponent() : new ComponentName(service.getPackage(), "A");
}
@Override public PackageManager getPackageManager() {
return new PackageManagerWrapper(super.getPackageManager()) {
@Override public List<ResolveInfo> queryIntentServices(final Intent intent, final int flags) {
final List<ResolveInfo> resolves = new ArrayList<>();
final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
final List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(32);
if (services != null) for (final ActivityManager.RunningServiceInfo service : services) {
if (service.uid == android.os.Process.myUid()) continue;
resolves.add(buildResolveInfo("bg.service.1", 999999999)); // Simulate a background UID.
resolves.add(buildResolveInfo("non.bg.service", service.uid));
resolves.add(buildResolveInfo("bg.service.2", 88888888));
break;
}
return resolves;
}
private ResolveInfo buildResolveInfo(final String pkg, final int uid) {
final ResolveInfo resolve = new ResolveInfo() { @Override public String toString() { return "ResolveInfo{test}"; } };
resolve.serviceInfo = new ServiceInfo();
resolve.serviceInfo.packageName = pkg;
resolve.serviceInfo.applicationInfo = new ApplicationInfo();
resolve.serviceInfo.applicationInfo.packageName = pkg;
resolve.serviceInfo.applicationInfo.uid = uid;
return resolve;
}
};
}
}, TAG);
private static final int EVENT_TAG_MARK = "Condom".hashCode() + 999;
private static final String TAG = "Test";
}