• Stars
    star
    224
  • Rank 177,766 (Top 4 %)
  • Language
    Java
  • Created over 8 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Android JNI bindings for libadblockplus

adblock-android adblock-android-webview adblock-android-settings

Adblock Android SDK

An Android library containing project, tests, settings fragments, and demo application for AdblockWebView.

Dependencies

The majority of project dependencies are declared as git submodules, make sure your checkout contains submodules. For example git clone --recurse-submodules when initially cloning or git submodule update --recursive --init to update an existing clone. There is also single com.jakewharton.timber Maven dependency.

Library

An Android library that provides the core functionality of Adblock Plus. You can find it in the 'adblock-android' directory.

Using as a Gradle dependency

Make sure you have jcenter() in the list of repositories and then add the following dependency:

dependencies {
    implementation 'org.adblockplus:adblock-android:+'
}

In the general case, it's suggested to use the most recent version.

Building

Requirements

Edit 'buildToolsVersion' in 'build.gradle' files if necessary.

Building of libadblockplus

First, make sure all the prerequisites are installed. Second, one needs to build the V8 required for libadblockplus. See libadblockplus/README or V8 documentation on how to build V8 or fetch precompiled one. For the latter, run in the 'libadblockplus' directory:

make TARGET_OS=android ABP_TARGET_ARCH=arm Configuration=release get-prebuilt-v8
make TARGET_OS=android ABP_TARGET_ARCH=arm64 Configuration=release get-prebuilt-v8
make TARGET_OS=android ABP_TARGET_ARCH=ia32 Configuration=release get-prebuilt-v8
make TARGET_OS=android ABP_TARGET_ARCH=x64 Configuration=release get-prebuilt-v8

Make sure to set ANDROID_NDK_ROOT environment variable to point to Android NDK installation, eg.:

export ANDROID_NDK_ROOT=/Users/developer/ndk/android-ndk-r16b

After that we can build libadblockplus:

make TARGET_OS=android ABP_TARGET_ARCH=arm Configuration=release
make TARGET_OS=android ABP_TARGET_ARCH=arm64 Configuration=release
make TARGET_OS=android ABP_TARGET_ARCH=ia32 Configuration=release
make TARGET_OS=android ABP_TARGET_ARCH=x64 Configuration=release

Building from command-line

In the project root directory create the file local.properties and set sdk.dir and ndk.dir to where you installed it, e.g.:

sdk.dir = /some/where/sdk
ndk.dir = /some/where/ndk

In the project root directory run:

./gradlew assembleDebug

This will generate *.aar artifacts in the '.../build/outputs/aar/' directories:

  • adblock-android-abi_all-... - AAR for all the ARCHs (x86, armv7a, arm64)
  • adblock-android-abi_x86-... - AAR for x86 only
  • adblock-android-abi_x86_64-... - AAR for x86_64 only
  • adblock-android-abi_arm-... - AAR for armv7a only
  • adblock-android-abi_arm64-... - AAR for arm64 only
  • adblock-android-webview-... - AAR for AdblockWebView
  • adblock-android-settings-... - AAR for Settings

Android permissions note

An app that uses the library have to add the following permissions to AndroidManifest.xml:

  • <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  • <uses-permission android:name="android.permission.INTERNET"/>

(added automatically if building with Gradle or should be added manually otherwise).

Build directory configuration

By default Gradle uses build directory to build modules, however, it can be undesired. for some use cases like CI or building as Chromium submodule. Set GRADLE_BUILD_DIR environment variable to configure build directory:

GRADLE_BUILD_DIR=/tmp ./gradlew clean assemble

Note

[Configuration] Building project in /tmp

output while building

Building with prebuilt shared V8

There is an option to use the product's V8 (let's say Chromium) instead of built-in V8. Put prebuilt shared V8 library file(s) in ARCH directories and set SHARED_V8_LIB_FILENAMES environment variable and SHARED_V8_LIB_DIR before building. You can pass multiple filenames in SHARED_V8_LIB_FILENAMES, separated with space. Libadblockplus is required to be linked with that library file(s).

For example:

SHARED_V8_LIB_FILENAMES=libv8.cr.so SHARED_V8_LIB_DIR="/tmp/shared_v8" ./gradlew clean assembleAbi_arm

or

