mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
When checking for overlay apps, ignore Play Services.
This commit is contained in:
@@ -6,10 +6,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.Signature;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.v7.preference.PreferenceManager;
|
||||
@@ -19,11 +19,16 @@ import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
@@ -31,32 +36,57 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
|
||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
||||
import static android.content.Intent.EXTRA_REPLACING;
|
||||
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
||||
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
||||
import static android.content.pm.PackageManager.GET_SIGNATURES;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
implements Service,
|
||||
ScreenFilterMonitor {
|
||||
implements Service, ScreenFilterMonitor {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ScreenFilterMonitorImpl.class.getName());
|
||||
private static final String PREF_SCREEN_FILTER_APPS =
|
||||
"shownScreenFilterApps";
|
||||
|
||||
/*
|
||||
* Ignore Play Services if it uses this package name and public key - it's
|
||||
* effectively a system app, but not flagged as such on older systems
|
||||
*/
|
||||
private static final String PLAY_SERVICES_PACKAGE =
|
||||
"com.google.android.gms";
|
||||
private static final String PLAY_SERVICES_PUBLIC_KEY =
|
||||
"30820120300D06092A864886F70D01010105000382010D0030820108" +
|
||||
"0282010100AB562E00D83BA208AE0A966F124E29DA11F2AB56D08F58" +
|
||||
"E2CCA91303E9B754D372F640A71B1DCB130967624E4656A7776A9219" +
|
||||
"3DB2E5BFB724A91E77188B0E6A47A43B33D9609B77183145CCDF7B2E" +
|
||||
"586674C9E1565B1F4C6A5955BFF251A63DABF9C55C27222252E875E4" +
|
||||
"F8154A645F897168C0B1BFC612EABF785769BB34AA7984DC7E2EA276" +
|
||||
"4CAE8307D8C17154D7EE5F64A51A44A602C249054157DC02CD5F5C0E" +
|
||||
"55FBEF8519FBE327F0B1511692C5A06F19D18385F5C4DBC2D6B93F68" +
|
||||
"CC2979C70E18AB93866B3BD5DB8999552A0E3B4C99DF58FB918BEDC1" +
|
||||
"82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" +
|
||||
"0B145B6AA192858E79020103";
|
||||
|
||||
private final Context appContext;
|
||||
private final AndroidExecutor androidExecutor;
|
||||
private final LinkedList<String> appNames = new LinkedList<>();
|
||||
private final PackageManager pm;
|
||||
private final SharedPreferences prefs;
|
||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||
|
||||
// The following must only be accessed on the UI thread
|
||||
private final Set<String> apps = new HashSet<>();
|
||||
private final Set<String> shownApps;
|
||||
// Used solely for the UiThread
|
||||
private boolean serviceStarted = false;
|
||||
|
||||
@Inject
|
||||
@@ -75,7 +105,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
@Override
|
||||
public Void call() {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||
intentFilter.addAction(ACTION_PACKAGE_ADDED);
|
||||
intentFilter.addDataScheme("package");
|
||||
appContext.registerReceiver(ScreenFilterMonitorImpl.this,
|
||||
intentFilter);
|
||||
@@ -109,9 +139,8 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
}
|
||||
|
||||
private Set<String> getShownScreenFilterApps() {
|
||||
// res must not be modified
|
||||
Set<String> s =
|
||||
prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null);
|
||||
// Result must not be modified
|
||||
Set<String> s = prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null);
|
||||
HashSet<String> result = new HashSet<>();
|
||||
if (s != null) {
|
||||
result.addAll(s);
|
||||
@@ -121,7 +150,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
|
||||
if (!intent.getBooleanExtra(EXTRA_REPLACING, false)) {
|
||||
final String packageName =
|
||||
intent.getData().getEncodedSchemeSpecificPart();
|
||||
androidExecutor.runOnUiThread(new Runnable() {
|
||||
@@ -155,7 +184,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
@Override
|
||||
@UiThread
|
||||
public void storeAppsAsShown(Collection<String> s, boolean persistent) {
|
||||
HashSet<String> buf = new HashSet(s);
|
||||
HashSet<String> buf = new HashSet<>(s);
|
||||
shownApps.addAll(buf);
|
||||
if (persistent && !s.isEmpty()) {
|
||||
buf.addAll(getShownScreenFilterApps());
|
||||
@@ -168,7 +197,7 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
private Set<String> getInstalledScreenFilterApps() {
|
||||
HashSet<String> screenFilterApps = new HashSet<>();
|
||||
List<PackageInfo> packageInfos =
|
||||
pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||
pm.getInstalledPackages(GET_PERMISSIONS);
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
if (isOverlayApp(packageInfo)) {
|
||||
String name = pkgToString(packageInfo);
|
||||
@@ -180,25 +209,22 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
return screenFilterApps;
|
||||
}
|
||||
|
||||
// Checks if pkg uses the SYSTEM_ALERT_WINDOW permission and if so
|
||||
// Checks if a package uses the SYSTEM_ALERT_WINDOW permission and if so
|
||||
// returns the app name.
|
||||
@Nullable
|
||||
private String isOverlayApp(String pkg) {
|
||||
try {
|
||||
PackageInfo pkgInfo =
|
||||
pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
|
||||
PackageInfo pkgInfo = pm.getPackageInfo(pkg, GET_PERMISSIONS);
|
||||
if (isOverlayApp(pkgInfo)) {
|
||||
return pkgToString(pkgInfo);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException ignored) {
|
||||
if (LOG.isLoggable(Level.WARNING)) {
|
||||
LOG.warning("Package name not found: " + pkg);
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Fetch the application name for a given package.
|
||||
// Fetches the application name for a given package.
|
||||
@Nullable
|
||||
private String pkgToString(PackageInfo pkgInfo) {
|
||||
CharSequence seq = pm.getApplicationLabel(pkgInfo.applicationInfo);
|
||||
@@ -208,25 +234,49 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
||||
return null;
|
||||
}
|
||||
|
||||
// Checks if an installed pkg is a user app using the permission.
|
||||
// Checks if an installed package is a user app using the permission.
|
||||
private boolean isOverlayApp(PackageInfo packageInfo) {
|
||||
int mask = ApplicationInfo.FLAG_SYSTEM |
|
||||
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
int mask = FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP;
|
||||
// Ignore system apps
|
||||
if ((packageInfo.applicationInfo.flags & mask) != 0) {
|
||||
return false;
|
||||
}
|
||||
//Get Permissions
|
||||
String[] requestedPermissions =
|
||||
packageInfo.requestedPermissions;
|
||||
// Ignore Play Services, it's effectively a system app
|
||||
if (isPlayServices(packageInfo.packageName)) {
|
||||
return false;
|
||||
}
|
||||
// Get permissions
|
||||
String[] requestedPermissions = packageInfo.requestedPermissions;
|
||||
if (requestedPermissions != null) {
|
||||
for (String requestedPermission : requestedPermissions) {
|
||||
if (requestedPermission
|
||||
.equals(SYSTEM_ALERT_WINDOW)) {
|
||||
if (requestedPermission.equals(SYSTEM_ALERT_WINDOW)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isPlayServices(String pkg) {
|
||||
if (!PLAY_SERVICES_PACKAGE.equals(pkg)) return false;
|
||||
try {
|
||||
PackageInfo sigs = pm.getPackageInfo(pkg, GET_SIGNATURES);
|
||||
// The genuine Play Services app should have a single signature
|
||||
Signature[] signatures = sigs.signatures;
|
||||
if (signatures == null || signatures.length != 1) return false;
|
||||
// Extract the public key from the signature
|
||||
CertificateFactory certFactory =
|
||||
CertificateFactory.getInstance("X509");
|
||||
byte[] signatureBytes = signatures[0].toByteArray();
|
||||
InputStream in = new ByteArrayInputStream(signatureBytes);
|
||||
X509Certificate cert =
|
||||
(X509Certificate) certFactory.generateCertificate(in);
|
||||
byte[] publicKeyBytes = cert.getPublicKey().getEncoded();
|
||||
String publicKey = StringUtils.toHexString(publicKeyBytes);
|
||||
return PLAY_SERVICES_PUBLIC_KEY.equals(publicKey);
|
||||
} catch (NameNotFoundException | CertificateException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user