3. 如何在主账户与被管理者账户之间做数据通信。
a) 什么是userID
刚才提到,Lollipop用来区分主账户与被管理账户的其实是一个int型数值userID。
从UserHandler.class可以看到,这个userID是通过对uid作整除得到的:
public static final int PER_USER_RANGE =100000;
/**
*Returns the user id for a given uid.
*@hide
*/
public static final int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
}else {
return 0;
}
}
所以100000以内的uid对应的userID都是0,而超过这个数值的再取其整除结果。注意,这个只是Google为了辨识主账户与被管理账户所做的设计,并不是Unix底层带上来的参数。
而这个userID的作用刚才也提到了。在service进程对应的方法里会进行参数校验,一般来说,只有系统应用才能调用一些涉及到其他profile的方法。
b) 两个账户之前通信的先决条件
由于Profile之间数据通信的相互隔离,导致任何一个Profile中的消息发送只能被自己Profile中的组件所捕获。这样一来,虽然从根本上解决了两个Profile之间因为数据交流所可能产生的隐私暴露的问题,但是也为我们的数据共享带来了不便。
当然,Google也考虑了这方面的问题,通过一个授权处理方法addCrossProfileIntentFilter(),指定一个用于处理对应消息的Intentfilter,既可以让被管理者账户的消息可以透传到主账户,也可以在被管理者账户中接收到主账户的消息。
其中的参数FLAG_MANAGED_CAN_ACCESS_PARENT对应前者, FLAG_PARENT_CAN_ACCESS_MANAGED 对应后者。
c) 验证可行的通信方式
Android常见的组件之间通信的方式无外乎Intent,通过Intent我们可以启动Activity,Service或者是进行Broadcast等。
但是在两个Profile之间进行组件的启动,我只成功尝试了startActivity一种……
先说startService。Android5.0之后,Google对于startService限制更加严格,已经不允许以隐式Intent的方式启动一个service,不管它是不是本进程的。虽然我在建立Intent对象的同时既指定了service class,也指定了对应的action,但是通过这个action建立的intentfilter仍然无法像Activity那样被其他Profile对应的Service组件捕获。
而Broadcast也有同样的问题,无论是静态注册