SHARED_V8_LIB_FILENAMES="libv8.cr.so libv8_libbase.cr.so libv8_libplatform.cr.so" SHARED_V8_LIB_DIR="/tmp/shared_v8" ./gradlew clean assembleAbi_arm

for multiple library files.

Note

[Configuration] Excluding shared v8 library libv8.cr.so from AAR
...
[Configuration] Linking dynamically with shared v8 library /tmp/shared_v8/release/libv8.cr.so
...

output while building.

Building with exposing of libadblockplus classes

Set EXPOSE_LIBABP_OBJECTS environment variable to expose libadblockplus classes in the shared library.

For example:

EXPOSE_LIBABP_OBJECTS=y ./gradlew clean assembleAbi_arm

JNI adjustments

To load custom library name pass LIBABP_SHARED_LIBRARY_NAME environment variable (without lib and .so):

LIBABP_SHARED_LIBRARY_NAME=adblockplus ./gradlew assembleRelease

To skip the compilation of JNI classes pass the SKIP_JNI_COMPILATION environment variable:

SKIP_JNI_COMPILATION=true ./gradlew assembleRelease

Building for single ARCH

By default, adblock-android is built for ARM/ARM64 and x86/x86_64 and it can be filtered when building end-user Android applications. However, sometimes it can be desired to build "adblock-android.aar" for a single ARCH.

Pass abi_arm, abi_arm64, abi_x86, or abi_x86_64 to build it for a single arch or abi_all for all ARCHs:

`./gradlew clean assembleAbi_arm`

Note

[Configuration] Using adblock-android ABI flavor: abi_arm

output while building.

SDK tests

Pure java tests

You can find pure Java tests in the 'src/test' directories of the modules (if provided). In the project directory run:

./gradlew test

You can select the test class/method and click 'Run ..Test'. No Android emulator/device running is required.

Android tests

You can find Android tests in the 'src/androidTest' directories of the modules (if provided). In the project directory run:

./gradlew connectedAbi_x86DebugAndroidTest

to test with x86 device/emulator or run:

./gradlew connectedAbi_armDebugAndroidTest

to test with ARM device/emulator. You can select the test class/method and click 'Run ..Test'.

Settings

An Android library that provides a configuration interface for Adblock Plus. You can find it in the 'adblock-android-settings' directory:

  • GeneralSettingsFragment - main fragment
  • WhitelistedDomainsSettingsFragment - whitelisted domains fragment

Using as a Gradle dependency

Make sure you have jcenter() in the list of repositories and then add the following dependency:

dependencies {
    implementation 'org.adblockplus:adblock-android-settings:+'
}

In the general case, it's suggested to use the most recent version.

Usage

Create AdblockEngineProvider instance and AdblockSettingsStorage instance. You can use the SharedPrefsStorage implementation to store settings in SharedPreferences. Or you can use AdblockHelper:

AdblockHelper
  .get()
  .init(this, getFilesDir().getAbsolutePath(), true, AdblockHelper.PREFERENCE_NAME);

  // optional - provide preloaded subscription files in app resources
  .preloadSubscriptions(AdblockHelper.PRELOAD_PREFERENCE_NAME, map);

Make sure you initialize it once during app launch, call isInit() to check it:

if (!AdblockHelper.get().isInit())
{
  // requires initialization
  ...
}

Sometimes it's desired to initialize or deinitialize the AdblockEngine instance when created:

AdblockHelper
  .get()
  .init(...)
  .addEngineCreatedListener(engineCreatedListener)

or disposed:

AdblockHelper
  .get()
  .init(...)
  .addEngineDisposedListener(engineDisposedListener)

Make sure you deinitialize it when values used during initialization are no longer valid:

AdblockHelper.get().deinit();

Note: one has to initialize it again to be used.

Implement the following interfaces in your settings activity:

  • BaseSettingsFragment.Provider
  • GeneralSettingsFragment.Listener
  • WhitelistedDomainsSettingsFragment.Listener

and return created instance or AdblockHelper instances:

AdblockHelper.get().getProvider().getEngine();  // engine
AdblockHelper.get().getStorage(); // storage

Retain Adblock instance in activity onCreate in synchronous mode (it may take few seconds):

AdblockHelper.get().getProvider().retain(false);

