Android 11 旧版本兼容修改:TelephonyManager的getDeviceId和getSubscriberId; WifiManager.setWifiEnabled

这篇具有很好参考价值的文章主要介绍了Android 11 旧版本兼容修改:TelephonyManager的getDeviceId和getSubscriberId; WifiManager.setWifiEnabled。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

    随着Android的更新,越新的版本收紧的权限越来越多,伴随着很多曾经可用的接口慢慢地出现了问题。

比如: TelephonyManager.getSubscriberId()

public static void testGetSubId(Context ctx){
        //Android 11:
        // java.lang.SecurityException: getSubscriberId: The user 10125 does not meet the requirements to access device identifiers.
        TelephonyManager telMgr = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
        @SuppressLint("MissingPermission")
        String subId = telMgr.getSubscriberId();
        android.util.Log.d(TAG, "testGetSubId subId=" + subId);
    }

原因

在代码注释中已经写得很明白:
The user 10125 does not meet the requirements to access device identifiers

要做的事情很简单, 找到权限检查的地方, 去掉它
权限检查的位置

frameworks/base/telephony/common/com/android/internal/telephony/TelephonyPermissions.java

    public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
            String callingPackage, @Nullable String callingFeatureId, String message) {
        return true || checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
                context, subId, callingPackage, callingFeatureId, message, true);
    }
    public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
            String callingPackage, @Nullable String callingFeatureId, String message) {
        return true || checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
                context, subId, callingPackage, callingFeatureId, message, false);
    }
    private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
            String message, boolean allowCarrierPrivilegeOnAnySub) {
        int uid = Binder.getCallingUid();
        int pid = Binder.getCallingPid();

        // If the calling package has carrier privileges for specified sub, then allow access.
        if (checkCarrierPrivilegeForSubId(context, subId)) return true;

        // If the calling package has carrier privileges for any subscription
        // and allowCarrierPrivilegeOnAnySub is set true, then allow access.
        if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) {
            return true;
        }

        PermissionManager permissionManager = (PermissionManager) context.getSystemService(
                Context.PERMISSION_SERVICE);
        if (permissionManager.checkDeviceIdentifierAccess(callingPackage, message, callingFeatureId,
                pid, uid) == PackageManager.PERMISSION_GRANTED) {
            return true;
        }

        return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
                message);
    }
    /**
     * Reports a failure when the app with the given pid/uid cannot access the requested identifier.
     *
     * @returns false if the caller is targeting pre-Q and does have the READ_PHONE_STATE
     * permission or carrier privileges.
     * @throws SecurityException if the caller does not meet any of the requirements for the
     *                           requested identifier and is targeting Q or is targeting pre-Q
     *                           and does not have the READ_PHONE_STATE permission or carrier
     *                           privileges.
     */
    private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
            int uid, String callingPackage, String message) {
        ApplicationInfo callingPackageInfo = null;
        try {
            callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
                    callingPackage, 0, UserHandle.getUserHandleForUid(uid));
        } catch (PackageManager.NameNotFoundException e) {
            // If the application info for the calling package could not be found then assume the
            // calling app is a non-preinstalled app to detect any issues with the check
            Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage,
                    e);
        }
        // The current package should only be reported in StatsLog if it has not previously been
        // reported for the currently invoked device identifier method.
        boolean packageReported = sReportedDeviceIDPackages.containsKey(callingPackage);
        if (!packageReported || !sReportedDeviceIDPackages.get(callingPackage).contains(
                message)) {
            Set invokedMethods;
            if (!packageReported) {
                invokedMethods = new HashSet<String>();
                sReportedDeviceIDPackages.put(callingPackage, invokedMethods);
            } else {
                invokedMethods = sReportedDeviceIDPackages.get(callingPackage);
            }
            invokedMethods.add(message);
            TelephonyCommonStatsLog.write(TelephonyCommonStatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED,
                    callingPackage, message, /* isPreinstalled= */ false, false);
        }
        Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message + ":"
                + subId);
        // if the target SDK is pre-Q then check if the calling package would have previously
        // had access to device identifiers.
        if (callingPackageInfo != null && (
                callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
            if (context.checkPermission(
                    android.Manifest.permission.READ_PHONE_STATE,
                    pid,
                    uid) == PackageManager.PERMISSION_GRANTED) {
                return false;
            }
            if (checkCarrierPrivilegeForSubId(context, subId)) {
                return false;
            }
        }
        throw new SecurityException(message + ": The user " + uid
                + " does not meet the requirements to access device identifiers.");
    }

frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java

    @Override
    public int checkDeviceIdentifierAccess(@Nullable String packageName, @Nullable String message,
            @Nullable String callingFeatureId, int pid, int uid) {
        // If the check is being requested by an app then only allow the app to query its own
        // access status.
        int callingUid = mInjector.getCallingUid();
        int callingPid = mInjector.getCallingPid();
        if (UserHandle.getAppId(callingUid) >= Process.FIRST_APPLICATION_UID && (callingUid != uid
                || callingPid != pid)) {
            String response = String.format(
                    "Calling uid %d, pid %d cannot check device identifier access for package %s "
                            + "(uid=%d, pid=%d)",
                    callingUid, callingPid, packageName, uid, pid);
            Log.w(TAG, response);
            throw new SecurityException(response);
        }
        // Allow system and root access to the device identifiers.
        final int appId = UserHandle.getAppId(uid);
        if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
        if (mInjector.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
                uid) == PackageManager.PERMISSION_GRANTED) {
            return PackageManager.PERMISSION_GRANTED;
        }
        // If the calling package is not null then perform the appop and device / profile owner
        // check.
        if (packageName != null) {
            // Allow access to a package that has been granted the READ_DEVICE_IDENTIFIERS appop.
            long token = mInjector.clearCallingIdentity();
            AppOpsManager appOpsManager = (AppOpsManager) mInjector.getSystemService(
                    Context.APP_OPS_SERVICE);
            try {
                if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid,
                        packageName, callingFeatureId, message) == AppOpsManager.MODE_ALLOWED) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            } finally {
                mInjector.restoreCallingIdentity(token);
            }
            // Check if the calling packages meets the device / profile owner requirements for
            // identifier access.
            DevicePolicyManager devicePolicyManager =
                    (DevicePolicyManager) mInjector.getSystemService(Context.DEVICE_POLICY_SERVICE);
            if (devicePolicyManager != null && devicePolicyManager.hasDeviceIdentifierAccess(
                    packageName, pid, uid)) {
                return PackageManager.PERMISSION_GRANTED;
            }
        }
        return PackageManager.PERMISSION_DENIED;
    }


WifiManager.setWifiEnabled

    从官方文档中已经说明: SDK >= Q 这个接口会直接返回 false,不再生效
Android 11 旧版本兼容修改:TelephonyManager的getDeviceId和getSubscriberId; WifiManager.setWifiEnabled,android-framework,android,android,权限,Wifi,手机信息
示例

build.gradle 注意targetSdkVersion

    defaultConfig {
        applicationId "com.xxx.apitester"
        minSdkVersion 21
        targetSdkVersion 30
		//...
    }
		WifiManager wifiMgr = (WifiManager) ctx.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        boolean en = wifiMgr.isWifiEnabled();
        //返回false
        boolean res = wifiMgr.setWifiEnabled(!en);

如果调用了从LOG中可以找到: setWifiEnabled not allowed for uid=xxx

原因

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

    /**
     * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
     * @param enable {@code true} to enable, {@code false} to disable.
     * @return {@code true} if the enable/disable operation was
     *         started or is already in the queue.
     */
    @Override
    public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
        if (enforceChangePermission(packageName) != MODE_ALLOWED) {
            return false;
        }
/*********************************/
//检查APP的SDK版本等信息。
/*********************************/
        boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());
        if (!isPrivileged && !isDeviceOrProfileOwner(Binder.getCallingUid(), packageName)
                && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q,
                  Binder.getCallingUid())
                && !isSystem(packageName, Binder.getCallingUid())) {
            mLog.info("setWifiEnabled not allowed for uid=%")
                    .c(Binder.getCallingUid()).flush();
            return false;
        }
        // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
        if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
            mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
            return false;
        }

        // If SoftAp is enabled, only privileged apps are allowed to toggle wifi
        if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
            mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
            return false;
        }

        mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
                .c(Binder.getCallingUid()).c(enable).flush();
        long ident = Binder.clearCallingIdentity();
        try {
            if (!mSettingsStore.handleWifiToggled(enable)) {
                // Nothing to do if wifi cannot be toggled
                return true;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) {
            if (enable) {
                mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON);
            } else {
                WifiInfo wifiInfo = mClientModeImpl.syncRequestConnectionInfo();
                mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF,
                        wifiInfo == null ? -1 : wifiInfo.getNetworkId());
            }
        }
        mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
        mActiveModeWarden.wifiToggled();
        return true;
    }

检查版本低于:Build.VERSION_CODES.Q

