修复 SecurityException: getDataNetworkTypeForSubscriber 问题
作者:Changing Lin
- 2021 年 11 月 22 日
本文字数:3879 字
阅读完需:约 13 分钟
1.问题
用户切换改变网络的过程中,应用概率会出现崩溃,日志如下
API level: '30'
OS version: '11'
ABI list: 'arm64-v8a,armeabi-v7a,armeabi'
Manufacturer: 'OnePlus'
Brand: 'OnePlus'
Model: 'GM1900'
Build fingerprint: 'OnePlus/OnePlus7_CH/OnePlus7:11/RKQ1.201022.002/2108161921:user/release-keys'
pid: 29126, tid: 29126, name: main >>> package name <<<
java stacktrace:
java.lang.SecurityException: getDataNetworkTypeForSubscriber
at android.os.Parcel.createExceptionOrNull(Parcel.java:2373)
at android.os.Parcel.createException(Parcel.java:2357)
at android.os.Parcel.readException(Parcel.java:2340)
at android.os.Parcel.readException(Parcel.java:2282)
at com.android.internal.telephony.ITelephony$Stub$Proxy.getNetworkTypeForSubscriber(ITelephony.java:8803)
at android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:3070)
at android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:3034)
at j.k.b0.a.e.b.c(Unknown Source:51)
at j.k.b.q.c.w.onCreateView(:14)
at androidx.fragment.app.Fragment.performCreateView(Unknown Source:15)
at h.l.d.q.V(:18)
at h.l.d.q.T(:1)
at h.l.d.q.U(Unknown Source:47)
at h.l.d.a.n(Unknown Source:182)
at h.l.d.q.E(:7)
at h.l.d.q.b0(Unknown Source:84)
at h.l.d.q.D(Unknown Source:31)
at h.l.d.a.e(:2)
at h.l.d.v.finishUpdate(Unknown Source:12)
at androidx.viewpager.widget.ViewPager.r(:2)
at androidx.viewpager.widget.ViewPager.onMeasure(:1)
at android.view.View.measure(View.java:25671)
at androidx.constraintlayout.widget.ConstraintLayout.e(:2)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(:70)
at android.view.View.measure(View.java:25671)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6987)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(Unknown Source:154)
at android.view.View.measure(View.java:25671)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6987)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:25671)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6987)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:25671)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6987)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:25671)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6987)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:776)
at android.view.View.measure(View.java:25671)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3713)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:2496)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2771)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2182)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8730)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1352)
at android.view.Choreographer.doCallbacks(Choreographer.java:1149)
at android.view.Choreographer.doFrame(Choreographer.java:1049)
at android.view.Choreographer$FrameHandler.handleMessage(Choreographer.java:1275)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8010)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
复制代码
2.分析
根据 SecurityException: getDataNetworkTypeForSubscriber 可以看到,这是一个安全性异常,所以猜测应用在 Android11 的权限有关,由于缺少该权限导致无法访问接口而异常。
找到网络状态检测方法,可以看到调用了 TelephonyManager.getNetworkType()接口获取网络类型,该方法是需要 READ_PHONE_STATE 权限的,该方法上面也有 RequiresPermission 注解声明
@RequiresPermission(value = "android.permission.READ_PHONE_STATE")
public int getNetworkState(Context context) {
if (null == mConnectivityManager) { // 为空则认为无网络
return NETWORK_NONE;
}
// 获取网络类型,如果为空,返回无网络
NetworkInfo activeNetInfo = mConnectivityManager.getActiveNetworkInfo();
if (activeNetInfo == null || !activeNetInfo.isAvailable()) {
return NETWORK_NONE;
}
// 判断是否为WIFI
NetworkInfo wifiInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (null != wifiInfo) {
NetworkInfo.State state = wifiInfo.getState();
if (null != state) {
if (state == NetworkInfo.State.CONNECTED || state == NetworkInfo.State.CONNECTING) {
return NETWORK_WIFI;
}
}
}
// 若不是WIFI,则去判断是2G、3G、4G网
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
int networkType = telephonyManager.getNetworkType();
...
}
复制代码
进一步分析,接口的调用堆栈为:
TelephonyManager.getNetworkType ->
PhoneInterfaceManager.getNetworkTypeForSubscriber->
TelephonyPermissions.checkCallingOrSelfReadPhoneState->
TelephonyPermissions.checkReadPhoneState->
ContextImpl.enforcePermission->
ContextImpl.checkPermission->
PermissionManager.checkPermission->
PermissionManager.checkPermissionUncached->
ActivityManager.getService->
IActivityManager.checkPermission->
复制代码
3.解决方法
private void requestPermission() {
LogUtil.printE(HomeActivity.class, ">>> etrunc requestPermission SDK-VERSION= " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { //Android 11 授权读写权限
XXPermissions.with(HomeActivity.this)
// 不适配 Android 11 可以这样写
//.permission(Permission.Group.STORAGE)
// 适配 Android 11 需要这样写,这里无需再写 Permission.Group.STORAGE
.permission(Permission.MANAGE_EXTERNAL_STORAGE, Permission.READ_PHONE_STATE)
.request(new OnPermissionCallback() {
@Override
public void onGranted(List<String> permissions, boolean all) {
if (all) {
ToastUtil.showToast(getApplication(), R.string.permission_success_tip);
}
}
@Override
public void onDenied(List<String> permissions, boolean never) {
if (never) {
ToastUtil.showToast(getApplication(), R.string.permissions_refuse_authorization);
// 如果是被永久拒绝就跳转到应用权限系统设置页面
XXPermissions.startPermissionActivity(HomeActivity.this, permissions);
} else {
ToastUtil.showToast(getApplication(), R.string.permissions_error);
}
}
});
}
}
复制代码
划线
评论
复制
发布于: 55 分钟前阅读数: 4
版权声明: 本文为 InfoQ 作者【Changing Lin】的原创文章。
原文链接:【http://xie.infoq.cn/article/65f472252da755c0b1708b2c3】。文章转载请联系作者。
Changing Lin
关注
获得机遇的手段远超于固有常规之上~ 2020.04.29 加入
我能做的,就是调整好自己的精神状态,以最佳的面貌去面对那些未曾经历过得事情,对生活充满热情和希望。
评论