or in asynchronous mode (without current thread lock):

AdblockHelper.get().getProvider().retain(true);

Invoke waitForReady every time you need AdblockEngine instance if retained in asynchronous mode:

AdblockHelper.get().getProvider().waitForReady();

Release Adblock instance in activity onDestroy:

AdblockHelper.get().getProvider().release();

Insert GeneralSettingsFragment fragment instance in runtime to start showing settings UI.

Memory management

Adblock Engine sometimes might be extensive to memory consumption. To guard your process from being killed by the system, call the AdblockEngineProvider#onLowMemory() method in ComponentCallbacks2#onTrimMemory(int).

  @Override
  public void onTrimMemory(int level)
  {
    // ...
    // if a system demands more memory, call the GC of the adblock engine to release some
    // this can free up to ~60-70% of memory occupied by the engine
    if (level == TRIM_MEMORY_RUNNING_CRITICAL && AdblockHelper.get().isInit())
    {
      AdblockHelper.get().getProvider().onLowMemory();
    }
    // ...
  }

If you are using androidx.fragment.app.Fragment or androidx.appcompat.app.AppCompatActivity, be sure to implement [ComponentCallbacks2] and register it by calling Context#registerComponentCallbacks(ComponentCallbacks2) and then unregister when not needed with Context#unregisterComponentCallbacks(ComponentCallbacks2)

If you are using old APIs, it's also possible to use any of onLowMemory() system callbacks: either Activity#onLowMemory() or Fragment#onLowMemory().

Please mind that if you are using AdblockHelper (which is in most cases), AdblockEngine exists only in one instance. Having one instance means that you only have to implement one call to AdblockHelper.get().getProvider().onLowMemory();. Thus it's recommended to do the call in Activity or somewhere else where you are sure you are not creating multiple instances (e.g. fragments).

Background operations

By default AdblockEngine will do some background operations like subscriptions synchronizations in the background shortly after initialized. If you want to have ad-blocking as an optional feature, you should consider using setDisabledByDefault

    AdblockHelper
      .get()
      .init(...)
      .setDisabledByDefault()

In this case no background operations will be done until you call AdblockEngine.setEnabled(true). Please note that setDisabledByDefault() only configures the default state. If user preference on the enabled state is stored in settings it will have priority.

Another thing to take into account is synchronization time. If you have configured setDisabledByDefault and then enable the engine, the first synchronization will be done only after some time. You can combine configuration with preloadSubscriptions to load data from local file first time rather than from the web.

Preloaded subscriptions

As mentioned previously, there is an option to set preloaded subscriptions. This means that at the application's first boot time, and every time the user clears the app's data, it will load the subscription lists that are bundled with the app. It will also set async calls to update these lists at once so that they are updated as soon as possible. Keep in mind that the ad-block engine will still periodically check for updates on the subscriptions at an hourly interval.

The benefit of using this feature is that it provides a better UX since the app does not have to wait for the subscription lists to be downloaded first, allowing the user to have an ad-blocking experience right away.

On the other hand, this is an opt-in feature that you have to set up. It also increases the footprint of the app by bundling the subscription lists with it, and you have to update the lists when building the apk. This is because subscription lists become outdated very fast. Ideally, you can set a gradle task for that, which is what we did.

By running ./gradlew downloadSubscriptionLists, you update the preloaded subscriptions with the latest minified EasyList and minimal exception list.

To set it up in the code, you can either explicitly map all the possible locale-specific subscriptions URLs to local files. Or you can set one general subscription file for all non AA and another for the AA subscription.

Usage example in a simplified way where all blocking subscriptions (like "easylist.txt" or "easylistgermany+easylist.txt") are mapped to the same file R.raw.easylist:

adblockHelper
    .get()
    .init(this, basePath, AdblockHelper.PREFERENCE_NAME)
    .preloadSubscriptions(R.raw.easylist, R.raw.exceptionrules)
    .addEngineCreatedListener(engineCreatedListener)
    .addEngineDisposedListener(engineDisposedListener)

To explicitly set which subscriptions to be preloaded use preloadSubscriptions() with a map argument:

Map<String, Integer> map = new HashMap<String, Integer>();
map.put(AndroidHttpClientResourceWrapper.EASYLIST, R.raw.easylist);
map.put(AndroidHttpClientResourceWrapper.ACCEPTABLE_ADS, R.raw.exceptionrules);

