(转)Android-shareUserId作用

转载: http://www.cnblogs.com/wotakuc/archive/2013/03/27/2984423.html

1.shareUserId介绍:

Android给每个APK进程分配一个单独的空间,manifest中的userid就是对应一个分配的Linux用户ID,
并且为它创建一个沙箱,以防止影响其他应用程序(或者其他应用程序影响它)。
用户ID 在应用程序安装到设备中时被分配,并且在这个设备中保持它的永久性。
通常,不同的APK会具有不同的userId,因此运行时属于不同的进程中,而不同进程中的资源是不共享的,
在保障了程序运行的稳定。然后在有些时候,我们自己开发了多个APK并且需要他们之间互相共享资源,
那么就需要通过设置shareUserId来实现这一目的。
通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中.所以默认就是可以互相访问任意数据. 也可以配置成运行成不同的进程, 同时可以访问其他APK的数据目录下的数据库和文件.就像访问本程序的数据一样。

2.shareUserId设置:

在需要共享资源的项目的每个AndroidMainfest.xml中添加shareuserId的标签。
android:sharedUserId="com.example"
id名自由设置,但必须保证每个项目都使用了相同的sharedUserId。一个mainfest只能有一个Shareuserid标签。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.shareusertesta"
    android:versionCode="1"
    android:versionName="1.0" 
    android:sharedUserId="com.example">

3.不同APP的(/data/data/app包名/文件)的共享

每个安装的程序都会根据自己的包名在手机文件系统的/data/data/app包名/建立一个文件夹(需要su权限才能看见),用于存储程序相关的数据。
在代码中,我们通过context操作一些IO资源时,相关文件都在此路径的相应文件夹中。比如默认不设置外部路径的文件、DB等等。
正常情况下,不同的apk无法互相访问对应的app文件夹。但通过设置相同的shareUserId后,就可以互相访问了。代码如下。

//程序A:
public class MainActivityA extends Activity {
    TextView textView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.textView1);
        WriteSettings(this, "123");
    }

    public void WriteSettings(Context context, String data) {
        FileOutputStream fOut = null;
        OutputStreamWriter osw = null;
        try {
            //默认建立在data/data/xxx/file/ 
            fOut = openFileOutput("settings.dat", MODE_PRIVATE);            
            osw = new OutputStreamWriter(fOut);
            osw.write(data);
            osw.flush();
            Toast.makeText(context, "Settings saved", Toast.LENGTH_SHORT)
                    .show();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(context, "Settings not saved", Toast.LENGTH_SHORT)
                    .show();
        } finally {
            try {
                osw.close();
                fOut.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

//程序B:
public class MainActivityB extends Activity {
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) this.findViewById(R.id.textView1);
        
        try {
            //获取程序A的context
            Context ctx = this.createPackageContext(
                    "com.example.shareusertesta",             Context.CONTEXT_IGNORE_SECURITY);
            String msg = ReadSettings(ctxDealFile);
            Toast.makeText(this, "DealFile2 Settings read" + msg,
                    Toast.LENGTH_SHORT).show();
            WriteSettings(ctx, "deal file2 write");
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public String ReadSettings(Context context) {
        FileInputStream fIn = null;
        InputStreamReader isr = null;
        char[] inputBuffer = new char[255];
        String data = null;
        try {
            //此处调用并没有区别,但context此时是从程序A里面获取的
            fIn = context.openFileInput("settings.dat");
            isr = new InputStreamReader(fIn);
            isr.read(inputBuffer);
            data = new String(inputBuffer);
            textView.setText(data);
            Toast.makeText(context, "Settings read", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(context, "Settings not read", Toast.LENGTH_SHORT)
                    .show();
        } finally {
            try {
                isr.close();
                fIn.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    public void WriteSettings(Context context, String data) {
        FileOutputStream fOut = null;
        OutputStreamWriter osw = null;
        try {
            fOut = context.openFileOutput("settings.dat", MODE_PRIVATE);
            //此处调用并没有区别,但context此时是从程序A里面获取的
            osw = new OutputStreamWriter(fOut);
            osw.write(data);
            osw.flush();
            Toast.makeText(context, "Settings saved", Toast.LENGTH_SHORT)
                    .show();

        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(context, "Settings not saved", Toast.LENGTH_SHORT)
                    .show();

        } finally {
            try {
                osw.close();
                fOut.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

如果A和B的mainfest中设置了相同的shareuserId,那么B的read函数就能正确读取A写入的内容。否则,B无法获取该文件IO。
通过这种方式,两个程序之间不需要代码层级的引用。之间的约束是,B需要知道A的file下面存在“settings.dat”这个文件以及B需要知道A的package的name。

4.Resources和SharedPreferences的共享

通过shareuserId共享,我们可获取到程序A的context。因此,我们就可以通过context来获取程序A对应的各种资源。
比较常用的就是Raw资源的获取,如一些软件的apk皮肤包就是采用了这种技术,将主程序和皮肤资源包分在两个apk中。
获取Resources很简单,在程序A和B的mainfest中设置好相同的shareuserId后,通过createPackageContext获取context即可。
之后就和原来的方式一样,通过getResources函数获取各种资源,只是此时的context环境是目标APP的context环境。

//在B中获取A的各种资源
Context friendContext = this.createPackageContext( "com.example.shareusertesta", Context.CONTEXT_IGNORE_SECURITY);
Resources res = friendContext.getResources();
int xId = res.getIdentifier("xxx", "drawable", "com.example.shareusertesta"); //R.string.xxx 
int yId = res.getIdentifier("yyy", "string", "com.example.shareusertesta"); //R.Drawable.yyy
res.getString(xId);
res.getDrawable(yId);

5.访问安全性(签名)

上文中通过测试,验证了同key下设置相同shareuserid后可共享资源,否则失败。
但还有两种情况尚未讨论。一是假设A和C用两个不同的签名,但设置相同的shareuserid,那么能否共享资源。
二是假设A用签名后的apk安装,C用usb直连调试(即debug key),两者设置相同的shareuserid,那么能否共享资源。
经过测试,不论是USB调试还是新签名APK都安装不上。
再进一步测试后发现,能否安装取决于之前手机中是否已经存在对应该shareduserId的应用。
如有,则需要判断签名key是否相同,如不同则无法安装。也就是说,如果你删除a和b的应用先装c,此时c的安装正常,
而原来a和b的安装就失败了(a、b同key,c不同key,三者userId相同)。

6.其他讨论

1 android:sharedUserId="android.uid.system" 如果这么设置,可实现提权的功能,修改系统时间等需要core权限的操作就可完成了。
但看到有人说会造成sd卡读取bug,网上有不少解决方案(未测试)。

2 修改shareuserId后,usb开发调试安装没有问题,但是利用Ecplise打包签名APK后,
部分机型会造成无法安装的问题。网上有提到需要源码环境mm打包或其他,较麻烦暂未验证。
目前测试了三台机子:三星S3自带系统失败;华为一机子成功;三星一刷官方anroid系统的机子成功。
初步估计部分厂商修改了一定的内核,造成安装失败,具体兼容性情况有待进一步测试

3 使用shareuserid后,对同系列的产品的签名key必须统一,不要丢失。否则后面开发的系列app就无法获取数据了。
此外,注意从没有userId的版本到有userId版本时的升级,也可能存在一定的安全权限问题。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容