The CommonsBlog


StrictMode for API Greylist Monitoring

Android P is putting restrictions on apps’ (and libraries’) ability to use hidden stuff, as I covered in January and in March. We were told to monitor LogCat, watching for “blacklist” and “greylist” messages showing what methods we called that were banned.

However, LogCat isn’t a great solution for this sort of thing:

  • LogCat gets flooded with messages, so these messages can get lost in the shuffle

  • These messages are not posted with error severity, so they do not stand out

  • These messages do not provide a stack trace or other concrete indication of where we are calling the banned API

Back in March, I asked for a solution for that third bullet. Much to my shock and amazement, a solution was granted in P DP2: greylist monitoring is now tied into StrictMode, via detectNonSdkApiUsage().

This gives us two main options for raising awareness of where and how we are using banned APIs. The classic solution would be to crash the app, by applying penaltyDeath() to the VmPolicy. This works but is a bit limited. Suppose we find a banned API use in a library. We may not be in position to fix the library ourselves and need to wait for some update to the library that avoids this banned API. However, in the interim, we may not be able to cope with our app crashing when we use the library.

Fortunately, Android P also adds another option to the StrictMode family of “penalties”: we can use penaltyListener() to receive a callback on a StrictMode violation. We are given a Violation object that describes the specific problem (CleartextNetworkViolation, NonSdkApiUsedViolation, etc.). And Violation is a Throwable, from which we can get a stack trace showing exactly where the problem occurred.

For example, this JUnit4 Suite logs each Violation to a file in getExternaCacheDir():

public class GreylistSuite {
  private static final String TAG="GreylistSuite";
  private static final ExecutorService LISTENER_EXECUTOR=Executors.newSingleThreadExecutor();
  private static File logDir=
    new File(InstrumentationRegistry.getTargetContext().getExternalCacheDir(), "__greylist");

  @BeforeClass
  public static void init() {
    if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.P) {
      if (logDir.listFiles()!=null) {
        for (File file : logDir.listFiles()) {
          if (!file.isDirectory()) {
            file.delete();
          }
        }
      }

      StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
        .detectNonSdkApiUsage()
        .penaltyListener(LISTENER_EXECUTOR, GREYLISTENER)
        .build());
    }
  }

  @AfterClass
  public static void term() {
    LISTENER_EXECUTOR.shutdown();

    try {
      LISTENER_EXECUTOR.awaitTermination(5, TimeUnit.SECONDS);
    }
    catch (InterruptedException e) {
      Log.e(TAG, "Saving stack traces took too long!", e);
    }
  }

  private final static StrictMode.OnVmViolationListener GREYLISTENER=
    new StrictMode.OnVmViolationListener() {
      @Override
      public void onVmViolation(Violation violation) {
        logDir.mkdirs();

        String name=Long.toString(SystemClock.uptimeMillis())+".txt";
        File trace=new File(logDir, name);

        try {
          FileOutputStream fos=new FileOutputStream(trace);
          OutputStreamWriter osw=new OutputStreamWriter(fos);
          PrintWriter out=new PrintWriter(osw);

          violation.printStackTrace(out);
          out.flush();
          fos.getFD().sync();
          out.close();
        }
        catch (IOException e) {
          Log.e(TAG, "Exception writing trace", e);
        }
      }
  };
}

A test harness could check that directory for files and fail something if there are logged violations. The suite could even have its own “whitelist” capability, to not log violations matching some pattern (e.g., if Library A called Banned Method B, do not log it, as we know about that problem already).

The biggest limitation of the penaltyListener() approach is that the listener is called on a background thread, via an Executor that you supply. If you throw a RuntimeException of your own from onVmViolation(), it will crash the process, but since that crash is decoupled from the thread running the tests, it will not fail any specific test.

Still, I expect that penaltyListener() will be a powerful tool going forward, for banned API detection and other StrictMode violations. For example, one might imagine a Sonar plugin that surfaces StrictMode violations, complete with stack traces, to help developers catch these problems without totally breaking the flow of the app or test suite.

And, for the purposes of detecting banned API use, penaltyListener() is something to consider integrating into your testing, to be able to catalog all of the banned API uses and where they come from, so you can start figuring out what to do in case Android 9.0 blocks your access to those banned items.

Jun 12, 2018


Random Musings on the P Developer Preview 3

Android P Developer Preview 3 (P DP3) was released yesterday. I usually do a “random musings” post for these releases, as I did for P DP1 and P DP2.

This was a really tiny update, in terms of API changes.

Other than some tweaks to the P slice API, there is very little that should directly affect existing code. And, since I suspect most slicemongers are using the AndroidX slice API, even that will not affect you, until a new version of that AndroidX API is released.