Note that in this example we use the general EasyList subscription. So for example, if you are using subscription lists for another locale, you need to change the URL and replace the file with the correct one. The effect is not the same without these preloaded subscriptions.

Then, when using the AdblockHelper for example, you can set it like:

adblockHelper
    .get()
    .init(this, basePath, AdblockHelper.PREFERENCE_NAME)
    .preloadSubscriptions(AdblockHelper.PRELOAD_PREFERENCE_NAME, map)
    .addEngineCreatedListener(engineCreatedListener)
    .addEngineDisposedListener(engineDisposedListener)

Theme

Make sure to set the application theme with PreferenceThemeOverlay.v14.Material parent theme (see AndroidManifest.xml and styles.xml in adblock-android-webviewapp as an example).

Building

In the project root directory run:

./gradlew assemble

This will generate *.aar in the 'adblock-android-settings/build/outputs/aar' directory.

WebView

An Android library that provides a WebView component with Adblock Plus integrated. You can find it in the 'adblock-android-webview' directory.

AdblockWebView class provides built-in ad blocking (both resource loading filtering and element hiding) and inherits from Android 'WebView'.

Using as a Gradle dependency

Make sure you have jcenter() in the list of repositories and then add the following dependency:

dependencies {
    implementation 'org.adblockplus:adblock-android-webview:MAJOR.MINOR.PATCHLEVEL'
}

In the general case it's suggested to use the most recent version.

Usage

In layout XML:

<org.adblockplus.libadblockplus.android.webview.AdblockWebView
    android:id="@+id/main_webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

In java source code:

AdblockWebView webView = findViewById(R.id.main_webview);

Use AdblockEngine.setEnabled(boolean enabled) to enable/disable ad blocking for AdblockEngine. Make sure you update the settings model if you want the new value to be applied after the restart of the application, eg:

AdblockSettingsStorage storage = AdblockHelper.get().getStorage();
AdblockSettings settings = storage.load();
if (settings == null) // not yet saved
{
  settings = AdblockSettingsStorage.getDefaultSettings(...); // default
}
...
settings.setAdblockEnabled(newValue);
storage.save(settings);

Android SDK logging system is based on the Timber library.

If you are configuring your project using Maven dependencies to consume our Android SDK then Timber dependency is automatically installed. If you are just copying AAR files to your project workspace then you need to add this line to your dependencies:

implementation 'com.jakewharton.timber:timber:4.7.1'.

To enable desired log output level you should configure the Timber logger in your application code.

For example, this code enables all debug logs in DEBUG mode:

if (BuildConfig.DEBUG) {
    Timber.plant(new Timber.DebugTree());
}

Please refer to https://github.com/JakeWharton/timber for more information about Timber.

Use setAllowDrawDelay(int allowDrawDelay) to set the custom delay to start rendering a web page after the 'DOMContentLoaded' event is fired.

Use setProvider(@NotNull AdblockEngineProvider provider) to use external adblock engine provider. The simplest solution is to use AdblockHelper from -settings as an external adblock engine provider:

webView.setProvider(AdblockHelper.get().getProvider());

If the adblock engine provider is not set, it's created by the AdblockWebView instance automatically.

Use setSiteKeysConfiguration(..) to support sitekeys whitelisting. This is optional but highly suggested. See TabFragment.java on usage example.

Please note that the AdblockWebView does intercept some of the HTTP(S) requests done by the subclassed WebView and does them internally by means of java.net.HttpURLConnection. For doing so AdblockWebView maintains the cookies in sync between the java.net.CookieManager and android.webkit.CookieManager. The sync is maintained by replacing the default CookieHandler with a SharedCookieManager which stores all the cookies in android.webkit.CookieManager storage. If a client code sets a cookie handler by calling java.net.CookieHandler.setDefault(), such a cookie handler will be later overwritten by our custom SharedCookieManager which is set by AdblockWebView when loading any url.

Use enableJsInIframes(true) to enable element hiding and element hiding emulation for iframes in AdblockWebView. This feature does not support yet element hiding for blocked requests. This is an optional feature that rewrites the HTML content under the hood in order to inject our custom element hiding (emulation) JavaScript before the </body> tag <script nonce="..">..</script>. If it's necessary, the CSP HTTP response header is updated by adding our nonce string to execute the script. This feature also requires setSiteKeysConfiguration(..) to be called beforehand, otherwise, an IllegalStateException is thrown. See TabFragment.java on usage example.

