Merge "Doc change: Add best practices docs for permissions and ids." into mnc-docs
BIN
docs/html/images/cards/card-user-ids_2x.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/html/images/cards/card-user-permissions_2x.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/html/images/cards/card-user_2x.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 61 KiB |
740
docs/html/training/articles/user-data-ids.jd
Normal file
@@ -0,0 +1,740 @@
|
||||
page.title=Best Practices for Unique Identifiers
|
||||
page.metaDescription=How to manage unique identifiers the right way for users.
|
||||
page.tags=ids, user data
|
||||
meta.tags="ids", "user data"
|
||||
page.image=images/cards/card-user-ids_2x.png
|
||||
|
||||
page.article=true
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>In this document</h2>
|
||||
<ol>
|
||||
<li><a href="#tenets_of_working_with_android_identifiers">Tenets of Working with
|
||||
Android Identifiers</a></li>
|
||||
<li><a href="#version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</a></li>
|
||||
<li><a href="#working_with_advertising_ids">Working with Advertising IDs</a></li>
|
||||
<li><a href="#working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</a></li>
|
||||
<li><a href="#understand_identifier_characteristics">Understanding Identifier
|
||||
Characteristics</a>
|
||||
<ol>
|
||||
<li><a href="#scope">Scope</a></li>
|
||||
<li><a href="#resettability_&_persistence">Resettability & persistence</a></li>
|
||||
<li><a href="#uniqueness">Uniqueness</h3>
|
||||
<li><a href="#integrity_protection_and_non-repudiability">Integrity protection and
|
||||
non-repudiability</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#use_appropriate_identifiers">Common Use Cases and the Identifier to Use</a>
|
||||
<ol>
|
||||
<li><a href="#a_track_signed-out_user_preferences">Tracking signed-out user
|
||||
preferences</a></li>
|
||||
<li><a href="#b_track_signed-out_user_behavior">Tracking signed-out user behavior</a></li>
|
||||
<li><a href="#c_generate_signed-out_anonymous_user_analytics">Generating
|
||||
signed-out/anonymous user analytics</a></li>
|
||||
<li><a href="#d_track_signed-out_user_conversion">Tracking signed-out user
|
||||
conversion</a></li>
|
||||
<li><a href="#e_handle_multiple_installations">Handling multiple installations</a></li>
|
||||
<li><a href="#f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud:
|
||||
Enforcing free content limits / detecting Sybil attacks</a></li>
|
||||
<li><a href="#g_manage_telephony_&_carrier_functionality">Managing telephony and carrier
|
||||
functionality</a></li>
|
||||
<li><a href="#h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection:
|
||||
Identifying bots and DDoS attacks</a></li>
|
||||
<li><a href="#i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection:
|
||||
Detecting high value stolen credentials</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
While there are valid reasons why your application may need to identify a
|
||||
device rather than an instance of the application or an authenticated user on
|
||||
the device, for the vast majority of applications, the ultimate goal is to
|
||||
identify a particular <em>installation</em> of your app (not the actual
|
||||
physical device).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Fortunately, identifying an installation on Android is straightforward using
|
||||
an Instance ID or by creating your own GUID at install time. This document
|
||||
provides guidance for selecting appropriate identifiers for your application,
|
||||
based on your use-case.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For a general look at Android permissions, please see <a href=
|
||||
"{@docRoot}training/articles/user-data-overview.html">Permissions
|
||||
and User Privacy</a>. For specific best practices for
|
||||
working with Android permissions, please see <a href=
|
||||
"{@docRoot}training/articles/user-data-permissions.html">Best Practices for
|
||||
App Permissions</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="tenets_of_working_with_android_identifiers">Tenets of Working with Android Identifiers</h2>
|
||||
|
||||
<p>
|
||||
We recommend that you follow these tenets when working with Android
|
||||
identifiers:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#1: Avoid using hardware identifiers.</strong></em> Hardware
|
||||
identifiers such as SSAID (Android ID) and IMEI can be avoided in most
|
||||
use-cases without limiting required functionality.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#2: Only use Advertising ID for user profiling or ads
|
||||
use-cases.</strong></em> When using an <a href=
|
||||
"https://support.google.com/googleplay/android-developer/answer/6048248?hl=en">
|
||||
Advertising ID</a>, always respect the <a href=
|
||||
"https://play.google.com/about/developer-content-policy.html#ADID">Limit Ad
|
||||
Tracking</a> flag, ensure the identifier cannot be connected to personally
|
||||
identifiable information (PII) and avoid bridging Advertising ID resets.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#3: Use an Instance ID or a privately stored GUID whenever
|
||||
possible for all other use-cases except payment fraud prevention and
|
||||
telephony.</strong></em> For the vast majority of non-ads use-cases, an
|
||||
instance ID or GUID should be sufficient.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#4: Use APIs that are appropriate to your use-case to minimize
|
||||
privacy risk.</strong></em> Use the
|
||||
<a href="http://source.android.com/devices/drm.html">DRM
|
||||
API</a> API for high value content
|
||||
protection and the <a href="{@docRoot}training/safetynet/index.html">SafetyNet
|
||||
API</a> for abuse prevention. The Safetynet API is
|
||||
the easiest way to determine whether a device is genuine without incurring
|
||||
privacy risk.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The remaining sections of this guide elaborate on these rules in the context
|
||||
of developing Android applications.
|
||||
</p>
|
||||
|
||||
<h2 id="version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</h2>
|
||||
|
||||
<p>
|
||||
MAC addresses are globally unique, not user-resettable and survive factory
|
||||
reset. It is generally not recommended to use MAC address for any form of
|
||||
user identification. As a result, as of Android M, local device MAC addresses
|
||||
(for example, Wifi and Bluetooth) <em><strong>are not available via third party
|
||||
APIs</strong></em>. The {@link android.net.wifi.WifiInfo#getMacAddress WifiInfo.getMacAddress()}
|
||||
method and the {@link android.bluetooth.BluetoothAdapter#getAddress
|
||||
BluetoothAdapter.getDefaultAdapter().getAddress()} method will
|
||||
both return <code>02:00:00:00:00:00</code>..
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Additionally, you must hold the following permissions to access MAC addresses
|
||||
of nearby external devices available via Bluetooth and Wifi scans:
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th><strong>Method/Property</strong></td>
|
||||
<th><strong>Permissions Required</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code><a href="{@docRoot}reference/android/net/wifi/WifiManager.html#getScanResults()">WifiManager.getScanResults()</a></code>
|
||||
</td>
|
||||
<td>
|
||||
<code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code><a href="{@docRoot}reference/android/bluetooth/BluetoothDevice.html#ACTION_FOUND">BluetoothDevice.ACTION_FOUND</a></code>
|
||||
</td>
|
||||
<td>
|
||||
<code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code><a href="{@docRoot}reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(android.bluetooth.le.ScanCallback)">BluetoothLeScanner.startScan(ScanCallback)</a></code>
|
||||
</td>
|
||||
<td>
|
||||
<code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<h2 id="working_with_advertising_ids">Working with Advertising IDs</h2>
|
||||
|
||||
<p>
|
||||
Advertising ID is a user-resettable identifier and is appropriate for Ads
|
||||
use-cases, but there are some key points to bear in mind when using it:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>Always respect the user’s intention in resetting the advertising
|
||||
ID</strong></em>. Do not bridge user resets by using a more persistent device
|
||||
identifier or fingerprint to link subsequent Advertising IDs together without
|
||||
the user’s consent. The <a href=
|
||||
"https://play.google.com/about/developer-content-policy.html">Google Play
|
||||
Developer Content Policy</a> states:
|
||||
</p>
|
||||
|
||||
<div style="padding:.5em 2em;">
|
||||
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
|
||||
<p>...upon reset, a new advertising
|
||||
identifier must not be connected to a previous advertising identifier or data
|
||||
derived from a previous advertising identifier without the explicit consent
|
||||
of the user</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<em><strong>Always respect the associated Interest Based Advertising
|
||||
flag</strong></em>. Advertising IDs are configurable in that users can limit
|
||||
the amount of tracking associated with the ID. Always use the <code><a href=
|
||||
"https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html#isLimitAdTrackingEnabled()">
|
||||
AdvertisingIdClient.Info.isLimitAdTrackingEnabled()</a></code> method to
|
||||
ensure you are not circumventing your users' wishes. The <a href=
|
||||
"https://play.google.com/about/developer-content-policy.html">Google Play
|
||||
Developer Content Policy</a> states:
|
||||
</p>
|
||||
|
||||
|
||||
<div style="padding:.5em 2em;">
|
||||
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
|
||||
<p>...you must abide by a user’s ‘opt out of
|
||||
interest-based advertising’ setting. If a user has enabled this setting, you
|
||||
may not use the advertising identifier for creating user profiles for
|
||||
advertising purposes or for targeting users with interest-based advertising.
|
||||
Allowed activities include contextual advertising, frequency capping,
|
||||
conversion tracking, reporting and security and fraud detection.</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<em><strong>Be aware of any privacy or security policies associated with SDKs
|
||||
you use that are related to Advertising ID use.</strong></em> For example, if
|
||||
you are using the Google Analytics SDK
|
||||
<code><a href=
|
||||
"https://developers.google.com/android/reference/com/google/android/gms/analytics/Tracker.html#enableAdvertisingIdCollection(boolean)">mTracker.enableAdvertisingIdCollection(true)</a></code>
|
||||
method, make sure to review and adhere to all applicable <a href=
|
||||
"https://developers.google.com/analytics/devguides/collection/android/v4/policy">
|
||||
Analytics SDK policies</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Also, be aware that the <a href=
|
||||
"https://play.google.com/about/developer-content-policy.html">Google Play
|
||||
Developer Content Policy</a> requires that the Advertising ID “must not be
|
||||
connected to personally-identifiable information or associated with any
|
||||
persistent device identifier (for example: SSAID, MAC address, IMEI, etc.,)
|
||||
without the explicit consent of the user.”
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As an example, suppose you want to collect information to populate database
|
||||
tables with the following columns:
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td class="tab2">
|
||||
<code>timestamp</code></td>
|
||||
<td class="tab2">
|
||||
<code>ad_id</code></td>
|
||||
<td>
|
||||
<code><strong>account_id</strong></code></td>
|
||||
<td class="tab2">
|
||||
<code>clickid</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>TABLE-01</p>
|
||||
</td>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<code><strong>account_id</strong></code></td>
|
||||
<td class="tab2">
|
||||
<code>name</code></td>
|
||||
<td class="tab2">
|
||||
<code>dob</code></td>
|
||||
<td class="tab2">
|
||||
<code>country</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>TABLE-02</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<p>
|
||||
In this example, the <code>ad_id</code> column could be joined to PII via the
|
||||
<code>account_id</code> column in both tables, which would be a violation of
|
||||
the <a href=
|
||||
"https://play.google.com/about/developer-content-policy.html">Google Play
|
||||
Developer Content Policy</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Keep in mind that links between Advertiser ID and PII aren't always this
|
||||
explicit. It's possible to have “quasi-identifiers” that appear in both PII
|
||||
and Ad ID keyed tables, which also cause problems. For example, assume we
|
||||
change TABLE-01 and TABLE-02 as follows:
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><table>
|
||||
<tr>
|
||||
<td>
|
||||
<code><strong>timestamp</strong></code></td>
|
||||
<td class="tab2">
|
||||
<code>ad_id</code></td>
|
||||
<td>
|
||||
<code>clickid</code></td>
|
||||
<td>
|
||||
<code><strong>dev_model</strong></code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</pre>
|
||||
<p>TABLE-01</p>
|
||||
</td>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<code><strong>timestamp</strong></code></td>
|
||||
<td class="tab2">
|
||||
<code>demo</code></td>
|
||||
<td class="tab2">
|
||||
<code>account_id</code></td>
|
||||
<td>
|
||||
<code><strong>dev_model</strong></code></td>
|
||||
<td class="tab2">
|
||||
<code>name</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>TABLE-02</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<p>
|
||||
In this case, with sufficiently rare click events, it's still possible to
|
||||
join between the Advertiser ID TABLE-01 and the PII contained in TABLE-2
|
||||
using the timestamp of the event and the device model.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
While it is often difficult to guarantee that no such quasi-identifiers exist
|
||||
in a dataset, the most obvious join risks can be prevented by generalizing
|
||||
unique data where possible. In the example, this would mean reducing the
|
||||
accuracy of the timestamp so that multiple devices with the same model appear
|
||||
for every timestamp.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Other solutions include:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><em><strong>Not designing tables that explicitly link PII with Advertising
|
||||
IDs</strong></em>. In the first example above this would mean not including the
|
||||
account_id column in TABLE-01.</li>
|
||||
|
||||
<li><em><strong>Segregating and monitoring access control lists for users or roles
|
||||
that have access to both the Advertising ID keyed data and PII</strong></em>. If the
|
||||
ability to access both sources simultaneously (for example, to perform
|
||||
a join between two tables) is tightly controlled and audited, it reduces the
|
||||
risk of association between the Advertising ID and PII. Generally speaking,
|
||||
controlling access means:
|
||||
|
||||
<ol>
|
||||
<li> Keeping access control lists (ACLs) for Advertiser ID keyed data and PII disjoint to
|
||||
minimize the number of individuals or roles that are in both ACLs, and</li>
|
||||
<li> Implementing access logging and auditing to detect and manage any exceptions to
|
||||
this rule.</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
For more information on working responsibly with Advertising IDs, please see
|
||||
the <a href=
|
||||
"https://support.google.com/googleplay/android-developer/answer/6048248?hl=en">
|
||||
Advertising ID</a> help center article.
|
||||
</p>
|
||||
|
||||
<h2 id="working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</h2>
|
||||
|
||||
<p>
|
||||
The most straightforward solution to identifying an application instance
|
||||
running on a device is to use an Instance ID, and this is the recommended
|
||||
solution in the majority of non-ads use-cases. Only the app instance for
|
||||
which it was provisioned can access this identifier, and it's (relatively)
|
||||
easily resettable because it only persists as long as the app is installed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As a result, Instance IDs provide better privacy properties compared to
|
||||
non-resettable, device-scoped hardware IDs. They also come with a key-pair
|
||||
for message signing (and similar actions) and are available on Android, iOS
|
||||
and Chrome. Please see the <a href=
|
||||
"https://developers.google.com/instance-id/">What is Instance ID?</a> help
|
||||
center document for more information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In cases where an Instance ID isn't practical, custom globally unique IDs
|
||||
(GUIDs) can also be used to uniquely identify an app instance. The simplest
|
||||
way to do so is by generating your own GUID using the following code.
|
||||
</p>
|
||||
|
||||
<pre>String uniqueID = UUID.randomUUID().toString();</pre>
|
||||
|
||||
<p>
|
||||
Because the identifier is globally unique, it can be used to identify a
|
||||
specific app instance. To avoid concerns related to linking the identifier
|
||||
across applications, GUIDs should be stored in internal storage rather than
|
||||
external (shared) storage. Please see <a href=
|
||||
"{@docRoot}guide/topics/data/data-storage.html">Storage Options</a> guide for
|
||||
more information.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="understand_identifier_characteristics">Understanding Identifier Characteristics</h2>
|
||||
|
||||
<p>
|
||||
The Android Operating system offers a number of IDs with different behavior
|
||||
characteristics and which ID you should use depends on how those following
|
||||
characteristics work with your use-case. But these characteristics also come
|
||||
with privacy implications so it's important to understand how these
|
||||
characteristics play together.
|
||||
</p>
|
||||
|
||||
<h3 id="scope">Scope</h3>
|
||||
|
||||
<p>
|
||||
Identifier scope explains which systems can access the identifier. Android
|
||||
identifier scope generally comes in three flavors:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> <em>Single app</em>. the ID is internal to the app and not accessible to other apps.
|
||||
<li> <em>Group of apps</em> - the ID is accessible to a pre-defined group of related apps.
|
||||
<li> <em>Device</em> - the ID is accessible to all apps installed on the device.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The wider the scope granted to an identifier, the greater the risk of it
|
||||
being used for tracking purposes. Conversely, if an identifier can only be
|
||||
accessed by a single app instance, it can’t be used to track a device across
|
||||
transactions in different apps.
|
||||
</p>
|
||||
<h3 id="resettability_&_persistence">Resettability and persistence</h3>
|
||||
|
||||
<p>
|
||||
Resettability and persistence define the lifespan of the identifier and
|
||||
explain how it can be reset. Common reset triggers are: in-app resets, resets
|
||||
via System Settings, resets on launch, and resets on installation. Android
|
||||
Identifiers can have varying lifespans, but the lifespan is usually related
|
||||
to how the ID is reset:
|
||||
</p>
|
||||
<ul>
|
||||
<li> <em>Session-only</em> - a new ID is used every time the user restarts the app.
|
||||
<li> <em>Install-reset</em> - a new ID is used every time user uninstalls and reinstalls the app.
|
||||
<li> <em>FDR-reset</em> - a new ID is used every time the user factory-resets the device.
|
||||
<li> <em>FDR-persistent</em> - the ID survives factory reset.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Resettability gives users the ability to create a new ID that is
|
||||
disassociated from any existing profile information. This is important
|
||||
because the longer, and more reliably, an identifier persists (e.g. across
|
||||
factory resets etc.), the greater the risk that the user may be subjected to
|
||||
long-term tracking. If the identifier is reset upon app reinstall, this
|
||||
reduces the persistence and provides a means for the ID to be reset, even if
|
||||
there is no explicit user control to reset it from within the app or the
|
||||
System Settings.
|
||||
</p>
|
||||
<h3 id="uniqueness">Uniqueness</h3>
|
||||
|
||||
<p>
|
||||
Uniqueness establishes the likelihood that identical identifiers exist within
|
||||
the associated scope. At the highest level, a globally unique identifier will
|
||||
never have a collision - even on other devices/apps. Otherwise, the level of
|
||||
uniqueness depends on the size of the identifier and the source of randomness
|
||||
used to create it. For example, the chance of a collision is much higher for
|
||||
random identifiers seeded with the calendar date of installation (e.g.,
|
||||
2015-01-05) than for identifiers seeded with the Unix timestamp of
|
||||
installation (e.g., 1445530977).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In general, user account identifiers can be considered unique (i.e., each
|
||||
device/account combo has a unique ID). On the other hand, the less the unique
|
||||
an identifier is within a population (e.g. of devices), the greater the
|
||||
privacy protection because it's less useful for tracking an individual user.
|
||||
</p>
|
||||
|
||||
<h3 id="integrity_protection_and_non-repudiability">Integrity protection and
|
||||
non-repudiability</h3>
|
||||
|
||||
<p>
|
||||
An identifier that is difficult to spoof or replay can be used to prove that
|
||||
the associated device or account has certain properties (e.g. it’s not a
|
||||
virtual device used by a spammer). Difficult to spoof identifiers also
|
||||
provide <em>non-repudiability</em>. If the device signs a message with a
|
||||
secret key, it is difficult to claim someone else’s device sent the message.
|
||||
Non-repudiability could be something a user wants (e.g. authenticating a
|
||||
payment) or it could be an undesirable property (e.g. sending a message they
|
||||
regret).
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="use_appropriate_identifiers">Common Use Cases and the Identifier to Use</h2>
|
||||
|
||||
<p>
|
||||
This section provides alternatives to using hardware IDs such as IMEI or
|
||||
SSAID for the majority of use-cases. Relying on hardware IDs is discouraged
|
||||
because the user cannot reset them and generally has limited control over
|
||||
their collection.
|
||||
</p>
|
||||
|
||||
<h3 id="a_track_signed-out_user_preferences">Tracking signed-out user preferences</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you are saving per-device state on the server side.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: Instance ID or a GUID.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Persisting information through reinstalls is not recommended because users
|
||||
may want to reset their preferences by reinstalling the app.
|
||||
</p>
|
||||
|
||||
<h3 id="b_track_signed-out_user_behavior">Tracking signed-out user behavior</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you have created a profile of a user based on their
|
||||
behavior across different apps/sessions on the same device.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: Advertising ID.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Use of the Advertising ID is mandatory for Advertising use-cases per the
|
||||
<a href="https://play.google.com/about/developer-content-policy.html">Google
|
||||
Play Developer Content Policy</a> because the user can reset it.
|
||||
</p>
|
||||
|
||||
<h3 id="c_generate_signed-out_anonymous_user_analytics">Generating signed-out/anonymous user analytics</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you are measuring usage statistics and analytics for
|
||||
signed-out or anonymous users.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: Instance ID; if an Instance ID is
|
||||
insufficient, you can also use a GUID.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An Instance ID or a GUID is scoped to the app that creates it, which prevents
|
||||
it from being used to track users across apps. It is also easily reset by
|
||||
clearing app data or reinstalling the app. Creating Instance IDs and GUIDs is
|
||||
straightforward:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> Creating an Instance ID: <code>String iid = InstanceID.getInstance(context).getId()</code>
|
||||
<li> Creating a GUID: <code>String uniqueID = UUID.randomUUID().toString</code>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Be aware that if you have told the user that the data you are collecting is
|
||||
anonymous, you should <em><strong>ensure you are not connecting the
|
||||
identifier to PII</strong></em> or other identifiers that may be linked to
|
||||
PII.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can also use Google Analytics for Mobile Apps, which offers a solution
|
||||
for per-app analytics.
|
||||
</p>
|
||||
|
||||
<h3 id="d_track_signed-out_user_conversion">Tracking signed-out user conversion</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you are tracking conversions to detect if your marketing
|
||||
strategy was successful.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: Advertising ID.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This is an ads-related use-case which may require an ID that is available
|
||||
across different apps so using an Advertising ID is the most appropriate
|
||||
solution.
|
||||
</p>
|
||||
|
||||
<h3 id="e_handle_multiple_installations">Handling multiple installations</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you need to identify the correct instance of the app when
|
||||
it's installed on multiple devices for the same user.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: Instance ID or GUID.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Instance ID is designed explicitly for this purpose; its scope is limited to
|
||||
the app so that it cannot be used to track users across different apps and it
|
||||
is reset upon app reinstall. In the rare cases where an Instance ID is
|
||||
insufficient, you can also use a GUID.
|
||||
</p>
|
||||
|
||||
<h3 id="f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud: Enforcing free content limits / detecting Sybil attacks</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you want to limit the number of free content (e.g.
|
||||
articles) a user can see on a device.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: Instance ID or GUID.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Using a GUID or Instance ID forces the user to reinstall the app in order to
|
||||
overcome the content limits, which is a sufficient burden to deter most
|
||||
people. If this is not sufficient protection, Android provides a
|
||||
<a href="http://source.android.com/devices/drm.html">DRM API</a>
|
||||
which can be used to limit access to content.
|
||||
</p>
|
||||
|
||||
<h3 id="g_manage_telephony_&_carrier_functionality">Managing telephony and carrier functionality</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, your app is interacting with the device's phone and texting
|
||||
functionality.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: IMEI, IMSI, and Line1.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Leveraging hardware identifiers is acceptable if it is required for
|
||||
telephony/carrier related functionality; for example, switching between
|
||||
cellular carriers/SIM slots or delivering SMS messages over IP (for Line1) -
|
||||
SIM-based user accounts. But it's important to note that in Android 6.0+
|
||||
these identifiers can only be used via a runtime permission and that users
|
||||
may toggle off this permission so your app should handle these exceptions
|
||||
gracefully.
|
||||
</p>
|
||||
|
||||
<h3 id="h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection:
|
||||
Identifying bots and DDoS attacks</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you are trying to detect multiple fake devices attacking
|
||||
your backend services.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend:</strong> The Safetynet API.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An identifier in isolation does little to indicate that a device is genuine.
|
||||
You can verify that a request comes from a genuine Android device (as opposed
|
||||
to an emulator or other code spoofing another device) using the Safetynet
|
||||
API's <code>SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)</code>
|
||||
method to verify the integrity of a device making a request. For more
|
||||
detailed information, please see <a href=
|
||||
"{@docRoot}training/safetynet/index.html">Safetynet's API documentation</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection:
|
||||
Detecting high value stolen credentials</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you are trying to detect if a single device is being used
|
||||
multiple times with high-value, stolen credentials (e.g. to make fraudulent
|
||||
payments).</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>We Recommend</strong>: IMEI/IMSI (requires <code>PHONE</code>
|
||||
permission group in Android 6.0 (API level 23) and higher.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Why this Recommendation?</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
With stolen credentials, devices can be used to monetize multiple high value
|
||||
stolen credentials (such as tokenized credit cards). In these scenarios,
|
||||
software IDs can be reset to avoid detection, so hardware identifiers may be
|
||||
used.
|
||||
</p>
|
||||
266
docs/html/training/articles/user-data-overview.jd
Normal file
@@ -0,0 +1,266 @@
|
||||
page.title=Permissions and User Privacy
|
||||
page.metaDescription=An overview of permissions on Android and how to manage them.
|
||||
page.tags="user data","permissions","identifiers"
|
||||
page.image=images/cards/card-user_2x.png
|
||||
|
||||
page.article=true
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>In this document</h2>
|
||||
<ol>
|
||||
<li><a href="#introduction">Introduction</a></li>
|
||||
<li><a href="#permission_groups">Permission Groups</a></li>
|
||||
<li><a href="#permission_requests_and_app_downloads">Permission
|
||||
Requests and App Downloads</a></li>
|
||||
<li><a href="#permission_requests_trend_downward">Permission Requests
|
||||
Trend Downward</a></li>
|
||||
</ol>
|
||||
<h2>You should also read</h2>
|
||||
<ol>
|
||||
<li><a href="{@docRoot}guide/topics/security/permissions.html">System Permissions</a></li>
|
||||
<li><a href="{@docRoot}training/permissions/index.html">Working with System
|
||||
Permissions</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Permissions protect sensitive information available from a device and should
|
||||
only be used when access to information is necessary for the functioning of
|
||||
your app.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This document provides a high-level overview on how permissions work in
|
||||
Android so you can make better, more informed decisions about the permissions
|
||||
you're requesting. The information in this document is not use-case specific
|
||||
and avoids complex, low-level discussions of the underlying code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For specific recommendations on how to manage permissions, please see
|
||||
<a href="{@docRoot}training/articles/user-data-permissions.html">Best
|
||||
Practices for App Permissions</a>. For best practices on using unique
|
||||
identifiers on Android, please see <a href=
|
||||
"{@docRoot}training/articles/user-data-ids.html">Best Practices for Unique
|
||||
Identifiers</a>. For details on how to work with permissions in your code,
|
||||
see <a href="{@docRoot}training/permissions/index.html">Working with System
|
||||
Permissions</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
Every Android application must have a <em>manifest file</em> that presents
|
||||
essential information about the app to the Android system. The Android system
|
||||
also requires apps to request permission when they want to access sensitive
|
||||
device or user information, and these requests must be documented in advance
|
||||
as a part of your app's manifest. Moreover, accessing sensitive information
|
||||
can affect user behavior, so it's important to make sure you are only making
|
||||
permission requests when that information is necessary for the functioning of
|
||||
your app.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="permission_groups">Permission Groups</h2>
|
||||
|
||||
<p>
|
||||
Permissions in Android are organized into <code><a href=
|
||||
"{@docRoot}guide/topics/security/permissions.html#perm-groups">permission
|
||||
groups</a></code> that organize, and group, permissions related to a device's
|
||||
capabilities or features. Under this system, permission requests are handled
|
||||
at the group level and a <em><strong>single permission group</strong></em>
|
||||
corresponds to <em><strong>several permission declarations</strong></em> in
|
||||
the app manifest; for example, the SMS group includes both the
|
||||
<code>READ_SMS</code> and the <code>WRITE_SMS</code> declarations.
|
||||
</p>
|
||||
|
||||
|
||||
<div class="wrap">
|
||||
<img src="{@docRoot}images/training/articles/user-data-overview-permissions-flow01.jpg">
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This arrangement is simpler and more informative for users; once an app is
|
||||
granted permission to access the group, it can use API calls within that
|
||||
group and users with auto-update enabled will not be asked for additional
|
||||
permissions because they have already granted access to the group. Grouping
|
||||
permissions in this way enables the user to make more meaningful and informed
|
||||
choices, without being overwhelmed by complex and technical permission
|
||||
requests.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This also means that when you request access to a particular API call or
|
||||
query a content provider behind a permission, the user will be presented with
|
||||
a request to grant permission for the whole group rather than the specific
|
||||
API call. For example, if you request the <code>MANAGE_ACOUNTS</code>
|
||||
permission, the user will be asked to grant access to the <em>Identity</em>
|
||||
group which is composed of the <code>GET_ACCOUNTS</code>,
|
||||
<code>READ_PROFILE</code>, and <code>WRITE_PROFILE</code> permissions, and
|
||||
all their associated methods.
|
||||
</p>
|
||||
|
||||
<div class="wrap">
|
||||
<img src="{@docRoot}images/training/articles/user-data-overview-permissions-flow02.jpg">
|
||||
</div>
|
||||
|
||||
<p>
|
||||
One consequence of grouping permissions is that a single API call within your
|
||||
app can have a multiplying effect in terms of the number of permissions
|
||||
requested by your app.
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>API Call →</li>
|
||||
<li stydle="margin-left:.5em;">Triggers a specific <em>Permission Group</em> access
|
||||
request →</li>
|
||||
<li stydle="margin-left:1em;">Successful request grants access to all permissions in
|
||||
group (if auto-update
|
||||
enabled) →</li>
|
||||
<li stydle="margin-left:1.5em;">Each permission grants access to all APIs under that
|
||||
permission</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
As another example, let's assume your application uses one or more <a href=
|
||||
"{@docRoot}reference/android/telephony/TelephonyManager.html"><code>TelephonyManager</code></a>
|
||||
methods, such as:
|
||||
</p>
|
||||
|
||||
<pre class="prettyprint">
|
||||
TelephonyManager.getDeviceId()
|
||||
TelephonyManager.getSubscriberId()
|
||||
TelephonyManager.getSimSerialNumber()
|
||||
TelephonyManager.getLine1Number()
|
||||
TelephonyManager.getVoiceMailNumber()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To use these methods, the <code>READ_PHONE_STATE</code> permission must be
|
||||
declared in the app's manifest, and the associated permission group,
|
||||
<em>Device ID and Call information</em>, will be surfaced to the user. This
|
||||
is important, because it means the user will be asked to grant permission for
|
||||
the relevant group and all its associated permissions and API calls, rather
|
||||
than for the specific API call you're requesting.
|
||||
</p>
|
||||
|
||||
<p>For a full mapping between permissions and their associated permission groups,
|
||||
please refer to the appropriate version-specific documentation below:</p>
|
||||
|
||||
<ul>
|
||||
<!--<li> <a href="">pre-M Android OS versions</a>.</li> -->
|
||||
<li> <a href="{@docRoot}guide/topics/security/permissions.html#perm-groups">Permission
|
||||
groups, Android 6.0 Marshmallow (API level 23) and later</a>.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="permission_requests_and_app_downloads">Permission Requests and App Downloads</h2>
|
||||
|
||||
<div style="padding:.5em 2em;">
|
||||
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
|
||||
<p><em>I'm currently using the READ_PHONE_STATE permission in Android to pause my
|
||||
media player when there's a call, and to resume playback when the call is over.
|
||||
The permission seems to scare a lot of people</em>...<span
|
||||
style="font-size:.8em;color:#777"><sup><em><a
|
||||
href="#references" style="color:#777;padding-left:.1em;">1</a></em></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Research shows that among apps that are otherwise identical (e.g.,
|
||||
functionality, brand recognition), requesting fewer permissions leads to more
|
||||
downloads. Publicly available sources exist that assign grades to apps based
|
||||
on their permissions usage and allow users to compare related apps by score;
|
||||
such grades exist for many of the current Android apps and users pay close
|
||||
attention to the related rankings.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One study<span style="font-size:.8em;color:#777"><sup><em><a href=
|
||||
"#references" style=
|
||||
"color:#777;padding-left:.1em;">2</a></em></sup></span><sup>, in which users
|
||||
were shown two unbranded apps with similar ratings that had the same
|
||||
functionality but different sets of permission requests, showed that users
|
||||
were, on average, 3 times more likely to install the app with fewer
|
||||
permissions requests. And a similar study<span style=
|
||||
"font-size:.8em;color:#777"><sup><em><a href="#references" style=
|
||||
"color:#777;padding-left:.1em;">3</a></em></sup> showed that users are 1.7
|
||||
times more likely, on average, to select the application with fewer
|
||||
permission requests.</span></sup>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<sup>Finally, permissions usage is not evenly distributed across apps within
|
||||
a similar category of Play apps. For example, 39.3% of arcade game apps in
|
||||
the Play store request no permissions that are surfaced to the user while
|
||||
only 1.5% of arcade games request the Phone permission group (see Figure
|
||||
1).</sup>
|
||||
</p>
|
||||
|
||||
<div class="wrap">
|
||||
<div class="cols">
|
||||
<div class="col-16of16">
|
||||
<img src="{@docRoot}images/training/articles/user-data-overview-permissions-groups.png">
|
||||
<p class="figure-caption"><strong>Figure 1.</strong> Distribution of
|
||||
permission groups use across Arcade Games category.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Users comparing your app to other similar apps may determine that it is
|
||||
making unusual permission requests for that category - in this case, Arcade
|
||||
Games apps accessing the <em>Phone</em> permission group. As a result, they
|
||||
may install a similar app in that category that avoids those
|
||||
requests.<span style="font-size:.8em;color:#777"><sup><em><a href=
|
||||
"#references" style="color:#777;padding-left:.1em;">4</a></em></sup></span>
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="permission_requests_trend_downward">Permission Requests Trend Downward</h2>
|
||||
|
||||
<p>
|
||||
A recent analysis of Play store apps over time indicated that many developers
|
||||
trim permissions after first publishing their apps, suggesting that they may
|
||||
be employing more caution around which permission groups they declare.
|
||||
</p>
|
||||
|
||||
<div class="wrap">
|
||||
<div class="cols">
|
||||
<div class="col-16of16">
|
||||
<img src="{@docRoot}images/training/articles/user-data-overview-permissions-usage.jpg">
|
||||
<p class="figure-caption"><strong>Figure 2.</strong> Developer usage of popular
|
||||
permissions has decreased over time.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The graph in <em>Figure 2</em> illustrates this trend. There has been a
|
||||
steady decrease in the average percentage of developers' apps requesting at
|
||||
least one of the three most popular permissions in the Play store
|
||||
(<code>READ_PHONE_STATE</code>, <code>ACCESS_FINE_LOCATION</code>, and
|
||||
<code>ACCESS_COARSE_LOCATION</code>). These results indicate that developers
|
||||
are reducing the permissions their apps request in response to user behavior.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The bottom line is that providing the same functionality to the user with
|
||||
minimal access to sensitive information means more downloads for your app.
|
||||
For specific recommendations on how to achieve this, please see <a href=
|
||||
"{@docRoot}training/articles/user-data-permissions.html">Best Practices for
|
||||
Application Permissions</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="references">References</h2>
|
||||
|
||||
<p>[1] Developer quote on StackOverflow. <em>(<a
|
||||
href="http://stackoverflow.com/questions/24374701/alternative-to-read-phone-state-permission-for-getting-notified-of-call">source</a>)</em></p>
|
||||
<p>[2] <em>Using Personal Examples to Improve Risk Communication for Security and Privacy Decisions</em>, by M. Harbach, M. Hettig, S. Weber, and M. Smith. In Proceedings of ACM CHI 2014.</p>
|
||||
<p>[3] <em>Modeling Users’ Mobile App Privacy Preferences: Restoring Usability in a Sea of Permission Settings</em>, by J. Lin B. Liu, N. Sadeh and J. Hong. In Proceedings of SOUPS 2014.</p>
|
||||
<p>[4] <em>Teens and Mobile Apps Privacy. (<a href="http://www.pewinternet.org/files/old-media/Files/Reports/2013/PIP_Teens%20and%20Mobile%20Apps%20Privacy.pdf">source</a>)</em></p>
|
||||
381
docs/html/training/articles/user-data-permissions.jd
Normal file
@@ -0,0 +1,381 @@
|
||||
page.title=Best Practices for App Permissions
|
||||
page.metaDescription=How to manage permissions to give users context and control.
|
||||
page.tags=permissions, user data
|
||||
meta.tags="permissions", "user data"
|
||||
page.image=images/cards/card-user-permissions_2x.png
|
||||
|
||||
page.article=true
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>In this document</h2>
|
||||
<ol>
|
||||
<li><a href="#tenets_of_working_with_android_permissions">Tenets</a></li>
|
||||
<li><a href="#version_specific_details_permissions_in_m">Permissions in Android
|
||||
6.0+</h2></a></li>
|
||||
<li><a href="#avoid_requesting_unnecessary_permissions">Avoid Requesting
|
||||
Unnecessary Permissions</h2></a>
|
||||
<ol>
|
||||
<li><a href="#a_camera_contact_access_with_real-time_user_requests">Camera/Contact
|
||||
access with realtime user requests</a></li>
|
||||
<li><a href="#b_running_in_the_background_after_losing_audio_focus">Running in
|
||||
the background after losing audio focus</a></li>
|
||||
<li><a href="#c_determine_the_device_your_instance_is_running_on">Determine the
|
||||
device your instance is running on</a></li>
|
||||
<li><a href="#d_create_a_unique_identifier_for_advertising_or_user_analytics">
|
||||
Create a unique identifier for advertising or user analytics</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#know_the_libraries_you're_working_with">Know the Libraries You're
|
||||
Working With</a></li>
|
||||
<li><a href="#be_transparent">Be Transparent</a></li>
|
||||
</ol>
|
||||
<h2>You should also read</h2>
|
||||
<ol>
|
||||
<li><a href="{@docRoot}guide/topics/security/permissions.html">System Permissions</a></li>
|
||||
<li><a href="{@docRoot}training/permissions/index.html">Working with System
|
||||
Permissions</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Permission requests protect sensitive information available from a device and
|
||||
should only be used when access to information is necessary for the
|
||||
functioning of your app. This document provides tips on ways you might be
|
||||
able to achieve the same (or better) functionality without requiring access
|
||||
to such information; it is not an exhaustive discussion of how permissions
|
||||
work in the Android operating system.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For a more general look at Android permissions, please see <a href=
|
||||
"{@docRoot}training/articles/user-data-overview.html">Permissions
|
||||
and User Privacy</a>. For details on how to work with permissions in your code,
|
||||
see <a href="{@docRoot}training/permissions/index.html">Working with System Permissions</a>.
|
||||
For best practices for working with unique identifiers, please see <a href=
|
||||
"{@docRoot}training/articles/user-data-ids.html">Best Practices for
|
||||
Unique Identifiers</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="tenets_of_working_with_android_permissions">Tenets of Working
|
||||
with Android Permissions</h2>
|
||||
|
||||
<p>
|
||||
We recommend following these tenets when working with Android permissions:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#1: Only use the permissions necessary for your app to
|
||||
work</strong></em>. Depending on how you are using the permissions, there may
|
||||
be another way to do what you need (system intents, identifiers,
|
||||
backgrounding for phone calls) without relying on access to sensitive
|
||||
information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#2: Pay attention to permissions required by
|
||||
libraries.</strong></em> When you include a library, you also inherit its
|
||||
permission requirements. You should be aware of what you're including, the
|
||||
permissions they require, and what those permissions are used for.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#3: Be transparent.</strong></em> When you make a permissions
|
||||
request, be clear about what you’re accessing, and why, so users can make
|
||||
informed decisions. Make this information available alongside the permission
|
||||
request including install, runtime, or update permission dialogues.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>#4: Make system accesses explicit.</strong></em> Providing
|
||||
continuous indications when you access sensitive capabilities (for example, the
|
||||
camera or microphone) makes it clear to users when you’re collecting data and
|
||||
avoids the perception that you're collecting data surreptitiously.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The remaining sections of this guide elaborate on these rules in the context
|
||||
of developing Android applications.
|
||||
</p>
|
||||
|
||||
<h2 id="version_specific_details_permissions_in_m">Permissions in Android 6.0+</h2>
|
||||
|
||||
<p>
|
||||
Android 6.0 Marshmallow introduced a <a href=
|
||||
"{@docRoot}training/permissions/requesting.html">new permissions model</a> that
|
||||
lets apps request permissions from the user at runtime, rather than prior to
|
||||
installation. Apps that support the new model request permissions when the app
|
||||
actually requires the services or data protected by the services. While this
|
||||
doesn't (necessarily) change overall app behavior, it does create a few
|
||||
changes relevant to the way sensitive user data is handled:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>Increased situational context</strong></em>: Users are be
|
||||
prompted at runtime, in the context of your app, for permission to access the
|
||||
functionality covered by those permission groups. Users are be more sensitive to
|
||||
the context in which the permission is requested, and if there’s a mismatch
|
||||
between what you are requesting and the purpose of your app, it's even
|
||||
more important to provide detailed explanation to the user as to why you’re
|
||||
requesting the permission; whenever possible, you should provide an
|
||||
explanation of your request both at the time of the request and in a
|
||||
follow-up dialog if the user denies the request.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>Greater flexibility in granting permissions</strong></em>: Users
|
||||
can deny access to individual permissions at the time they’re requested
|
||||
<em>and</em> in settings, but they may still be surprised when functionality is
|
||||
broken as a result. It’s a good idea to monitor how many users are denying
|
||||
permissions (e.g. using Google Analytics) so that you can either refactor
|
||||
your app to avoid depending on that permission or provide a better
|
||||
explanation of why you need the permission for your app to work properly. You
|
||||
should also make sure that your app handles exceptions created when users
|
||||
deny permission requests or toggle off permissions in settings.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em><strong>Increased transactional burden</strong></em>: Users will be asked
|
||||
to grant access for permission groups individually and not as a set. This
|
||||
makes it extremely important to minimize the number of permissions you’re
|
||||
requesting because it increases the user burden for granting permissions and
|
||||
increases the probability that at least one of the requests will be denied.
|
||||
</p>
|
||||
|
||||
<h2 id="avoid_requesting_unnecessary_permissions">Avoid Requesting
|
||||
Unnecessary Permissions</h2>
|
||||
|
||||
<p>
|
||||
This section provides alternatives to common use-cases that will help you
|
||||
limit the number of permission requests you make. Since the number and type
|
||||
of user-surfaced permissions requested affects downloads compared to other
|
||||
similar apps requesting fewer permissions, it’s best to avoid requesting
|
||||
permissions for unnecessary functionality.
|
||||
</p>
|
||||
|
||||
<h3 id="a_camera_contact_access_with_real-time_user_requests">Camera/contact
|
||||
access with realtime user requests</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you need occasional access to the device's camera or
|
||||
contact information and don’t mind the user being asked every time you need
|
||||
access.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If your requirement for access to user data is infrequent — in other
|
||||
words, it's not unacceptably disruptive for the user to be presented with a
|
||||
runtime dialogue each time you need to access data — you can use an
|
||||
<em>intent based request</em>. Android provides system intents that
|
||||
applications can use without requiring permissions because the user chooses
|
||||
what, if anything, to share with the app at the time the intent based request
|
||||
is issued.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, an intent action type of <code><a href=
|
||||
"{@docRoot}reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE">MediaStore.ACTION_IMAGE_CAPTURE</a></code>
|
||||
or <code><a href=
|
||||
"{@docRoot}reference/android/provider/MediaStore.html#ACTION_VIDEO_CAPTURE">MediaStore.ACTION_VIDEO_CAPTURE</a></code>
|
||||
can be used to capture images or videos without directly using the <a href=
|
||||
"{@docRoot}reference/android/hardware/Camera.html">Camera</a> object (or
|
||||
requiring the permission). In this case, the system intent will ask for the
|
||||
user’s permission on your behalf every time an image is captured.
|
||||
</p>
|
||||
|
||||
<h3 id="b_running_in_the_background_after_losing_audio_focus">Running in
|
||||
the background after losing audio focus</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, your application needs to go into the background when the
|
||||
user gets a phone call and refocus only once the call stops.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The common approach in these cases - for example, a media player muting or
|
||||
pausing during a phone call - is to listen for changes in the call state
|
||||
using <code>PhoneStateListener</code> or listening for the broadcast of
|
||||
<code>android.intent.action.PHONE_STATE</code>. The problem with this
|
||||
solution is that it requires the <code>READ_PHONE_STATE</code> permission,
|
||||
which forces the user to grant access to a wide cross section of sensitive
|
||||
data such as their device and SIM hardware IDs and the phone number of the
|
||||
incoming call.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can avoid this by requesting <code>AudioFocus</code> for your app, which
|
||||
doesn't require explicit permissions (because it does not access sensitive
|
||||
information). Simply put the code required to background your audio in the
|
||||
<code><a href=
|
||||
"{@docRoot}reference/android/media/AudioManager.OnAudioFocusChangeListener.html#onAudioFocusChange(int)">
|
||||
onAudioFocusChange()</a></code> event handler and it will run automatically
|
||||
when the OS shifts its audio focus. More detailed documentation on how to do
|
||||
this can be found <a href=
|
||||
"{@docRoot}training/managing-audio/audio-focus.html">here</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="c_determine_the_device_your_instance_is_running_on">Determine the
|
||||
device your instance is running on</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you need a unique identifier to determine which device the
|
||||
instance of your app is running on.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Applications may have device-specific preferences or messaging (e.g., saving
|
||||
a device-specific playlist for a user in the cloud so that they can have a
|
||||
different playlist for their car and at home). A common solution is to
|
||||
leverage device identifiers such as <code>Device IMEI</code>, but this
|
||||
requires the <code>Device ID and call information</code>
|
||||
permission group (<code>PHONE</code> in M+). It also uses an identifier which
|
||||
cannot be reset and is shared across all apps.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are two alternatives to using these types of identifiers:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li> Use the <code>com.google.android.gms.iid</code> InstanceID API.
|
||||
<code>getInstance(Context context).getID()<strong></code> </strong>will return a
|
||||
unique device identifier for your application instance. The
|
||||
result is an app instance scoped identifier that can be used as a key when
|
||||
storing information about the app and is reset if the user re-installs the app.
|
||||
<li> Create your own identifier that’s scoped to your app’s storage using basic
|
||||
system functions like <a
|
||||
href="{@docRoot}reference/java/util/UUID.html#randomUUID()"><code>randomUUID()</code></a>.</li>
|
||||
</ol>
|
||||
|
||||
<h3 id="d_create_a_unique_identifier_for_advertising_or_user_analytics">Create a unique
|
||||
identifier for advertising or user analytics</h3>
|
||||
|
||||
<p>
|
||||
<em>In this case, you need a unique identifier for building a profile for
|
||||
users who are not signed in to your app (e.g., for ads targeting or measuring
|
||||
conversions).</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Building a profile for advertising and user analytics sometimes requires an
|
||||
identifier that is shared across other applications. Common solutions for
|
||||
this involve leveraging device identifiers such as <code>Device IMEI</code>,
|
||||
which requires the <code>Device ID</code> <code>and call information</code>
|
||||
permission group (<code>PHONE</code> in API level 23+) and cannot be reset by
|
||||
the user. In any of these cases, in addition to using a non-resettable
|
||||
identifier and requesting a permission that might seem unusual to users, you
|
||||
will also be in violation of the <a href=
|
||||
"https://play.google.com/about/developer-content-policy.html">Play Developer
|
||||
Program Policies</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Unfortunately, in these cases using the
|
||||
<code>com.google.android.gms.iid</code> InstanceID API or system functions to
|
||||
create an app-scoped ID are not appropriate solutions because the ID may need
|
||||
to be shared across apps. An alternative solution is to use the
|
||||
<code>Advertising Identifier</code> available from the <code><a href=
|
||||
"{@docRoot}reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html">
|
||||
AdvertisingIdClient.Info</a></code> class via the <code>getId()</code>
|
||||
method. You can create an <code>AdvertisingIdClient.Info</code> object using
|
||||
the <code>getAdvertisingIdInfo(Context)</code> method and call the
|
||||
<code>getId()</code> method to use the identifier. <em><strong>Note that this
|
||||
method is blocking</strong></em>, so you should not call it from the main
|
||||
thread; a detailed explanation of this method is available <a href=
|
||||
"{@docRoot}google/play-services/id.html">here</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="know_the_libraries_you're_working_with">Know the Libraries You're
|
||||
Working With</h2>
|
||||
|
||||
<p>
|
||||
Sometimes permissions are required by the libraries you use in your app. For
|
||||
example, ads and analytics libraries may require access to the
|
||||
<code>Location</code> or <code>Identity</code> permissions groups to
|
||||
implement the required functionality. But from the user’s point of view, the
|
||||
permission request comes from your app, not the library.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Just as users select apps that use fewer permissions for the same
|
||||
functionality, developers should review their libraries and select
|
||||
third-party SDKs that are not using unnecessary permissions. For example, try
|
||||
to avoid libraries that require the <code>Identity</code> permission group
|
||||
unless there is a clear user-facing reason why the app needs those permissions.
|
||||
In particular, for libraries that provide location functionality, make sure you
|
||||
are not required to request the <code>FINE_LOCATION</code> permission unless
|
||||
you are using location-based targeting functionality.
|
||||
</p>
|
||||
|
||||
<h2 id="be_transparent">Be Transparent</h2>
|
||||
|
||||
<p>You should inform your users about what you’re accessing and why. Research shows
|
||||
that users are much less uncomfortable with permissions requests if they know
|
||||
why the app needs them. A user study showed that:</p>
|
||||
|
||||
<div style="padding:.5em 2em;">
|
||||
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
|
||||
<p>...a user’s willingness to grant a given permission to a given mobile app is
|
||||
strongly influenced by the purpose associated with such a permission. For
|
||||
instance a user’s willingness to grant access to his or her location will vary
|
||||
based on whether the request is required to support the app’s core
|
||||
functionality or whether it is to share this information with an advertising
|
||||
network or an analytics company.<span
|
||||
style="font-size:.8em;color:#777"><sup><em><a
|
||||
href="#references" style="color:#777;padding-left:.1em;">1</a></em></sup></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Based on his group’s research, Professor Jason Hong from CMU concluded that,
|
||||
in general:
|
||||
</p>
|
||||
|
||||
<div style="padding:.5em 2em;">
|
||||
<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
|
||||
<p>...when people know why an app is using something as sensitive as their location —
|
||||
for example, for targeted advertising — it makes them more comfortable than
|
||||
when simply told an app is using their location.<span
|
||||
style="font-size:.8em;color:#777"><sup><em><a
|
||||
href="#references" style="color:#777;padding-left:.1em;">1</a></em></sup></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
As a result, if you’re only using a fraction of the API calls that fall under
|
||||
a permission group, it helps to explicitly list which of those permissions
|
||||
you're using, and why. For example:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> If you’re only using coarse location, let the user know this in your app
|
||||
description or in help articles about your app. </li>
|
||||
<li> If you need access to SMS messages to receive authentication codes that
|
||||
protect the user from fraud, let the user know this in your app description
|
||||
and/or the first time you access the data.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Under certain conditions, it's also advantageous to let users know about
|
||||
sensitive data accesses in real-time. For example, if you’re accessing the
|
||||
camera or microphone, it’s usually a good idea to let the user know with a
|
||||
notification icon somewhere in your app, or in the notification tray (if the
|
||||
application is running in the background), so it doesn't seem like you're
|
||||
collecting data surreptitiously.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Ultimately, if you need to request a permission to make something in your app
|
||||
work, but the reason is not clear to the user, find a way to let the user
|
||||
know why you need the most sensitive permissions.
|
||||
</p>
|
||||
|
||||
<h2 id="references">References</h2>
|
||||
|
||||
<p>
|
||||
[1] <em>Modeling Users’ Mobile App Privacy Preferences: Restoring Usability
|
||||
in a Sea of Permission Settings</em>, by J. Lin B. Liu, N. Sadeh and J. Hong.
|
||||
In Proceedings of SOUPS 2014.
|
||||
</p>
|
||||
9
docs/html/training/best-permissions-ids.jd
Normal file
@@ -0,0 +1,9 @@
|
||||
page.title=Best Practices for Permissions and Identifiers
|
||||
page.trainingcourse=true
|
||||
|
||||
@jd:body
|
||||
|
||||
|
||||
|
||||
<p>The articles below highlight key guidelines for using permissions
|
||||
and identifiers properly in your apps.</p>
|
||||
@@ -2083,6 +2083,36 @@ results."
|
||||
</li>
|
||||
<!-- End security and user info -->
|
||||
|
||||
<li class="nav-section">
|
||||
<div class="nav-section-header">
|
||||
<a href="<?cs var:toroot ?>training/best-permissions-ids.html">
|
||||
<span class="small">Best Practices for</span><br/>
|
||||
Permissions & Identifiers
|
||||
</a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>training/articles/user-data-overview.html"
|
||||
description=
|
||||
"Overview of app permissions on Android and how they affect your users."
|
||||
>Permissions and User Privacy</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>training/articles/user-data-permissions.html"
|
||||
description=
|
||||
"How to manage permissions the right way for users."
|
||||
>Best Practices for App Permissions</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>training/articles/user-data-ids.html"
|
||||
description=
|
||||
"Unique identifiers available and how to choose the right one for your use case."
|
||||
>Best Practices for Unique Identifiers</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- End Permissions and identifiers -->
|
||||
|
||||
<li class="nav-section">
|
||||
<div class="nav-section-header">
|
||||
<a href="<?cs var:toroot ?>training/testing.html">
|
||||
|
||||