package biz.bokhorst.xprivacy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.provider.Telephony;
import android.service.notification.NotificationListenerService;
import android.telephony.TelephonyManager;
@SuppressLint("InlinedApi")
public class XIntentFirewall extends XHook {
private Methods mMethod;
private static Map<String, String> mapIntentRestriction = new HashMap<String, String>();
static {
// Intent receive: calling
mapIntentRestriction.put(Intent.ACTION_NEW_OUTGOING_CALL, PrivacyManager.cCalling);
mapIntentRestriction.put(TelephonyManager.ACTION_PHONE_STATE_CHANGED, PrivacyManager.cPhone);
mapIntentRestriction.put(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE, PrivacyManager.cCalling);
// Intent receive: C2DM
mapIntentRestriction.put("com.google.android.c2dm.intent.REGISTRATION", PrivacyManager.cNotifications);
mapIntentRestriction.put("com.google.android.c2dm.intent.RECEIVE", PrivacyManager.cNotifications);
// Intent receive: NFC
mapIntentRestriction.put(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED, PrivacyManager.cNfc);
mapIntentRestriction.put(NfcAdapter.ACTION_NDEF_DISCOVERED, PrivacyManager.cNfc);
mapIntentRestriction.put(NfcAdapter.ACTION_TAG_DISCOVERED, PrivacyManager.cNfc);
mapIntentRestriction.put(NfcAdapter.ACTION_TECH_DISCOVERED, PrivacyManager.cNfc);
// Intent receive: SMS
mapIntentRestriction.put(Telephony.Sms.Intents.DATA_SMS_RECEIVED_ACTION, PrivacyManager.cMessages);
mapIntentRestriction.put(Telephony.Sms.Intents.SMS_RECEIVED_ACTION, PrivacyManager.cMessages);
mapIntentRestriction.put(Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION, PrivacyManager.cMessages);
mapIntentRestriction.put(Telephony.Sms.Intents.SMS_DELIVER_ACTION, PrivacyManager.cMessages);
mapIntentRestriction.put(Telephony.Sms.Intents.WAP_PUSH_DELIVER_ACTION, PrivacyManager.cMessages);
// Intent receive: notifications
mapIntentRestriction.put(NotificationListenerService.SERVICE_INTERFACE, PrivacyManager.cNotifications);
// Intent receive: package changes
mapIntentRestriction.put(Intent.ACTION_PACKAGE_ADDED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_REPLACED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_RESTARTED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_REMOVED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_CHANGED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_DATA_CLEARED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_FIRST_LAUNCH, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_FULLY_REMOVED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_PACKAGE_VERIFIED, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE, PrivacyManager.cSystem);
mapIntentRestriction.put(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE, PrivacyManager.cSystem);
}
private XIntentFirewall(Methods method) {
super(null, method.name(), null);
mMethod = method;
}
public String getClassName() {
return "com.android.server.firewall.IntentFirewall";
}
// @formatter:off
// public boolean checkIntent(FirewallIntentResolver resolver, ComponentName resolvedComponent, int intentType, Intent intent, int callerUid, int callerPid, String resolvedType, int receivingUid)
// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/com/android/server/firewall/IntentFirewall.java
// @formatter:on
private enum Methods {
checkIntent
};
public static List<XHook> getInstances() {
List<XHook> listHook = new ArrayList<XHook>();
listHook.add(new XIntentFirewall(Methods.checkIntent));
return listHook;
}
@Override
protected void before(XParam param) throws Throwable {
// Do nothing
}
@Override
protected void after(XParam param) throws Throwable {
switch (mMethod) {
case checkIntent:
if (param.args.length > 7 && param.args[3] instanceof Intent && param.args[7] instanceof Integer) {
Intent intent = (Intent) param.args[3];
int receivingUid = (Integer) param.args[7];
if (isIntentRestricted(receivingUid, intent))
param.setResult(false);
}
break;
}
}
private boolean isIntentRestricted(int uid, Intent intent) throws Throwable {
String action = intent.getAction();
String data = intent.getDataString();
String actionData = (action == null ? "" : action) + (data == null ? "" : ":" + data);
if (PrivacyManager.getSettingBool(0, PrivacyManager.cSettingIntentWall, false))
if (isRestrictedExtra(uid, "system", "IntentFirewall", actionData))
return true;
if (mapIntentRestriction.containsKey(action)) {
// Get restriction category
String restrictionName = mapIntentRestriction.get(action);
if (Intent.ACTION_NEW_OUTGOING_CALL.equals(action)) {
// Outgoing call
if (intent.hasExtra(Intent.EXTRA_PHONE_NUMBER)) {
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
if (phoneNumber != null)
if (isRestrictedExtraValue(uid, restrictionName, action, phoneNumber, phoneNumber))
return true;
}
} else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
// Incoming call
if (intent.hasExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)) {
String phoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (phoneNumber != null)
if (isRestrictedExtraValue(uid, restrictionName, action, phoneNumber, phoneNumber))
return true;
}
} else if (PrivacyManager.cSystem.equals(restrictionName)) {
// Package event
if (isRestrictedExtra(uid, restrictionName, action, intent.getDataString())) {
String[] packageNames;
if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE)
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE))
packageNames = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
else
packageNames = new String[] { intent.getData().getSchemeSpecificPart() };
for (String packageName : packageNames)
if (!XPackageManager.isPackageAllowed(0, packageName))
return true;
}
} else if (isRestrictedExtra(uid, restrictionName, action, intent.getDataString()))
return true;
}
return false;
}
}