diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/BlockerInterfaceService.java b/lineage/lib/main/java/org/lineageos/platform/internal/BlockerInterfaceService.java
new file mode 100644
index 0000000000000000000000000000000000000000..056221bad8670026c788c98d7814e9857c5ffdf2
--- /dev/null
+++ b/lineage/lib/main/java/org/lineageos/platform/internal/BlockerInterfaceService.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2018-2020 The LineageOS 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 org.lineageos.platform.internal;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.lang.InterruptedException;
+
+import lineageos.app.LineageContextConstants;
+import lineageos.providers.LineageSettings;
+import lineageos.blockers.IBlockerInterface;
+import lineageos.blockers.BlockerInterface;
+
+import java.util.NoSuchElementException;
+
+/** @hide **/
+public class BlockerInterfaceService extends LineageSystemService {
+ private static final String TAG = "LineageBlockerInterfaceService";
+
+ private Context mContext;
+
+ public BlockerInterfaceService(Context context) {
+ super(context);
+ mContext = context;
+ if (context.getPackageManager().hasSystemFeature(LineageContextConstants.Features.BLOCKER)) {
+ publishBinderService(LineageContextConstants.LINEAGE_BLOCKER_INTERFACE, mService);
+ } else {
+ Log.wtf(TAG, "Blocker service started by system server but feature xml not" +
+ " declared. Not publishing binder service!");
+ }
+ }
+
+ @Override
+ public String getFeatureDeclaration() {
+ return LineageContextConstants.Features.BLOCKER;
+ }
+
+ @Override
+ public void onStart() {
+ runTestInternal(true);
+ }
+
+
+ private void runTestInternal(boolean fromStart) {
+ // TODO: Dummy method. replace with appropriate methods.
+ Log.d(TAG, "RunTestInternal called with "+fromStart);
+ Runtime r = Runtime.getRuntime();
+ try {
+ Process p = r.exec("/sbin/su -c iptables -L -w");
+ String result="";
+ String temp= null;
+ BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ while((temp = reader.readLine()) != null) {
+ Log.d(TAG, "RunTestInternal tempResult: "+temp);
+ result.concat(temp);
+ }
+ Log.d(TAG, "RunTestInternal result: "+result);
+
+ BufferedReader errReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+ while((temp = errReader.readLine()) != null) {
+ Log.d(TAG, "RunTestInternal error: "+temp);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private boolean blockIpOrDomainInternal(String ipOrDomain) {
+ Log.d(TAG, "blockIpOrDomainInternal called with " + ipOrDomain);
+ String iptableCmd = "iptables -A INPUT -m string --hex-string \"" + ipOrDomain + "\" --algo bm -j DROP && iptables -A OUTPUT -m string --hex-string \"" + ipOrDomain + "\" --algo bm -j DROP";
+ String[] cmds = new String[] {"su", "-c", iptableCmd};
+ Runtime r = Runtime.getRuntime();
+ try {
+ Process p = r.exec(cmds);
+
+ String result="";
+ String temp= null;
+ BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ while((temp = reader.readLine()) != null) {
+ Log.d(TAG, "blockIpOrDomainInternal tempResult: "+temp);
+ result.concat(temp);
+ }
+ Log.d(TAG, "blockIpOrDomainInternal result: "+result);
+
+ BufferedReader errReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+ while((temp = errReader.readLine()) != null) {
+ Log.d(TAG, "blockIpOrDomainInternal error: "+temp);
+ }
+ p.waitFor();
+
+ if (p.exitValue() == 0) return true;
+ else return false;
+ } catch (InterruptedException | IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ private boolean unblockIpOrDomainInternal(String ipOrDomain) {
+ Log.d(TAG, "unblockIpOrDomainInternal called with " + ipOrDomain);
+ String iptableCmd = "iptables -D INPUT -m string --hex-string \"" + ipOrDomain + "\" --algo bm -j DROP && iptables -D OUTPUT -m string --hex-string \"" + ipOrDomain + "\" --algo bm -j DROP";
+ String[] cmds = new String[] {"su", "-c", iptableCmd};
+ Runtime r = Runtime.getRuntime();
+ try {
+ Process p = r.exec(cmds);
+
+ String result="";
+ String temp= null;
+ BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ while((temp = reader.readLine()) != null) {
+ Log.d(TAG, "unblockIpOrDomainInternal tempResult: "+temp);
+ result.concat(temp);
+ }
+ Log.d(TAG, "unblockIpOrDomainInternal result: "+result);
+
+ BufferedReader errReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+ while((temp = errReader.readLine()) != null) {
+ Log.d(TAG, "unblockIpOrDomainInternal error: "+temp);
+ }
+ p.waitFor();
+
+ if (p.exitValue() == 0) return true;
+ else return false;
+ } catch (InterruptedException | IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+
+ /* Utils */
+
+ private void enforceBlockerPermission() {
+ mContext.enforceCallingOrSelfPermission(BlockerInterface.BLOCKER_INTERFACE_PERMISSION,
+ "You do not have permissions to use the Blocker interface");
+ }
+
+ /* Service */
+
+ private final IBinder mService = new IBlockerInterface.Stub() {
+ @Override
+ public void runTest() {
+ enforceBlockerPermission();
+ /*
+ * We need to clear the caller's identity in order to
+ * allow this method call to modify settings
+ * not allowed by the caller's permissions.
+ */
+ long token = clearCallingIdentity();
+ runTestInternal(false);
+ restoreCallingIdentity(token);
+ }
+
+ @Override
+ public boolean blockIp(String ipAddress) {
+ enforceBlockerPermission();
+ /*
+ * We need to clear the caller's identity in order to
+ * allow this method call to modify settings
+ * not allowed by the caller's permissions.
+ */
+ long token = clearCallingIdentity();
+ boolean result = blockIpOrDomainInternal(ipAddress);
+ restoreCallingIdentity(token);
+ return result;
+ }
+
+ @Override
+ public boolean unblockIp(String ipAddress) {
+ enforceBlockerPermission();
+ /*
+ * We need to clear the caller's identity in order to
+ * allow this method call to modify settings
+ * not allowed by the caller's permissions.
+ */
+ long token = clearCallingIdentity();
+ boolean result = unblockIpOrDomainInternal(ipAddress);
+ restoreCallingIdentity(token);
+ return result;
+ }
+
+ @Override
+ public boolean blockDomain(String domainName) {
+ enforceBlockerPermission();
+ /*
+ * We need to clear the caller's identity in order to
+ * allow this method call to modify settings
+ * not allowed by the caller's permissions.
+ */
+ long token = clearCallingIdentity();
+ boolean result = blockIpOrDomainInternal(domainName);
+ restoreCallingIdentity(token);
+ return result;
+ }
+
+ @Override
+ public boolean unblockDomain(String domainName) {
+ enforceBlockerPermission();
+ /*
+ * We need to clear the caller's identity in order to
+ * allow this method call to modify settings
+ * not allowed by the caller's permissions.
+ */
+ long token = clearCallingIdentity();
+ boolean result = unblockIpOrDomainInternal(domainName);
+ restoreCallingIdentity(token);
+ return result;
+ }
+ };
+}
diff --git a/lineage/res/AndroidManifest.xml b/lineage/res/AndroidManifest.xml
index e6ec86d25a100e3964cd052f58fc52b1da8e7273..3ec2209059dc3e4aba1d97245f5a717ae035812c 100644
--- a/lineage/res/AndroidManifest.xml
+++ b/lineage/res/AndroidManifest.xml
@@ -125,6 +125,13 @@
android:icon="@drawable/ic_trust"
android:protectionLevel="signature|privileged" />
+
+
+
org.lineageos.platform.internal.LineageAudioService
- org.lineageos.platform.internal.TrustInterfaceService
- org.lineageos.platform.internal.LineageSettingsService
+ - org.lineageos.platform.internal.BlockerInterfaceService
diff --git a/lineage/res/res/values/strings.xml b/lineage/res/res/values/strings.xml
index ab06347fd92c3918d15eca49a9328ed749eaa25e..4ff33cca807b62ac99f8c7f79bcb1630c77df050 100644
--- a/lineage/res/res/values/strings.xml
+++ b/lineage/res/res/values/strings.xml
@@ -171,4 +171,8 @@
Discover Trust
Get to know how to assure your device is safe
Manage alerts
+
+
+ Access Blocker interface
+ Allows an app to access Blocker
diff --git a/sdk/src/java/lineageos/app/LineageContextConstants.java b/sdk/src/java/lineageos/app/LineageContextConstants.java
index 0b435b4da117829917d2855278a8ae601c1b15d7..b0eceaf3399eec7abbfaa85779e0676ed2e785a4 100644
--- a/sdk/src/java/lineageos/app/LineageContextConstants.java
+++ b/sdk/src/java/lineageos/app/LineageContextConstants.java
@@ -107,6 +107,16 @@ public final class LineageContextConstants {
*/
public static final String LINEAGE_TRUST_INTERFACE = "lineagetrust";
+ /**
+ * Use with {@link android.content.Context#getSystemService} to retrieve a
+ * {@link lineageos.blockers.BlockerInterface} to access the Blocker interface.
+ *
+ * @see android.content.Context#getSystemService
+ * @see lineageos.blockers.BlockerInterface
+ *
+ * @hide
+ */
+ public static final String LINEAGE_BLOCKER_INTERFACE = "lineageblocker";
/**
* Features supported by the Lineage SDK.
*/
@@ -182,5 +192,13 @@ public final class LineageContextConstants {
*/
@SdkConstant(SdkConstant.SdkConstantType.FEATURE)
public static final String FOD = "vendor.lineage.biometrics.fingerprint.inscreen";
+
+ /**
+ * Feature for {@link PackageManager#getSystemAvailableFeatures} and
+ * {@link PackageManager#hasSystemFeature}: The device includes the /e/ blocker service
+ * utilized by the lineage sdk.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.FEATURE)
+ public static final String BLOCKER = "org.lineageos.blocker";
}
}
diff --git a/sdk/src/java/lineageos/blockers/BlockerInterface.java b/sdk/src/java/lineageos/blockers/BlockerInterface.java
new file mode 100644
index 0000000000000000000000000000000000000000..500b55819935df756dc75651ef28fbcced3efea8
--- /dev/null
+++ b/sdk/src/java/lineageos/blockers/BlockerInterface.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright (C) 2018-2019 The LineageOS 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 lineageos.blockers;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import lineageos.app.LineageContextConstants;
+
+public class BlockerInterface {
+ /**
+ * Allows an application to use the Blocker interface to provide blocking trackers/ads
+ * feature to the user.
+ * This is a system-only permission, user-installed apps cannot use it
+ */
+ public static final String BLOCKER_INTERFACE_PERMISSION = "lineageos.permission.ACCESS_BLOCKER";
+
+ private static final String TAG = "BlockerInterface";
+
+ private static IBlockerInterface sService;
+ private static BlockerInterface sInstance;
+
+ private Context mContext;
+
+ private BlockerInterface(Context context) {
+ Context appContext = context.getApplicationContext();
+ mContext = appContext == null ? context : appContext;
+ sService = getService();
+ if (context.getPackageManager().hasSystemFeature(
+ LineageContextConstants.Features.BLOCKER) && sService == null) {
+ throw new RuntimeException("Unable to get BlockerInterfaceService. The service" +
+ " either crashed, was not started, or the interface has been called to early" +
+ " in SystemServer init");
+ }
+ }
+
+ /**
+ * Get or create an instance of the {@link lineageos.blockers.BlockerInterface}
+ *
+ * @param context Used to get the service
+ * @return {@link BlockerInterface}
+ */
+ public static BlockerInterface getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new BlockerInterface(context);
+ }
+ return sInstance;
+ }
+
+ /** @hide **/
+ public static IBlockerInterface getService() {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService(LineageContextConstants.LINEAGE_BLOCKER_INTERFACE);
+ sService = IBlockerInterface.Stub.asInterface(b);
+
+ if (b == null) {
+ Log.e(TAG, "null service. SAD!");
+ return null;
+ }
+
+ sService = IBlockerInterface.Stub.asInterface(b);
+ return sService;
+ }
+
+ public void runTest() {
+ if (sService == null) {
+ return;
+ }
+ try {
+ Log.d(TAG, "Service method called.");
+ sService.runTest();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ }
+ return;
+ }
+
+ public boolean blockIp(String ipAddress) {
+ if (sService == null) {
+ return false;
+ }
+ try {
+ Log.d(TAG, "BlockIP method called.");
+ return sService.blockIp(ipAddress);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ return false;
+ }
+ }
+
+ public boolean unblockIp(String ipAddress) {
+ if (sService == null) {
+ return false;
+ }
+ try {
+ Log.d(TAG, "BlockIP method called.");
+ return sService.unblockIp(ipAddress);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ return false;
+ }
+ }
+
+ public boolean blockDomain(String domainName) {
+ if (sService == null) {
+ return false;
+ }
+ try {
+ Log.d(TAG, "BlockIP method called.");
+ return sService.blockDomain(domainName);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ return false;
+ }
+ }
+
+ public boolean unblockDomain(String domainName) {
+ if (sService == null) {
+ return false;
+ }
+ try {
+ Log.d(TAG, "BlockIP method called.");
+ return sService.unblockDomain(domainName);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ return false;
+ }
+ }
+
+}
diff --git a/sdk/src/java/lineageos/blockers/IBlockerInterface.aidl b/sdk/src/java/lineageos/blockers/IBlockerInterface.aidl
new file mode 100644
index 0000000000000000000000000000000000000000..d7953a0ccfe5aead033b3e3f445ba2a0a86029ea
--- /dev/null
+++ b/sdk/src/java/lineageos/blockers/IBlockerInterface.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 E FOUNDATION
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package lineageos.blockers;
+
+/** {@hide} */
+interface IBlockerInterface {
+
+ void runTest();
+
+ boolean blockIp(String ipAddress);
+
+ boolean unblockIp(String ipAddress);
+
+ boolean blockDomain(String domainName);
+
+ boolean unblockDomain(String domainName);
+}