Use setEventsListener() to subscribe and unsubscribe to ad blocking and whitelisting events, eg. "resource loading blocked" or "resource loading whitelisted" event that can be used for stats. For the latter, there is a convenience class WebViewCounters which can be bound to EventsListener and notify your View about new values. See an example of usage in WebView Application.

Use dispose(Runnable disposeFinished) to release resources (required). Note it can be invoked from the background thread.

Enabling/disabling of ad blocking per AdblockWebView is not supported.

Ad blocking requires JavaScript to be enabled and every AdblockWebView instance enables JavaScript during the initialization.

Building

In the project root directory run:

./gradlew assemble

This will generate *.aar in the 'adblock-android-webview/build/outputs/aar' directory.

WebView Application

An Android application that demonstrates how to use AdblockWebView. You can find it in the 'adblock-android-webviewapp' directory.

Building

Make sure Library requirements are present.

In the project root directory run:

./gradlew assemble

This will generate *.apk in the 'adblock-android-webviewapp/build/outputs/apk/' directory.

Proguard

Required configuration changes

Configure Proguard/R8 to skip Adblock Android SDK files (root package org.adblockplus.libadblockplus) from being modified for Release build of the end-user application. See adblock-android/proguard-rules-adblock.txt as an example. If building an end-user application with Gradle, no actions are required - Gradle will use provided consumer Proguard file automatically. See https://developer.android.com/studio/projects/android-library "A library module may include its own ProGuard configuration file" section for further information.

Reason

Adblock Android SDK uses JNI behind the scene so Java classes and methods are accessed by full names from native code. If class names/members are modified by Proguard/R8 during Release build they can't be accessed from native code resulting in Runtime exceptions like follows:

java.lang.NoSuchMethodError: no non-static method "Lorg/adblockplus/libadblockplus/JsValue;.<init>(J)V"

Contribute

You are more than welcome to contribute! Please use Building sections from corresponding submodules in order to set up build them and start developing.

Git commits

This repo uses pre-commit to maintain agreed conventions in the repo. It should be installed (tldr; pip install pre-commit then pre-commit install) before making any new commits to the repo.

Code style

We use Eyeo Coding Style Convention as a base. In general:

  • Follow the Mozilla Coding Style general practices and its naming and formatting rules.
  • All files should have a license header, but no mode line comments.
  • Newline at end of the file, otherwise no trailing whitespace.
  • Lines can be longer than the limit if limiting line length would hurt readability in a particular case.
  • Opening braces always go on their own line.
  • No Hungarian notation, no special variable name prefixes or suffixes denoting type or scope.
  • All variable names start with a lower case letter.
  • Don't comment code out, delete it.

Java

Overall it inherits the basic code style rules above. More specific rules:

  • Spaces over tabs 
  • Indentation is in an increment of two spaces.
  • Dedicated new line on opening brackets and closing brackets.
// good 
void doSomething()
{
  if (that())
  {
  }
}
// bad 
void doSomething(){
  if (that()) {
  }
}
  • Inline comments leave space after marker 
  • Remove trailing white spaces 
  • Don’t exceed 120 characters per line
  • else should be followed with a new line
  • Add a new line at the end of the file 
  • Variables, parameters, and class members should be final where it is possible (they are not modified)

We use Checkstyle to verify syntax for Java. You can find the config in config\checkstyle\checkstyle.xml

You can verify the syntax in several ways:

  1. Gradle Checkstyle plugin. Just run ./gradlew checkstyle and it will perform codestyle check over all the submodules, including tests. Also
    • you can run the check over a submodule (eg ./gradlew :adblock-android:checkstyle)
    • you can run the check on tests on main source files only: ./gradlew checkstyleMain or ./gradlew checkstyleAndroidTest or ./gradlew checkstyleAndroidTest
  2. Android Checkstyle plugin. Install the plugin and import the config\checkstyle\checkstyle.xml. Then it will be automatically checking the codestyle for you.
  3. Pre-commit hook. For installation and usage, please check the Git commits section. We use github.com/gherynos/pre-commit-java hook for checking codestyle. It will run on every commit if pre-commit hooks are installed.