I am curious about FEATURE_CANT_SAVE_STATE. A device with that feature is supposed to support cantSaveState (perhaps a new XML attribute on <application>?), which is described as:

Declare that this application can’t participate in the normal state save/restore mechanism. Since it is not able to save and restore its state on demand, it can not participate in the normal activity lifecycle. It will not be killed while in the background; the user must explicitly quit it. Only one such app can be running at a time; if the user tries to launch a second such app, they will be prompted to quit the first before doing so. While the application is running, the user will be informed of this.

My guess is that this is for dedicated single-app devices, as an adjunct to kiosk mode and similar features, but that is just a guess.

One thing that will not directly affect your code but will affect your UX is that call log-related permissions have been pulled out into a separate permission group. If you are requesting both phone-related permissions (e.g., READ_PHONE_STATE) and call log-related permissions (e.g., READ_CALL_LOG), you should get separate panes in the runtime permission dialog and will get separate entries in the list of permissions on your app’s screen in Settings. Unfortunately, at the moment, both permission groups share the same icon.

If you have been fighting API graylist/blacklist issues – perhaps because you have been naughty – it is possible that you will encounter some changes in behavior.

And, as Sebastiano Poggi and others pointed out, it appears that Android P is going to be Android 9.0.

Jun 07, 2018


The Busy Coder's Guide to Android Development Version 8.12 Released

Subscribers now have access to the latest release of The Busy Coder’s Guide to Android Development, known as Version 8.12, in all formats. Just log into your Warescription page and download away, or set up an account and subscribe!

This update:

  • Adds more to the Android P coverage, including:

    • A dedicated chapter on publising slices

    • BiometricPrompt (as the replacement for FingerprintDialog, which itself replaces the now-deprecated FingerprintManager)

    • AppComponentFactory

    • WebView tracing

    • New salvos in “the War on Background Processing”

  • Updates much of the book to cover Android Studio 3.1

  • Added material on the 1.1 release of ConstraintLayout, including groups, barriers, percentage constraints, and circular constraints

  • Rewrote the fragments chapter to focus on the fragments backport

  • Updated most remaining samples to use the fragments backport, for those that were not doing so already

  • Converted some samples that were using ListView to use RecyclerView, and moved the RecyclerView chapter to be earlier in the book

  • Added some material on the Chrome OS emulator

  • Moved the material on SlidingPaneLayout to the Widget Catalog

  • Made minor improvements to the chapters on Espresso, unit testing, and Ui Automator

  • Retired the chapter on dynamic code, the chapter on Android Things, the chapter on SlidingDrawer (from the Widget Catalog), and the chapter on large screen strategies, as well as some other specific sample apps and their corresponding sections)

  • Fixes a variety of errata and other miscellaneous bugs

Right now, I expect that I will publish Version 8.13 in about two months.

Jun 04, 2018


At Last... HtmlCompat

In the 28.0.0 edition of the support libraries ActiveX AndroidX Jetpack(?), we will get an HtmlCompat, offering an API compatible with the current implementation of Html. This will be very useful for getting consistent results both pre- and post-API Level 24, when the API was revamped, which deprecated methods like the one-parameter version of Html.fromHtml().

Such a class had been suggested two years ago, and it’s good to see that it was added.

OTOH, HtmlCompat suffers from the same documentation limitation as does Html: no specification for what subset of HTML is supported. API Level 24 expanded the support from the roster that I wrote up 8 years ago, but there is no official list of what is and is not supported. As a result, handing arbitrary HTML to HtmlCompat is still risky, in that you might wind up with a mix of actual formatting and unprocessed HTML tags.

But, this is still a step in the right direction, and I am grateful for it.

May 29, 2018


"Exploring Android" Version 0.3 Released

Subscribers now have access to an update to Exploring Android, known as Version 0.3, in PDF, EPUB, and MOBI/Kindle formats. Just log into your Warescription page and download away, or set up an account and subscribe!

This is a small update, adding two more tutorials, plus fixing some bugs in the previous versions.

Updates to this book are now on hold for a while. Later this year, I will revamp the book to be Android Jetpack-compliant, but that needs to wait until AndroidX ships in final form. That revamp will also make some other improvements to the tutorial implementation.

Also, at minimum, the revamp will involve Kotlin. I have not yet decided whether to replace Java with Kotlin, or whether to offer two separate editions of the book in parallel, one with Java and one with Kotlin. If you have thoughts on this, or if you have any other major structural changes that you would like me to consider, contact me at future@commonsware.com.

May 17, 2018


Older Posts