frameworks/opt/net/wifi/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java


    /**
     * Checks whether than the target SDK of the package is less than the specified version code.
     */
    public boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) {
    	//强制返回,版本检测将不再生效
    	if(true)return true;
        long ident = Binder.clearCallingIdentity();
        try {
            if (mContext.getPackageManager().getApplicationInfoAsUser(
                    packageName, 0,
                    UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion
                    < versionCode) {
                return true;
            }
        } catch (PackageManager.NameNotFoundException e) {
            // In case of exception, assume unknown app (more strict checking)
            // Note: This case will never happen since checkPackage is
            // called to verify validity before checking App's version.
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        return false;
    }

参考

  • 第三方APP无法申请READ_PRIVILEGED_PHONE_STATE权限:
Android 10 changes the permissions for device identifiers so that all device identifiers are now protected by the READ_PRIVILEGED_PHONE_STATE permission. 
Prior to Android 10, persistent device identifiers (IMEI/MEID, IMSI, SIM, and build serial) were protected behind the READ_PHONE_STATE runtime permission. 
The READ_PRIVILEGED_PHONE_STATE permission is only granted to apps signed with the platform key and privileged system apps.

How to request for permission: READ_PRIVILEGED_PHONE_STATE?

Android 获取双卡手机IMEI,IMSI,ICCID文章来源地址https://www.toymoban.com/news/detail-605422.html

  • Turning on wifi using WifiManager stops to work on Android 10

到了这里,关于Android 11 旧版本兼容修改:TelephonyManager的getDeviceId和getSubscriberId; WifiManager.setWifiEnabled的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android的Gradle、Studio、Java、Kotlin版本兼容

    Android Gradle 插件和 Android Studio 兼容性 Android Studio 版本 所需插件版本 Hedgehog - 2023.1.1 3.2-8.2 Giraffe - 2022.3.1 3.2-8.1 Flamingo - 2022.2.1 3.2-8.0 Electric Eel - 2022.1.1 3.2-7.4 Dolphin - 2021.3.1 3.2-7.3 Chipmunk - 2021.2.1 3.2-7.2 Bumblebee - 2021.1.1 3.2-7.1 Arctic Fox - 2020.3.1 3.1-7.0 Gradle版本和Java版本对应关系 Ja

    2024年02月09日
    浏览(47)
  • Android11.0 修改系统默认显示大小

    系统设置中的显示大小调整的就是屏幕密度,调整的越小,屏幕显示的内容就越多。 在系统中都会有定义一个默认的屏幕密度 设置中显示大小相关内容 源码:/packages/apps/Settings/res/xml/display_settings.xml 源码:/packages/apps/Settings/src/com/android/settings/display/ScreenZoomSettings.java 密度缩

    2024年02月09日
    浏览(64)
  • Android11.0 launcher修改为单层

    OS: RK3568 Android11.0 现在的产品基本都是按照手机样式去做,所以需要把系统默认的Launcher样式,去掉抽屉改为单层显示,也就是把所有的app添加到workspace中。 以下修改是在设备横屏模式下进行 。 1.添加一个宏开关控制Launcher单双层显示 源码: /packages/apps/Launcher3/src/com/android/

    2024年02月08日
    浏览(62)
  • 从GitHub下载的Android Studio项目,在较新版本AS打开出现版本不兼容问题的解决方法。

            在GitHub下载了一个Android Studio计算器项目,打开项目后出现一系列问题,本文简单记录出现的问题及解决方法。 问题描述:The specified Gradle installation directory \\\'G:AndroidAndroid Studiogradlegradle-2.14.1\\\' does not exist. 解决方法:按照以下步骤更改Gradle安装目录的路径 打开您的

    2024年02月06日
    浏览(68)
  • android11 如何修改状态栏的背景

    修改status_bar.xml :

    2024年04月16日
    浏览(34)
  • rk3568 安卓11 修改android id

    frameworksbasepackagesSettingsProvidersrccomandroidproviderssettingsSettingsProvider.java 系统应用获取的android id 直接写死 上层普通应用 android id跟着sn变化 android id跟着IMEI变化

    2024年04月28日
    浏览(49)
  • Android项目:如何确定Java版本兼容的gradle版本(Unsupported Java. Your build is currently configured to use Java……)

    在配置从github上下载的项目时,配置的过程中出现错误: 解决方法概括:根据链接所提供的Java和gradle对应的兼容版本,调整Java或是gradle版本 问题所在:Java版本需要和gradle版本兼容,调整版本即可 我们可以在这个链接中查看对应Java版本所兼容的gradle版本。 2023.8.11截图版本

    2024年02月08日
    浏览(54)
  • Android Studio 修改 Gradle 版本

    Gradle 是一种强大的构建工具,广泛应用于 Android 开发中。它可以帮助我们管理项目的依赖、编译代码并生成可执行文件等等。在 Android Studio 中,Gradle 的版本是由项目的 build.gradle 文件指定的。本文将介绍如何修改 Android Studio 中的 Gradle 版本,并给出相应的源代码示例。 首先

    2024年02月02日
    浏览(57)
  • Android Studio版本升级后的问题 gradle降级、jdk升级 Compose 与 Kotlin 的兼容性对应关系

    AGPBI: {“kind”:“error”,“text”:“Can’t determine type for tag ‘macro name=“m3_comp_switch_disabled_selected_handle_color”?attr/colorSurface’”,“sources”:[{“file”:“/Users/fausto/.gradle/caches/transforms-3/4948d05d0ff6027d2e3c9f4a6010103b/transformed/material-1.7.0-alpha02/res/values/values.xml”}],“tool”:“Resource and

    2024年02月04日
    浏览(78)
  • Android Studio 的Gradle版本修改

    使用Android Studio构建项目时,需要配置Gradle,与Gradle插件。 Gradle是一个构建工具,用于管理和自动化Android项目的构建过程。它使用Groovy或Kotlin作为脚本语言,并提供了强大的配置能力来定义项目的依赖关系、编译选项、打包方式等。 Gradle插件是专门为Android项目设计的Gradle扩

    2024年02月14日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包