More Repositories

1

adblockpluschrome

Mirrored from https://gitlab.com/eyeo/adblockplus/adblockpluschrome
JavaScript
546
star
2

adblockplus-legacy

DEPRECATED: Adblock Plus extension for Firefox and other Gecko-based browsers
JavaScript
360
star
3

adblockplusandroid

Adblock Plus app for Android
Java
236
star
4

backup-adblockplus

Adblock Plus extension for Firefox and other Gecko-based browsers
JavaScript
231
star
5

backup-adblockpluschrome

Adblock Plus extension for Google Chrome
JavaScript
224
star
6

adblockplussafariios

Adblock Plus Safari iOS source code
Objective-C
151
star
7

libadblockplus

A C++ wrapper library around the core functionality of Adblock Plus
C++
132
star
8

adblockpluscore

Mirrored from https://gitlab.com/eyeo/adblockplus/adblockpluscore
JavaScript
115
star
9

abp2blocklist

Code to convert Adblock Plus filter lists to WebKit content blocker lists
JavaScript
91
star
10

adblockplussbrowser

Adblock Plus for Samsung Browser source code
Java
33
star
11

python-abp

Adblock Plus utilities for Python
Python
32
star
12

abpcrawler

Website crawler for Adblock Plus
Python
26
star
13

adblockplus

Shared Adblock Plus UI code
JavaScript
26
star
14

gyp

Fork of https://chromium.googlesource.com/external/gyp.git
Python
23
star
15

infrastructure

Puppet-based configuration definitions for various servers used by the Adblock Plus project.
Puppet
17
star
16

adblockplusie

Adblock Plus for Internet Explorer
C++
16
star
17

buildtools

Build tools for Adblock Plus and related extensions
Python
12
star
18

elemhidehelper

DEPRECATED: Element Hiding Helper extension for Adblock Plus
JavaScript
10
star
19

sitescripts

Various scripts used on adblockplus.org, mirrored from https://gitlab.com/eyeo/devops/legacy/sitescripts
Python
8
star
20

web.adblockplus.org

AdblockPlus.org website content
JavaScript
6
star
21

cms

CMS used for adblockplus.org [mirrored from https://gitlab.com/eyeo/websites/cms]
Python
6
star
22

adblockbrowserios

Swift
5
star
23

libadblockplus-binaries

Binaries created from libadblockplus repository (for faster Android builds)
C++
4
star
24

abpcustomization

DEPRECATED: Customizations for Adblock Plus extension
Python
4
star
25

jshydra

JSHydra, a static analysis tool for JavaScript (forked from http://hg.mozilla.org/users/Pidgeot18_gmail.com/jshydra)
JavaScript
4
star
26

web.acceptableads.org

Source files for the acceptableads.org web content
HTML
3
star
27

abpwatcher

DEPRECATED: Diagnostics for Adblock Plus extension
JavaScript
2
star
28

yajl-dynamic

YAJL 2.1.0 dynamic framework for iOS
C
2
star
29

web.adblockbrowser.org

Source files for the adblockbrowser.org web content
CSS
2
star
30

adblockbrowserios-core

Swift
2
star
31

adblockbrowser

Adblock Browser for Android source code
2
star
32

adblockplustests

DEPRECATED: Firefox extension running Adblock Plus unit tests
JavaScript
2
star
33

easylist.adblockplus.org

Source files for the easylist.adblockplus.org web content
1
star
34

needs-translation

Configurable translations diff and exclusion tool for XLIFF 1.2 designed for Xcode localization exports
JavaScript
1
star
35

chromium-src-build

Fork of https://chromium.googlesource.com/chromium/src/build
Python
1
star
36

subscribe.adblockplus.org

Source files for the subscribe.adblockplus.org web content
1
star
37

youtube.adblockplus.me

Source files for the youtube.adblockplus.me web content
HTML
1
star
38

share.adblockplus.org

Source files for the share.adblockplus.org web content
HTML
1
star
39

chromium-trace_event-common

Fork of https://chromium.googlesource.com/chromium/src/base/trace_event/common
C++
1
star
40

codingtools

Various tools to aid working on Adblock Plus code
Python
1
star