Mark L. Murphy's Blog, page 38
December 27, 2016
PSA: v25.1.0 Support Fragments Behavior Change
The most recent Awesome Android Newsletter
contained a link to an Android issue
about a side-effect of an API change.
Up until a few weeks ago, both for the native implementation of fragments
(android.app.Fragment) and the Android Support Library backport
in support-v4 (android.support.v4.app.Fragment), when executing
a replace() transaction, the fragment being replaced would be called
with onStop() before the replacement fragment would be called
with onStart().
However, the v25.1.0 version of the backport inverts this by default,
with onStart()
of the replacement fragment being called before onStop() is called
on the fragment being replaced.
And, since this issue is flagged as ���working as intended���, this default
behavior seems unlikely to change.
Note that the native implementation of fragments behaves as it has ���
this change has not affected Android 7.1.1, for example. Also note
that calling setAllowOptimization(false) on the FragmentTransaction
should revert this change and roll you back to the prior behavior.
This is part of a larger optimization change that aims to apply only the
subset of your transactions that represent the overall net change in the
state of the fragments. Quoting the documentation:
For example, one transaction adds fragment A, a second adds fragment B, then a third removes fragment A. Without optimization, fragment B could expect that while it is being created, fragment A will also exist because fragment A will be removed after fragment B was added. With optimization, fragment B cannot expect fragment A to exist when it has been created because fragment A���s add/remove will be optimized out.
If you have code that is dependent upon the order of these lifecycle
events, you will want to double-check how your code behaves with
fragment optimizations enabled. If you encounter problems, either adjust
your code or disable the optimizations.
December 15, 2016
About the Support ExifInterface
Version 25.1.0 of the Android Support library has debuted a new
com.android.support:exifinterface artifact, which offers a standalone
implementation of ExifInterface, a Java class for reading the EXIF
tags from JPEG and raw files.
If that class name sounds familiar, that is because:
in May,
I suggested moving ExifInterface into Android Support, to
provide InputStream as a data source, to better work with content
Uri values
in September,
I suggested moving ExifInterface into Android Support, to give
us an implementation that was free of the security bug that Tim Strazzere
uncovered
The new ExifInterface is not showing up in
the online Android developer documentation.
Also, there are no JavaDocs in the Android Support Repository (the
JavaDocs JAR is effectively empty). Hopefully,
this is a temporary hiccup.
Based on eyeballing the source to android.support.media.ExifInterface,
it seems like they matched the API of the Android 7.0 ExifInterface
implementation.
This solves two problems:
We now have an ExifInterface constructor that takes an InputStream
This implementation is pure Java, and so it avoids the buggy JHEAD
implementation that was the source of the security flaw
Note though that this class ��� and its SDK counterpart ���
offers a limited API compared with ExifInterface code
elsewhere in the AOSP. In particular:
You cannot modify the thumbnail image
You cannot save modified EXIF tags, thumbnails, etc. to a different
JPEG file than the one that you started with
Hence, you may find yourself still needing to use a separate EXIF
parser, just to get needed functionality.
That being said, though, the ExifInterface in the the Android Support
library is a welcome addition, and I am very grateful to the engineers
who took the time to create it!
December 13, 2016
Security Things About Android Things
Today, Google released
a developer preview
of Android Things.
Android Things, roughly speaking, is ���usually-headless Android���, designed
to run on embedded hardware, with an eye towards ���the Internet of Things���
(IoT) use cases. There have been many developers over the years attempting
to do this sort of thing using stock Android, and so I would imagine
that Android Things will have reasonable success.
However, in the security space, the most polite term for IoT seems to
be ���the Internet of Really Insecure Things���. Names go downhill rapidly
from there, frequently involving profanity.
This is not an idle concern. The Mirai botnet
is powered by IoT devices and took down chunks of the Internet earlier
this year through an attack on Dyn���s DNS servers.
Mirai is not alone in exploiting poorly-secured IoT devices, and I
expect that Dyn-caliber attacks will become all too common.
With Android Things, now you get to add to the Internet of Really Insecure
Things.
IoT devices usually need some sort of a control interface, so owners can
tell the devices what to do and how to behave. Sometimes, those control
interfaces will be purely local (e.g., Bluetooth via an app on a phone
or tablet). Sometimes, you will want those control interfaces to be
over the Internet, or at least over a local network.
In those cases, sometimes you will tie into an
existing framework, such as Google���s proprietary
Weave,
and sometimes you will try to roll your own.
We rarely host control interfaces, such as embedded Web servers,
on phones and tablets,
which is why this concern has not been at the forefront of security
issues for Android app developers.
If you elect to roll your own network-based control interface:
You and your organization need to take security very, very seriously
You and your organization need a good legal defense fund, in case
you fail in your attempt to secure that control interface
Android Things offers a lot of promise to make IoT development easier.
That is a double-edged sword, as ���easier��� all too often means ���sloppier���
in software development. Sloppy UIs, sloppy threading, and sloppy storage
may make users unhappy. Sloppy IoT security, like pollution, is
what economists call an
���externality���,
where the costs of sloppiness are
paid by society. Where there are externalities, lawsuits and regulation
follow, as society pushes back against the sloppiness.
Make security a priority in your Android Things projects. Please.
December 12, 2016
FYI: sdkmanager for Command-Line SDK Installs
In version 25.2.3 of the SDK Tools package, Google quietly slipped
in sdkmanager, a command-line tool for installing SDK packages.
This is documented,
though I do not recall seeing an announcement about it.
If you have been struggling to keep the old android command going
for command-line SDK work ��� for example, for CI server configuration ���
it would appear that sdkmanager is at least the near-term replacement.
sdkmanager itself gets installed to $ANDROID_SDK/tools/bin/, where
$ANDROID_SDK is wherever you have the Android SDK installed. This
appears to be a new directory; leastways, in my environment, sdkmanager
is the only thing in there. Hence, you might not have this directory
in your PATH.
sdkmanager is not perfect. For example, the output of --list
is simultaneously not very human readable
and not very machine readable. But, it is what we have.
November 28, 2016
Certificate Pinning and Failing Open
SSL is nice, but there are risks of fraudulent certificates being
issued by rogue certificate authorities. One approach to dealing with
this risk is to use certificate pinning, teaching your Android app
details about the expected SSL certificate, so the app can fail if it
encounters a fraudulent one. This reduces the risk of somebody with
a fake cert intercepting your communications. However, it can increase
other risks, as Square���s Jesse Wilson pointed out earlier today.
For example:
If you pin to your own certificate, that works, until you need to
replace that certificate, because it is expiring or for other reasons
(e.g., the Heartbleed attack ���OMG replace all teh certs!��� response)
If you pin to some other certificate up the chain towards the CA���s
root certificate, that works, until the intermediary needs to replace
the certificate
I imagine that this is why Android 7.0���s
network security configuration���s
certificate pinning implementation fails open. In other words, when
you put an expiration date on a pinned certificate, when that date arrives,
that pin is ignored. For planned certificate obsolescence ���
such as the certificate���s own expiration date ��� this will allow your
app to keep working, even for those users who failed to update their
app. Users who update their app can be moved over to a new pin for a new
certificate. Since CWAC-NetSecurity
is a backport of Android 7.0���s network security configuration, it too
supports expiring pins.
If you elect to pin certificates, whether using network security configuration
or something else:
Set an expiration date on the pin, and fail open. Yes, this reduces
security, but only for those users running older editions of your app.
Have a plan for an emergency app update, in case you need to replace
the server���s SSL certificate in a hurry (e.g., Heartbleed-style
scenarios).
For a server that only handles mobile apps, not Web browsers, you could
avoid some of this by switching to a self-signed certificate and effectively
���pinning��� to that. Since there is no certificate authority in the mix,
you are not at risk of a certificate authority screwing up, being hacked,
or being suborned into issuing a fraudulent certificate.
Remember: the rationale
behind a certificate authority is to help the user with a generic client
app (Web browser) determine if a certificate is valid. It does not add
as much value in scenarios with a specific client, such as an Android app
dealing exclusively with your server.
November 22, 2016
Random Musings on the 7.1 Developer Preview 2
Each time Google releases a new developer preview, I try to
talk about the changes that may not be obvious when reading the
high-level descriptions.
However, in this case, there does not seem to be much that is different
that affects most developers, beyond the items that I mentioned in
my Developer Preview 1 post.
Near as I can tell, this is just bug fixes, which makes sense, if the
rollout of 7.1 to non-Pixel phones is only weeks away.
November 21, 2016
Consuming Content? Be Flexible!
Many times, when we work with a content Uri, we get an InputStream,
read in the content, and we���re good to go.
Sometimes, though, consumers of content make some unfortunate assumptions.
One assumption is that you can pass rw in for the mode on
openFileDescriptor()
and kin. First, this assumes that you have write access, which may or
may not be true. Plus, rw requires that the content that you are
working with be stored as a plain file on the filesystem somewhere.
Another related assumption is that the InputStream is seekable,
supporting mark() and reset(). Once again, this only works
if the content in question is backed by a plain file on the filesystem.
However, increasingly, that will not be the case, as more and more
developers turn to publishing content, to get around things like
the file Uri ban in Android 7.0.
While content may be backed by a plain file on the filesystem,
it might also be backed by:
A file, but one that needs to be transformed on the fly by the
provider (e.g., decrypted)
A piece of a file (e.g., an asset packaged in the app���s APK)
Something in memory (e.g., the contents of a BLOB column that
was read in from a database)
Something being streamed from the Internet (though this is kinda
risky IMHO, on the provider���s part)
The ContentProvider publishing this content will be using something
other than a file-based ParcelFileDescriptor, usually in the form
of a pipe or socket pair. Those do not support rw mode, nor do they
support seeking.
In particular, if your app is usable with read-only non-seekable content,
but perhaps with a subset of functionality, make sure that you support
it. For example, a couple of Android PDF viewers ��� including Google���s
Drive PDF Viewer ��� seem to require rw access and crash in situations
where other apps (e.g., Adobe Reader) work fine. Gracefully degrade in
these cases: try for rw access, and then try for r access if the rw
attempt fails.
If seekability is the issue, more so than rw access, you can try
calling getStatSize() on the ParcelFileDescriptor that you get
back from openFileDescriptor() on the ContentResolver. If this
returns -1, then there is a good chance that the stream is not file-backed
and will not support seeking. If this returns 0 or a positive value,
that should be the size of the file that the stream is delivering to you.
If you need a test case for these cases, toss
my StreamProvider
in your test suite and test against an asset served via a content
Uri. This will be a non-seekable stream on which rw is not an
option (as you cannot modify an asset).
The majority of the time, when you get a content Uri, it will
be served by a provider that is using a file for the content. In that
case, rw mode may be available, and seeking should work. Just do
not assume that you can always do that for every Uri. Make
sure that you test cases where the Uri is something else, and that
you handle those cases as best as you can.
November 18, 2016
Be Careful with Scoped Directory Access
Android 7.0 added scoped directory access.
This API allows you to ask the user for blanket access to a common
public directory on an arbitrary StorageVolume, such as a USB OTG
drive or other removable storage. If the user grants access, you get
a Uri back, akin to as if you had used ACTION_OPEN_DOCUMENT_TREE
and the user happened to have chosen that particular directory. The
difference is that you are choosing the directory, from
a list of candidates,
rather than granting the user full freedom to choose any directory
or other ���document tree��� that the user wants.
However, there is a UX flaw with scoped directory access.
The flow of the permission dialogs resembles that of Android 6.0���s
runtime permissions:
When you first ask for access, the user can allow or deny
If the user denied access, and you later ask for access again,
the dialog now has a ���Don���t ask again��� checkbox
If the user checked that checkbox and denied access again, any future
attempts you make to request access will be denied immediately,
without the user seeing a dialog
One problem is that we have no good way of knowing that the user
has previously denied our request, let alone checked the ���Don���t ask
again��� checkbox. With Android 6.0���s runtime permissions, we have
checkSelfPermission() and shouldShowPermissionRequestRationale()
for those things. We have no equivalents for scoped directory access.
However, the bigger problem is that once the user checks ���Don���t ask
again��� and denies access, the user has no further recourse. With
runtime permissions, the user can always go into the Permissions
area of your app���s page in Settings and manually grant permissions.
There is no equivalent of this for the scoped directory access API.
On one device (a Nexus 5X running the 7.1 preview), the user
can use ���Clear Data��� to reset these dialogs, causing future dialogs
to appear again even if ���Don���t ask again��� had been checked. Of course,
���Clear Data��� has somewhat broader impact than this, and the user might
not appreciate wiping out all the app���s local data.
Worse, on two test devices (a Nexus 5X running 7.0 and a Google Pixel
running 7.1), not only does ���Clear Data��� not fix this, but
a full uninstall of the app does not fix this. AFAICT, nothing short
of a factory reset would allow the app to ask the user for permission
and the user have an opportunity again to grant permission.
Admitttedly, this is an edge case, but it is one that you should
keep in mind if you are using createAccessIntent() and the
scoped directory access API. I filed
this issue
to try to get some resolution to how the user is supposed to manually
revert the ���Don���t ask again��� status.
November 14, 2016
The Busy Coder's Guide to Android Development Version 8.1 Released
Subscribers now have
access to the latest release of The Busy Coder���s Guide to Android Development,
known as Version 8.1, in all formats. Just log into
your Warescription page and download
away, or set up an account and subscribe!
This time around, I:
Added a new chapter on the basic steps for writing Gradle plugins
Added a new chapter on compile-time code generation,
by means of a Gradle plugin and Square���s JavaPoet
Added a new chapter on updating your app���s code dynamically,
as a counterpart to updating the app���s code by publishing a new APK
Added a new chapter on Android 7.1���s app shortcuts, both the static
kind (which can be used by pre-7.1 home screens) and the dynamic kind
Added a new chapter on Java 8 lambda expressions,
enabled via the Jack compiler
Added a new section to the RecyclerView chapter
on using DiffUtil to identify and animate changes to the
contents of a RecyclerView
Overhauled the chapter on NetCipher
Added a bit more material on ConstraintLayout
Made other minor improvements and errata fixes
Also, the APK edition of the book has a new appinar on drag-and-drop.
Barring some major code drop from Google here in the waning weeks of 2016,
this is the eighth and final update for this year, adding about 500
pages of material, along with the first 24 appinars.
The next update is tentatively scheduled for early January 2017.
November 10, 2016
Freeform Windows, the 7.0 CDD, and You
After some delay, Google published
the Android 7.0 edition of Compatibility Definition Document.
This outlines the requirements of Android device manufacturers who wish
to license the Play Store and other Google proprietary apps.
I was waiting for this CDD to be released, to see what it covered regarding
freeform multi-window mode.
The SDK documentation has:
Manufacturers of larger devices can choose to enable freeform mode, in which the user can freely resize each activity. If the manufacturer enables this feature, the device offers freeform mode in addition to split-screen mode.
However, at the same time,
we do not have an official freeform multi-window test environment.
Hence, I was hoping that the SDK documentation passage represented
a bit of a documentation bug. Even if the OS itself supported freeform
mode, surely Google would not authorize its use via the CDD. After all,
new Android releases are riddled with bugs, including many 7.0 bugs
with split-screen multi-window mode. It would be risky, at best, for Google
to officially condone freeform multi-window mode when the vast majority
of Android developers have no formal means of testing Android���s freeform
multi-window mode.
Google tells manufacturers to use it anyway.
Specifically, the section on multi-window support
contains two passages directly referencing freeform:
Device implementations MUST NOT offer split-screen or freeform mode if both the screen height and width is less than 440 dp.
This is what enforces the ���your window will never be smaller than 220dp���
rule. This is reasonable, though strangely it does allow picture-in-picture (PIP)
mode for these small screens, and a later passage allows that PIP window
to be 240x135dp.
Device implementations with screen size xlarge SHOULD support freeform mode.
In the parlance of this CDD, there appear to be three levels of
endorsement: SHOULD, STRONLY ENCOURAGED, and MUST. SHOULD is the weakest
of the three, but it is still an endorsement. So, 10���+ tablets running
7.0 may well start offering freeform multi-window mode, literally at
any point.
Except, of course, for the Pixel C, the one official Google device that
meets the xlarge requirement. It does not, as of today, offer freeform
mode, meaning that Google is not listening to Google.
The technique that I mentioned a month ago,
using adb shell settings put global enable_freeform_support 1, does
work with the Pixel C, as well as with emulators and other Android 7.0/7.1
hardware.
However, this hacked freeform mode is fairly weak.
It is difficult for me to believe that Google wants manufacturers
shipping with this as the stock behavior. Perhaps the
freeform mode that manufacturers would enable is different from
what enable_freeform_support offers��� but then, we still would need an official
test environment to see how our apps will work and whether freeform
multi-window mode has any bugs.
What should you do?
Try your app with enable_freeform_support enabled, at least on an
xlarge-caliber emulator. This is unofficial and may bear little
resemblance to what future devices will use, but it is all we have.
Pray to the deity of your choice that no manufacturer ships with freeform
enabled until we have an official way of testing our app���s behavior.


