Home | History | Annotate | Download | only in admin
      1 <html devsite>
      2   <head>
      3     <title>Building Multiuser-Aware Apps</title>
      4     <meta name="project_path" value="/_project.yaml" />
      5     <meta name="book_path" value="/_book.yaml" />
      6   </head>
      7   <body>
      8   <!--
      9       Copyright 2017 The Android Open Source Project
     10 
     11       Licensed under the Apache License, Version 2.0 (the "License");
     12       you may not use this file except in compliance with the License.
     13       You may obtain a copy of the License at
     14 
     15           http://www.apache.org/licenses/LICENSE-2.0
     16 
     17       Unless required by applicable law or agreed to in writing, software
     18       distributed under the License is distributed on an "AS IS" BASIS,
     19       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     20       See the License for the specific language governing permissions and
     21       limitations under the License.
     22   -->
     23 
     24 
     25 
     26 <p>When a device supports <a href="multi-user.html">multiple users</a>, its apps must be made aware of these distinct users.</p>
     27 
     28 <p>Certain apps need to have some components run as singletons and can accept
     29 requests from any user. Only system apps can currently use this feature.</p>
     30 
     31 <p>This facility:</p>
     32 
     33 <ul>
     34   <li>Conserves resources
     35   <li>Arbitrates one or more shared resources across users
     36   <li>Reduces network overhead by using a single server connection
     37 </ul>
     38 
     39 <p>See the diagram below for a depiction of permissions flow with multiple users.</p>
     40 
     41 <p><img src="/devices/tech/admin/images/multi-user-perms.png" alt="Multiple users permissions flow" />
     42 <p class="img-caption"><strong>Figure 1.</strong> Multiple users permissions</p>
     43 
     44 <h2 id=enabling_a_singleton_component>Enabling a singleton component</h2>
     45 
     46 <p>To identify an app as a singleton, Add <code>android:singleUser=true</code> to your service or provider in the Android manifest.</p>
     47 
     48 <p>The system will instantiate that component in the process running as user 0
     49 only. Any requests to connect to that provider or service from any user will be
     50 routed to the process in user 0. If this is the only component in your app,
     51 only one instance of your app will run.</p>
     52 
     53 <p>Activities in your package will still be launched in a separate process for
     54 each user, with the UID being in the UID range for that user (such as 1010034).</p>
     55 
     56 <h2 id=interacting_with_users>Interacting with users</h2>
     57 
     58 <h3 id=perms_required>Set permissions</h3>
     59 
     60 <p>These permissions are required</p>
     61 
     62 <pre class="devsite-click-to-copy">
     63 INTERACT_ACROSS_USERS (signature|system)
     64 INTERACT_ACROSS_USERS_FULL (signature)
     65 </pre>
     66 
     67 <h3 id=apis>Employ APIs</h3>
     68 
     69 <p>Use the following APIs to make apps aware of multiple users.</p>
     70 
     71 <ol>
     72   <li> Extract the user handle from incoming Binder calls:
     73   <ul>
     74     <li> <code>int userHandle = UserHandle.getCallingUserId()</code>
     75   </ul>
     76   <li> Use new, protected APIs to start services, activities, broadcasts on a specific
     77 user:
     78   <ul>
     79     <li><code>Context.startActivityAsUser(Intent, UserHandle)</code>
     80     <li><code>Context.bindServiceAsUser(Intent, , UserHandle)</code>
     81     <li><code>Context.sendBroadcastAsUser(Intent,  , UserHandle)</code>
     82     <li><code>Context.startServiceAsUser(Intent, , UserHandle)
     83 UserHandle</code> can be an explicit user or one of the special handles: <code>UserHandle.CURRENT</code> or <code>UserHandle.ALL</code>. <code>CURRENT</code> indicates the user that is currently in the foreground. You can use <code>ALL</code> when you want to send a broadcast to all users.
     84   </ul>
     85   <li>Communicate with components in your own app:
     86 <code>(INTERACT_ACROSS_USERS)</code>
     87 Or with components in other apps:
     88 <code>(INTERACT_ACROSS_USERS_FULL)</code>
     89   <li>You may need to create proxy components that run in the users process that
     90 then access the <code>singleUser</code> component in user 0.
     91   <li>Query users and their handles with the new <code>UserManager</code> system service:
     92   <ul>
     93     <li><code>UserManager.getUsers()</code>
     94     <li><code>UserManager.getUserInfo()</code>
     95     <li><code>UserManager.supportsMultipleUsers()</code>
     96     <li><code>UserManager.getUserSerialNumber(int userHandle)</code> - a non-recycled number that corresponds to a user handle.
     97     <li><code>UserManager.getUserHandle(int serialNumber)</code>
     98     <li><code>UserManager.getUserProfiles() </code>- returns the collection of self and managed profiles, if any.
     99   </ul>
    100   <li>Register to listen to specific or all users and the callbacks with new APIs on
    101 ContentObserver, PackageMonitor, BroadcastReceiver that provide additional
    102 information about which user has caused the callback.
    103 </ol>
    104 
    105 <h3 id="work-profiles">Services in multiple users or profiles</h3>
    106 
    107 <p>Not all services need to run an instance in another user or work profile. If your system service
    108 only needs to run as user 0, disable the service's components when running under other users to
    109 help preserve resources. The following example shows how you might do this at your service's entry
    110 points:</p>
    111 
    112 <pre class="devsite-click-to-copy">
    113 // Add on all entry points such as boot_completed or other manifest-listed receivers and providers
    114 if (!UserManager.isSystemUser()) {
    115     // Disable the service
    116     ComponentName targetServiceName = new ComponentName(this, TargetService.class);
    117     context.getPackageManager().setComponentEnabledSetting(
    118         targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0);
    119 }
    120 </pre>
    121 
    122 <p>The example could also use <code>PackageManager.setApplicationEnabledSetting()</code> to disable
    123 the entire app.</p>
    124 
    125 
    126 
    127 
    128   </body>
    129 </html>
    130