关于Activity的getReferrer()之一:如何在Activity中获取调用者
来源:互联网 发布:702qq.com域名更改为 编辑:程序博客网 时间:2024/06/05 09:00
0. 为什么要在Activity中获取调用者?
主要是安全和定制两个方面的需求吧。
安全需求:
一般Activity如果已经对外开放了(即exported为true,或者加了Intent-filter),那么对Activity的保护就会降低,形成Activity攻击面,引入了风险。如果只对某几个app开放其Activity,则可以获取调用者的信息,并进行控制。定制需求:
如果被启动的Activity想对特定的调用者进行定制操作,则需要知道调用者是谁。
1. 在Activity中获取调用者的方法
注:先列出所有可能的方法,后面会给出哪些方法可行。
Binder.getCallingUid()
和Binder.getCallingPid()
,然后根据uid,pid查找到包名Activity的
getCallingPackage()
和getCallingActivity()
Activity的
getReferrer()
【注意:Android 5.1(Api level 22)中才引入的】反射的方式获取Activity的
mReferrer
:reflectGetReferrer()
【注:自定义函数,目的是获取到android.app.Activity
类的mReferrer
的值,也需要Api level 22(含)之后才能使用】
这里先给出结论:
方法1:不能在调用者startActivity()的时候获取到调用者的包名,只能用于Activity用到的Binder同步调用的地方。
方法2: 在特定情况下可以使用getCallingPackage()
和 getCallingActivity()
,即如果Activity是通过startActivityForResult
启动的,则可以使用。
方法3: Activity的getReferrer()
是不可靠的,因为调用者可以自己设置referrer的值。
方法4:是对方法3的改进,消除getReferrer()
可能返回的不可靠的值,直接获取可靠的mReferrer
值(目前来看是可靠的)。
2. 测试代码:验证上面的各种方法
2.1 场景和测试代码
场景:
有2个app,一个包名为com.galian.mainapp
,app名为MainApp
;另一个包名为com.galian.secondapp
,app名为SecondApp
。
SecondApp启动MainApp的MainActivity,在MainApp的MainActivity中检查调用者是谁。
需要说明的是,本文中有referrer
和mReferrer
两种说法,这两种是有区别的。
其中referrer
是指Activity的getReferrer()
的返回值。 mReferrer
是Activity类中的成员变量。 getReferrer()
的代码后面会给出。
被调用者:MainApp
MainApp的全部代码
MainApp的界面:
其实这是从Launcher app启动MainApp的情况,可以看到Launcher的包名(com.sec.android.app.launcher)。
// 测试各种方法,并显示 private void checkCallingApp() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("\n\n"); // Binder.getCallingUid(), Binder.getCallingPid() stringBuffer.append("1. caller uid = ").append(Binder.getCallingUid()).append(", pid = ") .append(Binder.getCallingPid()).append("\n\n"); // getReferrer(), Activity自带的获取referrer的方法,Api Level22之后才可以用 Uri referrer = getReferrer(); stringBuffer.append("2. caller (referrer uri) : "); if (referrer != null) { stringBuffer.append(referrer.toString()); } else { stringBuffer.append("null"); } stringBuffer.append("\n\n"); // reflectGetReferrer()反射的方式获取mReferrer String referrerStr = reflectGetReferrer(); stringBuffer.append("3. caller (reflect mReferrer) : ").append(referrerStr).append("\n\n"); // Activity的getCallingPackage() String callingPkg = getCallingPackage(); stringBuffer.append("4. callingPkg: ").append(callingPkg).append("\n\n"); // Activity的getCallingActivity() ComponentName componentName = getCallingActivity(); stringBuffer.append("5. caller componentName: "); if (componentName != null) { stringBuffer.append(componentName.toString()); } else { stringBuffer.append("null"); } mTextView.setText(getString(R.string.caller_name, stringBuffer.toString())); }
反射的方式获取mReferrer
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
调用者:SecondApp
SecondApp的全部代码
SecondApp的界面:
SecondApp的代码在各种情况中给出。
2.2 情况1: 调用者没有修改referrer
SecondApp启动MainApp的MainActivity
:
// 测试getReferrer(): 没有修改referrer的情况 Intent intent = new Intent(); intent.setClassName("com.galian.mainapp", "com.galian.mainapp.MainActivity"); startActivity(intent);
结果分析:
- uid为10189,pid为29089,这是MainApp自身。
- 1
- 2
- 1
- 2
- getReferrer()的返回值为
android-app://com.galian.secondapp
,此值可以得到调用者的包名。 - 反射方式获取到的
mReferrer
为:com.galian.secondapp
,此值可以得到调用者的包名。 - getCallingPackage()和getCallingActivity()都返回null
2.3 情况2:调用者通过Intent.EXTRA_REFERRER
修改referrer的值
SecondApp启动MainApp的MainActivity
:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
结果分析:
- uid为10189,pid为29089,这是MainApp自身。
- getReferrer()的返回值为
android-app://com.test.app
,此值不是真正的调用者的包名。 - 反射方式获取到的
mReferrer
为:com.galian.secondapp
,此值可以得到调用者的包名。 - getCallingPackage()和getCallingActivity()都返回null
2.4 情况3:调用者通过Intent.EXTRA_REFERRER_NAME
修改referrer的值
SecondApp启动MainApp的MainActivity
:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
结果分析:
- uid为10189,pid为29089,这是MainApp自身。
- getReferrer()的返回值为
android-app://com.example.app
,此值不是真正的调用者的包名。 - 反射方式获取到的
mReferrer
为:com.galian.secondapp
,此值可以得到调用者的包名。 - getCallingPackage()和getCallingActivity()都返回null
2.5 情况4:测试getCallingPackage()和getCallingActivity()
同时调用者通过Intent.EXTRA_REFERRER
修改referrer的值。
SecondApp通过startActivityForResult()
启动MainApp的MainActivity
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
结果分析:
- uid为10189,pid为29089,这是MainApp自身。
- getReferrer()的返回值为
android-app://com.test.app
,此值不是真正的调用者的包名。 - 反射方式获取到的
mReferrer
为:com.galian.secondapp
,此值可以得到调用者的包名。 - getCallingPackage()返回
com.galian.secondapp
,getCallingActivity()返回ComponentInfo{com.galian.secondapp/com.galian.secondapp.SecondMainActivity}
。可以得到调用者的包名。
3. 结论
从上面的测试结果可以得到下面的结论:
通过反射的方式(
reflectGetReferrer()
)获取到的mReferrer
,是调用者的包名,目前来看是可靠的,但是需要在Android5.1(Api level 22)以及之后才能用。getCallingPackage()
和getCallingActivity()
只有在startActivityForResult()
的时候才可以得到调用者的包名。Activity的
getReferrer()
是不可靠的,因为调用者可以自己设置referrer的值。所以不能依赖此值来判断调用者。Binder.getCallingUid()
和Binder.getCallingPid()
一般用在同步调用中,在这几个情况中并不适用。
4. 关于mReferrer
的细节
4.1 Activity的getReferrer()
需要注意的是,此方法是在Android 5.1 (Api level 22)中引入的,Android 5.1之前是不能使用的。
Intent.Java
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
Activity.java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
4.2 反射的方式获取Activity的mReferrer
需要注意的是,此方法是基于getReferrer()
(mReferrer
)的,所以也必须在Android 5.1 (Api level 22)及 5.1 之后才能用。
自定义方法:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
**4.3 Activity中的mReferrer
是如何传递过来的?
由于内容较多,请参考另一篇博文《关于Activity的getReferrer()
之二:调用者的包名是如何传给mReferrer
的,兼谈startActivity的详细流程》
转自:http://blog.csdn.net/u013553529/article/details/53856800
- 关于Activity的getReferrer()之一:如何在Activity中获取调用者?
- 关于Activity的getReferrer()之一:如何在Activity中获取调用者
- 关于Activity的getReferrer()之二:调用者的包名是如何传给mReferrer的,兼谈startActivity的详细流程
- 关于如何在activity之外调用Conetxt
- 如何在一个Service中调用Activity
- 如何在Activity中调用系统的返回功能
- 在Fragment中如何调用指定Activity的方法
- 如何在Fragment中获取Activity
- 在activity中如何正确获取View的宽高
- 在一个Activity中获取另一个Activity的上下文
- 《如何在一个Activity的一部分中显示其他Activity》
- 如何在非Activity类中调用getContentResolver()方法
- Android开发实用技巧:如何在Activity中获取资源
- 如何解决在Activity中无法获取getSupportFragmentManager()
- 在一个组件中调用其他组件的内容||android中怎样在activity中获取fragment中的控件
- Android中,如何在其他类调用Activity的方法,适用于类似场景
- 如何在activity中获取我们想要的view的宽高?
- android 在Activity的OnCreate()方法中如何获取view的宽和高
- 小石头UI自动化测试框架(项目实战)python、Selenium(日志、邮件、pageobject)
- mybatis generator 生成数据库注释等问题
- Java基础小细节,面试可能会出
- 日志带参输出 The Art of Logging: Advanced message formatting
- POJO和javabean的区别
- 关于Activity的getReferrer()之一:如何在Activity中获取调用者
- 笨办法学python ex29-35
- 暑期集训day1例题(最短路径、二分图匹配、拓扑排序)
- The kth great number
- 进制均值
- win10和Ubuntu下时间不同步
- 【blog】vue项目搭建
- IBM 发布基于 Kubernetes 的 IBM 私有云平台
- 纯css美化复选框、单选框、下拉列表、file文件上传器