Pages

Tuesday, April 7, 2015

Check if current user is owner

One would think that this is a simple task in Android, especially since one would expect Google to have added some kind of tool for it, like something to return the current user id. Well they have, but they also decided to hide it. Android actually has a very pore collection of tools when it comes to working with multi-users. Like many things in the framework, Google did not think that apps had any reason to access to any information regarding the users. Android's sources might be fully open, but the framework is more closed than boot loaders on HTC devices.

The user id is normally not a very important information since it is nothing more than a number from 10 and up, except for the owner which have 00. The only thing that this number can tell you, is which user was created first. But checking for the 00 id to identify the owner can be very helpful. You may be working on an app that should have certain restrictions when not used by the device owner. Maybe your app should not be used by other users at all. In any case identifying the owner is useful enough that Google should have added something like isOwner() to the UserManager service.

Searching the web, it seams like people are using a lot of reflection to access some of the hidden classes in order to identify the device owner. However reflection is not really needed, and it should be avoided if possible, simply because hidden classes are not official and might change over time. If this happens, apps need to be updated or they will be broken on future versions of Android.

Even though Android did not directly provide any access to the current user id, they did indirectly do this in one way, namely the app data folder. In Android 4.1 and below, all app data was placed in /data/data, but in newer versions they are placed in /data/user/[userid] and all apps have access to their own data folder. So to get the current user id from within an app, you only need to get the name of the parent folder to your apps data location. This is very simple.

MainActivity.java:
public class Utils {
 public static boolean isOwner(Context context) {
  /* 
   * Get the parent location. 
   * This can either be /data/user/[userid] or /data/data depending on Android version.
   */
  File file = new File(context.getApplicationInfo().dataDir).getParentFile();
  
  /*
   * Get the name of the folder in the parent location. 
   * This can either be [userid] or data
   */
  String user = file.getName();
  
  try {
   /*
    * Returns TRUE if this user has the id 0 (device owner)
    */
   return Integer.valueOf(user) == 0;
   
  } catch (NumberFormatException e) {
   /*
    * The user variable contained "data". 
    * This is not an multi-user environment, which means that we only have the device owner available.
    */
   return true;
  }
 }
}

The above code is even backward compatible with Android version without multi-user support, without any need to check the current API level. And we did not use any reflection or unsupported classes/methods.