当前位置:   article > 正文

android 各个版本安全特性_android各个版本特性

android各个版本特性

一、Android SDK与API Level

Google发布的Android系统习惯以甜点命令,并且首字母以字母顺序表依次排序,对应表如下:

平台版本API级别版本代号发布时间
Android 14.033–>Beta32023.8(预计)
Android 13.033Android 13(提拉米苏)2022.8
Android 12.031、32Android S、Android S_V22020.9
Android 11.0®30Android R2020.2
Android 10.0(Q)29Android Q2019.3
Android 9.028Pie(馅饼)2018.8
Android 8.127Oreo(奥利奥)2017.12
Android 8.026Oreo(奥利奥)2017.8
Android 7.1.125Nougat(牛轧糖)2016.10
Android 7.024Nougat(牛轧糖)2016.8
Android 6.023Marshmallow(棉花糖)2015.10
Android 5.122Lollipop(棒棒糖)2015.3
Android 5.021Lollipop(棒棒糖)2014.11
Android 4.4W20KITKAT_WATCH2014.6
Android 4.419KitKat(奇巧)2013.10
Android 4.318Jelly Bean(果冻豆)2013.7
Android 4.217Jelly Bean(果冻豆)2012.10
Android 4.116Jelly Bean(果冻豆)2012.6
Android 4.0315Ice Cream Sandwich(冰激凌三明治)2011.12
Android 4.014Ice Cream Sandwich(冰激凌三明治)2011.10
Android 3.213Honeycomb(蜂巢)2011.7
Android 3.112Honeycomb(蜂巢)2011.5
Android 3.011Honeycomb(蜂巢)2011.2
Android 2.3.310Gingerbread(姜饼)2011.2
Android 2.3.19Gingerbread(姜饼)2010.12
Android 2.28Froyo(冻酸奶)2010.5
Android 2.17Eclair(泡芙)2010.1
Android 2.0.16Eclair(泡芙)2009.12
Android 2.05Eclair(泡芙)2009.10
Android 1.64Donut(甜甜圈)2009.9
Android 1.53Cupcake(纸杯蛋糕)2009.4
Android 1.12-2009.2
Android 1.01-2008.9

Android在正式发行前的两个内部测试版本,以著名机器人来命名:阿童木(AndroidBeta),发条机器人(Android 1.0)

二、各Android版本

Android 6.0

Google I/O 2015大会如约已于2015年5月28日举行。在发布会上代号为“Marshmallow(棉花糖)”的安卓6.0系统正式推出。
Android 6.0 的API级别:23
新特性:

1.运行时权限(最主要)

此版本引入了一种新的权限模式,用户可直接在运行时管理应用权限。
对于以 Android 6.0(API 级别 23)或更高版本为目标平台的应用,请务必在运行时检查和请求权限。要确定您的应用是否已被授予权限,请调用新增的 checkSelfPermission() 方法。要请求权限,请调用新增的 requestPermissions() 方法。即使您的应用并不以 Android 6.0(API 级别 23)为目标平台,您也应该在新权限模式下测试您的应用。

2.取消支持Apache HTTP客户端

Android 6.0版本移除了对Apache HTTP客户端的支持。
如果您的应用使用该客户端,并以 Android 2.3(API 级别 9)或更高版本为目标平台,请改用 HttpURLConnection 类。此 API 效率更高,因为它可以通过透明压缩和响应缓存减少网络使用,并可最大限度降低耗电量。要继续使用 Apache HTTP API,您必须先在 build.gradle 文件中声明以下编译时依赖项:

android {
    useLibrary 'org.apache.http.legacy'//使用Apache库
}
  • 1
  • 2
  • 3

Android 7.0

Android 7.0是Google推出的智能手机操作系统,官方代号为“Nougat”(牛轧糖)。于2016年5月18-20日(美国西部时间)在Google I/O开发者大会上正式发布,发布地点是山景城的Shoreline Ampitheatre圆形剧场
Android 7.0 包括旨在延长设备电池寿命和减少 RAM 使用的系统行为变更。这些变更可能会影响您的应用访问系统资源,以及您的应用通过特定隐式 intent 与其他应用交互的方式。
新特性:

1.低电耗模式

Android 6.0引入了低电耗模式,当用户设备未插接电源,处于静止状态且屏幕关闭时,该模式会推迟 CPU 和网络活动,从而延长电池寿命。而 Android 7.0 则通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持式设备装在口袋里)时应用部分 CPU 和网络限制,进一步增强了低电耗模式。

2.系统权限的更改

为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问 (0700)。此设置可防止私有文件的元数据泄漏,如它们的大小或存在性。此权限更改有多重副作用
传递软件包网域外的 file:// URI 可能给接收器留下无法访问的路径。因此,尝试传递 file:// URI 会触发 FileUriExposedException。分享私有文件内容的推荐方法是使用 FileProvider。
Android7.0之前访问系统相册

  File file = new File(Environment.getExternalStorageDirectory(), "/temp/" + System.currentTimeMillis() + ".jpg");
                if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
                Uri imageUri = Uri.fromFile(file);
                Intent intent = new Intent();
//设置Action为拍照
                intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
//将拍取的照片保存到指定URI
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, 1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在7.0之后的话访问相册会报如下错误:
android.os.FileUriExposedException: file:///storage/emulated/0/temp/1627010812423.jpg exposed beyond app through ClipData.Item.getUri()
在Android7.0系统上,Android 框架强制执行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片。

3.网络安全配置

借助网络安全配置功能,应用可以在一个安全的声明性配置文件中自定义其网络安全设置,而无需修改应用代码。您可以针对特定网域和特定应用配置这些设置。此功能的主要特性如下所示:

  • 自定义信任锚:针对应用的安全连接自定义哪些证书授权机构 (CA) 值得信赖。例如,信任特定的自签名证书或限制应用信任的公共 CA 集。
  • 仅调试替换:在应用中以安全方式调试安全连接,而不会增加安装设备的风险。
  • 选择停用明文流量:防止应用意外使用明文流量。
  • 证书固定:限制应用仅安全连接到特定的证书。
4.自定义可信 CA

应用可能需要信任自定义的 CA 集,而不是平台默认值。出现此情况的最常见原因包括:

  • 连接到具有自定义证书授权机构(如自签名或在公司内部签发的 CA)的主机。
  • 仅限您信任的 CA(而不是每个预装 CA)。
  • 信任未包含在系统中的其他 CA。

默认情况下,来自所有应用的安全连接(使用 TLS 和 HTTPS 之类的协议)均信任预装的系统 CA,而以 Android 6.0(API 级别 23)及更低版本为目标平台的应用默认情况下还会信任用户添加的 CA 存储区。应用可以使用 base-config(应用范围的自定义)或 domain-config(针对每个网域的自定义)自定义自己的连接。

5.固定证书

一般情况下,应用信任所有预装 CA。如果有预装 CA 颁发了欺诈性证书,则应用将面临被中间人攻击的风险。有些应用选择通过限制信任的 CA 集或通过固定证书来限制其接受的证书集。

如需固定证书,您可以通过按公钥的哈希值(X.509 证书的 SubjectPublicKeyInfo)提供证书集。然后,只有至少包含一个已固定公钥的证书链才有效。

请注意,固定证书时,您应始终包含一个备用密钥,这样,当您被强制切换到新密钥或更改 CA 时(固定到某个 CA 证书或该 CA 的中间证书时),应用的连接性不会受到影响。否则,您必须推送应用更新以恢复连接性。

此外,可以设置证书固定的到期时间,在该时间之后不再固定证书。这有助于防止尚未更新的应用出现连接性问题。不过,设置证书固定的到期时间可能会绕过证书固定。

Android 8.0

2017年8月22日,谷歌正式发布了Android 8.0的正式版,其正式名称为:Android Oreo(奥利奥) 。2017年12月5日谷歌正式发布了Android 8.1的正式版。

1.通知渠道 — Notification Channels

通知渠道是由应用自行定义的通知内容类别,借助渠道,开发者可以让用户对不同种类的通知进行精细控制,用户可以单独拦截或更改每个渠道的行为,而不是统一管理应用的所有通知。
创建通知渠道的步骤:

创建 NotificationChannel 对象,并设置应用内唯一的通知 ID。
配置通知渠道的属性,比如提示声音等。
在 NotificationManager 中注册通知渠道对象。

2.画中画模式 — PIP

Android O 现已支持 Activity 的画中画模式。PIP 是一种多窗口显示模式,多用于视频播放。这和普通的画中画分屏模式并不相同。这一功能的唤醒只需要点击Home键按钮,如果想结束这一模式,可以将小窗口滑下来以终止。
关于生命周期
PIP 模式不会改变 Activity 的生命周期。在指定时间只有最近与用户交互过的 Activity 为活动状态。 该 Activity 将被视为顶级 Activity。 所有其他 Activity 虽然可见,但均处于暂停状态。当一个 Activity 处于 PIP 模式时,其实它是出在暂停状态,但其内容会继续展示。
API变更
在 Android O 中新增 PictureInPictureArgs 对象来指明你的 Activity 在 PIP 模式中的属性,比如长宽比等。
Android O 还新增了以下方法来支持 PIP。
Activity.enterPictureInPictureMode(PictureInPictureArgs args):将Activity置于 PIP 模式之下。
Activity.setPictureInPictureArgs():用于更新 Activity 在 PIP 模式下的设置。如果 Activity 正处于 PIP 模式之下,那么更改的属性将立即生效。

3.安全性与隐私
权限

Android 8.0 引入了多个与电话有关的新权限:

  • ANSWER_PHONE_CALLS允许您的应用通过编程方式接听呼入电话。要在您的应用中处理呼入电话,您可以使用 acceptRingingCall() 函数。
  • READ_PHONE_NUMBERS权限允许您的应用读取设备中存储的电话号码。

这些权限均被划分为危险类别,属于 PHONE 权限组。

新的帐号访问和 Discovery API

Android 8.0 对应用访问用户帐号的方式引入多项改进。对于由身份验证器管理的帐号,身份验证器在决定对应用隐藏帐号还是显示帐号时可以使用自己的策略。Android 系统跟踪可以访问特定帐号的应用。

在以前的 Android 版本中,想要跟踪用户帐号列表的应用必须获取有关所有帐号的更新,包括具有不相关类型的帐号。Android 8.0 添加了 addOnAccountsUpdatedListener 函数,其允许应用指定应接收帐号变更的帐号类型列表。

API 变更

AccountManager 提供六个新函数以帮助身份验证器管理哪些应用可以查看某个帐号:

  • setAccountVisibility:针对特定用户帐号和软件包组合设置可见性级别。
  • getAccountVisibility:获取特定用户帐号和软件包组合的可见性级别。
  • getAccountsAndVisibilityForPackage:允许身份验证器获取帐号和给定软件包的可见性级别。
  • getPackagesAndVisibilityForAccount:允许身份验证器获取存储的给定帐号的可见性值。
  • addAccountExplicitly:允许身份验证器初始化帐号的可见性值。
  • addOnAccountsUpdatedListener:将 OnAccountsUpdateListener 侦听器添加到 AccountManager 对象。无论设备上的帐号列表何时发生变化,系统都将调用此侦听器。

Android 8.0 引入两个特殊的软件包名称值,以使用 setAccountVisibility 函数指定未设置的应用的可见性级别。PACKAGE_NAME_KEY_LEGACY_VISIBLE 可见性值应用于具有 GET_ACCOUNTS 权限的应用,并且其目标 Android 版本低于 Android 8.0,或其签名与针对任意 Android 版本的身份验证器匹配。PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE 为之前未设置的应用提供默认的可见性值,对于此类应用,PACKAGE_NAME_KEY_LEGACY_VISIBLE 不适用。

Google Safe Browsing API

WebView 类现在添加了一个 Safe Browsing API 来增强网络浏览的安全性。通过使用 Safe Browsing API 的 WebView 实现,您的应用可以在 WebView 实例尝试转到 Google 已归类为已知威胁的网址时检测到该行为。WebView 默认会显示一个插页,以警告用户存在已知威胁。通过该界面,用户可以选择仍然加载网址或返回到上一个安全的页面。

Android 9.0

Android 9.0是谷歌研发的移动端操作系统,开发代号为“Pie”(派),于2018年8月7日正式发布

1.利用wifi RTT 进行室内定位

Android 9 添加了对 IEEE 802.11mc Wi-Fi 协议(也称为 Wi-Fi Round-Trip-Time (RTT))的平台支持,从而让您的应用可以利用室内定位功能。

在运行 Android 9 且具有硬件支持的设备上,应用可以使用 RTT API 来测量与附近支持 RTT 的 Wi-Fi 接入点 (AP) 的距离。 设备必须已启用位置服务并开启 Wi-Fi 扫描(在 Settings > Location 下),同时您的应用必须具有 ACCESS_FINE_LOCATION 权限。

设备无需连接到接入点即可使用 RTT。 为了保护隐私,只有手机可以确定与接入点的距离;接入点无此信息。

如果您的设备测量与 3 个或更多接入点的距离,您可以使用一个多点定位算法来预估与这些测量值最相符的设备位置。 结果通常精准至 1 至 2 米。

通过这种精确性,您可以打造新的体验,例如楼内导航、基于精细位置的服务,如无歧义语音控制(例如,“打开这盏灯”),以及基于位置的信息(如 “此产品是否有特别优惠?”)。

2.显示屏缺口支持

Android 9 支持最新的全面屏,其中包含为摄像头和扬声器预留空间的屏幕缺口。 通过 DisplayCutout 类可确定非功能区域的位置和形状,这些区域不应显示内容。 要确定这些屏幕缺口区域是否存在及其位置,请使用 getDisplayCutout() 函数。

全新的窗口布局属性 layoutInDisplayCutoutMode 让您的应用可以为设备屏幕缺口周围的内容进行布局。 您可以将此属性设为下列值之一:
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
可以按以下方法在任何运行 Android 9 的设备或模拟器上模拟屏幕缺口:

启用开发者选项。
在 Developer options 屏幕中,向下滚动至 Drawing 部分并选择 Simulate a display with a cutout。
选择屏幕缺口的大小。
注:我们建议您通过使用运行 Android 9 的设备或模拟器测试屏幕缺口周围的内容显示。

3.前台服务

如果应用以 Android 9 或更高版本为目标平台并使用前台服务,则必须请求 FOREGROUND_SERVICE 权限。这是普通权限,因此,系统会自动为请求权限的应用授予此权限。

如果以 Android 9 或更高版本为目标平台的应用尝试创建前台服务且未请求 FOREGROUND_SERVICE,则系统会抛出
9.0 要求创建一个前台服务需要请求 FOREGROUND_SERVICE 权限,否则系统会引发 SecurityException。

Intent intentService = new Intent(this, MyService.class);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
    startForegroundService(intentService);//开启前台服务
} else {
    startService(intentService);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

PS:表忘记AndroidManifest.xml中添加FOREGROUND_SERVICE权限

//9.0这个前台服务权限不要忘了

4.启动Activity

在9.0 中,不能直接非 Activity 环境中(比如Service,Application)启动 Activity,否则会崩溃报错。
这类问题一般会在点击推送消息跳转页面这类场景,解决方法就是 Intent 中添加标志FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent(this, TestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
  • 1
  • 2
  • 3
5.Apache HTTP 客户端弃用

在 Android 6.0 时,就已经取消了对 Apache HTTP 客户端的支持。从 Android 9.0 开始,默认情况下该库已从 bootclasspath 中移除。但是耐不住有些SDK中还在使用,比如我见到的友盟QQ分享报错问题。
所以要想继续使用Apache HTTP,需要在应用的 AndroidManifest.xml 文件中添加:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyGitignore">

<uses-library android:name="org.apache.http.legacy" android:required="false"/>//使用这个
<application/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
6.多进程使用WebView时不支持同时从多个进程使用具有相同数据目录的WebView
7.安全增强功能

Android 9 引入了若干安全功能,详见以下各节摘要说明:

Android Protected Confirmation

运行 Android 9 或更高版本的受支持设备赋予您使用 Android Protected Confirmation 的能力。 使用该工作流时,您的应用会向用户显示提示,请他们批准一个简短的声明。 应用可以通过这个声明再次确认,用户确实想完成一项敏感事务,例如付款。

如果用户接受该声明,Android 密钥库会收到并存储由密钥哈希消息身份验证代码 (HMAC) 保护的加密签名。 Android 密钥库确认消息的有效性之后,您的应用可以使用在可信执行环境 (TEE) 下通过 trustedConfirmationRequired 生成的密钥来签署用户已接受的消息。 该签名具有很高的可信度,它表示用户已看过声明并同意其内容。

统一生物识别身份验证对话框

在 Android 9 中,系统代表您的应用提供生物识别身份验证对话框。 该功能可创建标准化的对话框外观、风格和位置,让用户更加确信,他们在使用可信的生物识别凭据检查程序进行身份验证。

如果您的应用使用 FingerprintManager向用户显示指纹身份验证对话框,请切换到改用 BiometricPromptBiometricPrompt 依赖系统来显示身份验证对话框。 它还会改变其行为,以适应用户所选择的生物识别身份验证类型。

硬件安全性模块

运行 Android 9 或更高版本的受支持设备可拥有 StrongBox Keymaster,它是位于硬件安全性模块中的 Keymaster HAL 的一种实现。 该模块包含以下组成部分:

  • 自己的 CPU。
  • 安全存储空间。
  • 真实随机数生成器。
  • 可抵御软件包篡改和未经授权线刷应用的附加机制。

检查存储在 StrongBox Keymaster 中的密钥时,系统会通过可信执行环境 (TEE) 证实密钥的完整性。

保护对密钥库进行的密钥导入

Android 9 通过利用 ASN.1‑编码密钥格式将已加密密钥安全导入密钥库的功能,提高了密钥解密的安全性。 Keymaster 随后会在密钥库中将密钥解密,因此密钥的内容永远不会以明文形式出现在设备的主机内存中。

具有密钥轮转的 APK 签名方案

Android 9 新增了对 APK Signature Scheme v3 的支持。该架构提供的选择可以在其签名块中为每个签名证书加入一条轮转证据记录。 利用此功能,应用可以通过将 APK 文件过去的签名证书链接到现在签署应用时使用的证书,从而使用新签名证书来签署应用。

只允许在未锁定设备上进行密钥解密的选项

Android 9 引入了 unlockedDeviceRequired 标志。 此选项确定在允许使用指定密钥对任何正在传输或存储的数据进行解密之前,密钥库是否要求屏幕解锁。 这些类型的密钥非常适合用于加密要存储在磁盘上的敏感数据,例如健康或企业数据。 该标志为用户提供了更高的保证,即使手机丢失或被盗,在设备锁定的情况下,无法对数据进行解密。

默认启用网络传输层安全协议 (TLS)

如果您的应用以 Android 9 或更高版本为目标平台,则 isCleartextTrafficPermitted方法默认返回 false。如果您的应用需要针对特定网域启用明文,则您必须在应用的网络安全配置中,针对这些网域明确将 cleartextTrafficPermitted 设置为 true

按进程分设基于网络的数据目录

在 Android 9 中,为改善应用稳定性和数据完整性,应用无法再让多个进程共享一个 WebView数据目录。通常情况下,此类数据目录会存储 Cookie、HTTP 缓存以及其他与网络浏览有关的持久性和临时性存储。

按应用划分的 SELinux 域

以 Android 9 或更高版本为目标平台的应用无法使用所有人都可访问的 Unix 权限与其他应用共享数据。这项变更可提高 Android 应用沙盒的完整性,尤其是对于应用的私有数据仅能由相应应用访问这一要求而言。

Android 10

Android 10包含多项功能升级,包括手势导航、通知栏管理、全局黑暗模式等等,通知管理新增了“优先”、“无声”和“自适应通知”三种功能,新增深色主题的背景

1.用户存储权限的变更

Android Q 在外部存储设备中为每个应用提供了一个“隔离存储沙盒”(例如 /sdcard)。任何其他应用都无法直接访问您应用的沙盒文件。由于文件是您应用的私有文件,因此您不再需要任何权限即可在外部存储设备中访问和保存自己的文件。此变更可让您更轻松地保证用户文件的隐私性,并有助于减少应用所需的权限数量。
谷歌官方推荐应用在沙盒内存储文件的地址为Context.getExternalFilesDir()下的文件夹。比如要存储一张图片,则应放在Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)中。

2.用户的定位权限的变更

为了让用户更好地控制应用对位置信息的访问权限,Android Q 引入了新的位置权限 ACCESS_BACKGROUND_LOCATION。

与现有的 ACCESS_FINE_LOCATION和 ACCESS_COARSE_LOCATION权限不同,新权限仅会影响应用在后台运行时对位置信息的访问权。除非应用的某个 Activity 可见或应用正在运行前台服务,否则应用将被视为在后台运行。
与iOS系统一样,Q中也加入了后台位置权限ACCESS_BACKGROUND_LOCATION,如果应用需要在后台时也获得用户位置(比如滴滴),就需要动态申请ACCESS_BACKGROUND_LOCATION权限。

当然如果不需要的话,应用就无需任何改动,且谷歌会按照应用的targetSDK作出不同处理:
targetSDK <= P 应用如果请求了ACCESS_FINE_LOCATION或 ACCESS_COARSE_LOCATION权限,Q设备会自动帮你申请ACCESS_BACKGROUND_LOCATION权限。

3.设备唯一标识符的变更

从 Android Q 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE签名权限才能访问设备的不可重置标识符(包含 IMEI 和序列号)。
如果您的应用没有该权限,但您仍尝试查询标识符的相关信息,会返回空值或报错。
设备唯一标识符需要特别注意,原来的READ_PHONE_STATE权限已经不能获得IMEI和序列。
如果想在Q设备上通过使用以下代码获取设备的ID

((TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()
  • 1

则执行以上代码会返回空值(targetSDK<=P)或者报错(targetSDK==Q)。且官方所说的READ_PRIVILEGED_PHONE_STATE权限只提供给系统app,所以这个方法行不通了。
谷歌官方给予了设备唯一ID最佳做法,但是此方法给出的ID可变,可以按照具体需求具体解决。本文给出一个不变和基本不重复的UUID方法:

public static String getUUID() {
    String serial = null;
    String m_szDevIDShort = "35" +
        Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +
        Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 +
        Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 +
        Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 +
        Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 +
        Build.TAGS.length() % 10 + Build.TYPE.length() % 10 +
        Build.USER.length() % 10; //13 位
try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            serial = android.os.Build.getSerial();
        } else {
            serial = Build.SERIAL;
        }
        //API>=9 使用serial号
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        //serial需要一个初始化
        serial = "serial"; // 随便一个初始化
  }
//使用硬件信息拼凑出来的15位号码
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
4.加密

存储加密是最基本(也是最有效的)安全技术之一,但目前的加密标准要求设备具有加密加速硬件。由于此要求,许多设备无法使用存储加密。Adiantum的推出改变了Android Q版本中的这一点。我们在二月份宣布了Adiantum。Adiantum旨在无需专用硬件即可高效运行,并且可以在从智能手表到互联网连接医疗设备的所有方面工作。

5.平台强化

Android 采用纵深防御策略,确保单个实现错误不足以绕过我们的安全系统。我们应用进程隔离、攻击面减少、架构分解和漏洞利用缓解措施,使漏洞更难或更不可能被利用,并增加攻击者实现其目标所需的漏洞数量。

在 Android Q 中,我们将这些策略应用于媒体、蓝牙和内核等安全关键领域:

  • 软件编解码器的受约束沙盒。
  • 提高了清理程序的生产使用率,以缓解处理不可信内容的组件中的整类漏洞。
  • 影子调用堆栈,它提供后向边缘控制流完整性 (CFI),并补充 LLVM 的 CFI 提供的前沿保护。
  • 使用仅异指令内存 (XOM) 保护地址空间布局随机化 (ASLR) 免受泄漏。
  • 引入Scudo强化分配器,这使得许多与堆相关的漏洞更难利用。
6.认证

Android Pie 引入了 BiometricPrompt API 来帮助应用利用生物识别技术,包括面部、指纹和虹膜。自推出以来,我们看到许多应用程序都采用了新的API,现在在Android Q中,我们已经更新了底层框架,对面部和指纹提供了强大的支持。此外,我们还扩展了 API 以支持其他用例,包括隐式和显式身份验证。

7.隐私权限

Android 10 引入了大量隐私权限变更(如改进了系统界面、让权限授予更加严格以及对应用能够使用哪些数据实施了限制),目的是保护隐私权并赋予用户控制权。

Android 11

Android 11正式版系统在2020年9月9日正式发布。系统主要增强了聊天气泡,安全性和隐私性的保护,电源菜单,可以更好的支持瀑布屏,折叠屏,双屏和 Vulkan 扩展程序等。
新特性

1.短信更新改进

首先是聊天泡泡。与Facebook多年来在Android上提供的Messenger应用程序类似,Android 11优化了短信功能,提供更加友好的交互。同时,为了确保用户能尽快收到对方的消息,Android 11在通知阴影(Notification Shade)中引入了一个专门的对话部分,它将提供对用户正在进行的任何对话的即时访问。这一更新将有助于短信消息从其他通知中脱颖而出。

2.电话号码相关权限

Android 11 更改了您的应用在读取电话号码时使用的与电话相关的权限。

其实就是两个API:
TelecomManager 类中的 getLine1Number() 方法
TelecomManager 类中的 getMsisdn() 方法

也就是当用到这两个API的时候,原来的READ_PHONE_STATE权限不管用了,需要READ_PHONE_NUMBERS权限才行。

3.现在需要 APK 签名方案 v2

对于以 Android 11(API 级别 30)为目标平台,且目前仅使用 APK 签名方案 v1 签名的应用,现在还必须使用 APK 签名方案 v2 或更高版本进行签名。用户无法在搭载 Android 11 的设备上安装或更新仅通过 APK 签名方案 v1 签名的应用。

如果你的targetSdkVersion修改到30,那么你就必须要加上v2签名才行。否则无法安装和更新。

4安全性
SSL 套接字默认情况下使用 Conscrypt SSL 引擎

Android 的默认 SSLSocket 实现基于 Conscrypt。从 Android 11 开始,该实现是在 Conscrypt 的 SSLEngine 之上内部构建的。

Scudo Hardened Allocator

Android 11 在内部使用 Scudo Hardened Allocator 为堆分配提供服务。Scudo 能够检测并减轻某些类型的内存安全违规行为。

应用使用情况统计信息

为了更好地保护用户,Android 11 将每个用户的应用使用情况统计信息存储在凭据加密存储空间中。因此,系统和任何应用都无法访问该数据,除非 isUserUnlocked() 返回 true,这发生在出现以下某种情况之后:

  • 用户在系统启动后首次解锁其设备。
  • 用户在设备上切换到自己的帐号。

如果您的应用已绑定到 UsageStatsManager 的实例,请检查您是否是在用户解锁其设备后在此对象上调用方法。如果并非如此,该 API 现在会返回 null 或空值。

生物识别身份验证机制更新

为了帮助您控制应用数据的安全级别,Android 11 对生物识别身份验证机制进行了多项改进。

Android 11 引入了 BiometricManager.Authenticators 接口,可用于声明您的应用支持的身份验证类型。在用户进行身份验证后,您可以通过调用 getAuthenticationType() 检查用户是使用设备凭据还是生物识别凭据进行的身份验证。

Android 11 弃用了以下方法:

  • setDeviceCredentialAllowed() 方法。
  • setUserAuthenticationValidityDurationSeconds() 方法。
  • 不带任何参数的 canAuthenticate() 过载版本。
安全共享大型数据集

在某些情况下,例如涉及机器学习或媒体播放时,您的应用可能需要与其他应用使用同一个大型数据集。在较早的 Android 版本中,您的应用与其他应用需要各自单独下载该数据集。为帮助减少网络中和磁盘上的数据冗余,Android 11 允许使用共享数据 blob 在设备上缓存这些大型数据集。

因 OTA 更新而重启设备后在未提供用户凭据的情况下执行文件级加密

设备完成 OTA 更新并重启后,放在受凭据保护的存储空间中的凭据加密 (CE) 密钥可立即用于执行文件级加密 (FBE) 操作。这意味着,完成 OTA 更新后,您的应用可以在用户输入其 PIN 码、解锁图案或密码之前恢复需要 CE 密钥的操作。

5.隐私权限变更

Android 11 基于 Android 早期版本构建,增加了多种功能和更新,以保障用户安全并提高透明度和可控性。所有开发者都应查看隐私功能并测试他们的应用。具体影响可能会因每个应用的核心功能、目标平台和其他因素而异。

Android 12

Android 12 重新发现了代号为 “Columbus”的功能,并且优化了触发问题,新的手势需要更加用力敲击背面。新的双击背面手势可以截取屏幕截图、召唤谷歌 Assistant、打开通知栏、控制媒体播放或打开最近的应用程序列表。

1.AVIF图像支持

为了为您提供更高的图像质量和更有效的压缩,Android 12引入了对AV1图像文件格式(AVIF)的平台支持。AVIF是用于使用AV1编码的图像和图像序列的容器格式。与其他现代图像格式一样,AVIF利用了视频压缩中的帧内编码内容。与JPEG等较旧的图像格式相比,这可以显着提高相同文件大小的图像质量。
AVIF(18.2kB)JPEG(20.7kB)

2.前台服务优化

前台服务是应用程序管理某些类型的面向用户任务的重要方式,但是如果过度使用,它们可能会影响性能,甚至导致应用程序中断。为了确保为用户带来更好的体验,对于以新平台为目标的应用,我们将从后台阻止前台服务启动。为了更轻松地从此模式过渡,我们在JobScheduler中引入了一个新的加急作业,该作业获得了较高的进程优先级,网络访问权限,并且可以在不考虑节电或节电的情况下立即运行。为了实现向后兼容,我们还在最新版本的Jetpack WorkManager库中内置了加急作业。。另外,为了减少用户的注意力,我们现在将某些前台服务通知的显示延迟最多10秒钟。这使短暂的任务有机会在显示通知之前完成

3.麦克风和相机指示器和开关

在Android 12中,由于手机状态栏中的新指示器,您可以查看应用程序何时使用麦克风或相机。如果您不希望任何应用程序访问您的麦克风或相机,您可以在快速设置中使用两个新开关完全禁用这些传感器。只需翻转开关即可。

4.大致位置权限

虽然一些应用程序需要精确的位置信息来完成逐向导航等任务,但许多其他应用程序只需要您的大致位置即可提供帮助。在Android 12中,您可以在让应用程序访问您的精确位置或大致位置之间进行选择。

如果您的应用请求 ACCESS_FINE_LOCATION 运行时权限,您还应请求 ACCESS_COARSE_LOCATION 权限,以便处理用户授予应用大致位置访问权限的情形。您应该在单个运行时请求中包含这两项权限。

5.权限软件包可见性

在搭载 Android 12 或更高版本的设备上,根据应用对其他应用的软件包可见性,以 Android 11(API 级别 30)或更高版本为目标平台且调用以下某种方法的应用会收到一组过滤后的结果:

  • getAllPermissionGroups()
  • getPermissionGroupInfo()
  • getPermissionInfo()
  • queryPermissionsByGroup()
6.剪贴板访问通知

在 Android 12 及更高版本中,当某个应用首次调用 getPrimaryClip()从另一个应用访问剪辑数据时,会弹出一个消息框消息,通知用户对剪贴板的访问。

7.安全和隐私设置
隐私信息中心

在搭载 Android 12 或更高版本的受支持设备上,系统设置中会显示“隐私信息中心”屏幕。在此屏幕上,用户可以访问一些单独的屏幕,这些屏幕显示了应用何时访问位置信息、相机和麦克风信息。每个屏幕都会显示一个时间轴,指明不同的应用何时访问过特定类型的数据。

权限组查找

在 Android 12 或更高版本中,您可以查询系统将平台提供的权限组织到权限组中的方式:

  • 如需确定系统在其中分配平台定义的权限的权限组,请调用 [getGroupOfPlatformPermission()](https://developer.android.google.cn/reference/android/content/pm/PackageManager#getGroupOfPlatformPermission(java.lang.String, java.util.concurrent.Executor, java.util.function.Consumer))。
  • 如需确定系统向特定权限组授予的平台定义的权限,请调用 [getPlatformPermissionsForGroup()](https://developer.android.google.cn/reference/android/content/pm/PackageManager#getPlatformPermissionsForGroup(java.lang.String, java.util.concurrent.Executor, java.util.function.Consumer>))。
隐藏应用叠加窗口

为了让开发者能够更好地控制用户在与开发者的应用互动时会看到什么内容,Android 12 引入了隐藏由具有 SYSTEM_ALERT_WINDOW 权限的应用绘制的叠加窗口的功能。

声明 HIDE_OVERLAY_WINDOWS 权限后,应用可以调用 setHideOverlayWindows() 以指明当应用自己的窗口可见时所有 TYPE_APPLICATION_OVERLAY 类型的窗口都应隐藏。在显示敏感屏幕(如交易确认流程)时,应用可能会选择这样做。

显示 TYPE_APPLICATION_OVERLAY 类型窗口的应用应考虑可能更适合其用例的替代方案,如画中画气泡

已知签名者权限保护标志

从 Android 12 开始,签名级权限knownCerts 属性可让您在声明时引用已知签名证书的摘要。

您的应用可以声明此属性并使用 knownSigner 标志,以使设备和应用向其他应用授予签名权限,而不必在设备制造和发货时对应用进行签名。

安全锁定屏幕通知操作

从 Android 12 开始,Notification.Action.Builder 类支持 setAuthenticationRequired() 方法,这使您的应用可以在调用指定的通知操作前要求必须解锁设备。此方法有助于为锁定设备上的通知添加一道额外的安全保障。

BiometricPrompt 的可本地化字符串

Android 12 引入了新的 API 来帮助您改进应用的生物识别身份验证用户体验。新的 BiometricManager.Strings 嵌套类包括 getButtonLabel()getPromptMessage()getSettingName() 方法,让您的应用可以检索用户可读的本地化按钮标签、提示消息或应用设置名称。使用这些标签可以创建更精确的面向用户且特定于所使用的生物识别身份验证方法的指令,例如“使用人脸解锁”或“使用指纹继续操作”。

WebView 中的现代 SameSite Cookie

Android 的 WebView 组件基于为 Google 的 Chrome 浏览器提供支持的开源项目 Chromium。Chromium 变更了对第三方 Cookie 的处理方式,目的是为了更好地保护用户的安全和隐私,并赋予用户更高的透明度和控制权。从 Android 12 开始,当应用以 Android 12(API 级别 31)或更高版本为目标平台时,WebView 中也会包含这些变更。

Cookie 的 SameSite 属性决定了它是可以与任何请求一起发送,还是只能与同站点请求一起发送。以下隐私保护方面的变更改善了对第三方 Cookie 的默认处理方式,并可帮助防止意外跨站点共享:

  • 没有 SameSite 属性的 Cookie 被视为 SameSite=Lax
  • 带有 SameSite=None 的 Cookie 还必须指定 Secure 属性,这意味着它们需要安全的上下文,并应通过 HTTPS 发送。
  • 站点的 HTTP 版本和 HTTPS 版本之间的链接现在被视为跨站点请求,因此除非将 Cookie 正确标记为 SameSite=None; Secure,否则 Cookie 不会被发送。

对于开发者而言,一般指导意见是识别关键用户流中的跨站点 Cookie 依赖项,并确保在需要时使用适当的值显式设置 SameSite 属性。您必须显式指定允许在不同网站上运行的 Cookie,或适用于从 HTTP 切换到 HTTPS 进行同站点导航的 Cookie。

数据访问审核中的归因声明

在 Android 11(API 级别 30)中引入的数据访问审核 API 可让您根据应用的用例创建归因标记。这些标记可让您更轻松地确定应用的哪一部分执行特定类型的数据访问。如果您的应用以 Android 12 或更高版本为目标平台,您必须在应用的清单文件中声明这些归因标记

ADB 备份限制

为了保护私有应用数据,Android 12 变更了 adb backup 命令的默认行为。对于以 Android 12(API 级别 31)或更高版本为目标平台的应用,用户运行 adb backup 命令时,从设备导出的任何其他系统数据都不包含应用数据。

如果您的测试或开发工作流程依赖于使用 adb backup 的应用数据,现在您可以选择通过在应用的清单文件中将 android:debuggable 设置为 true 来导出应用数据。为了帮助保护应用数据,请务必在发布应用前将 android:debuggable 设置为 false

更安全的组件导出

如果您的应用以 Android 12 或更高版本为目标平台,且包含使用 intent 过滤器activity服务广播接收器,您必须为这些应用组件显式声明 android:exported 属性。如果 activity、服务或广播接收器使用 intent 过滤器,并且未显式声明 android:exported 的值,您的应用将无法在搭载 Android 12 或更高版本的设备上进行安装。如果应用组件包含 LAUNCHER 类别,请将 android:exported 设置为 true。在大多数其他情况下,请将 android:exported 设置为 false

不安全的 intent 启动

为了提高平台安全性,Android 12 及更高版本提供了一种调试功能,用于检测不安全的 intent 启动。当系统检测到此类不安全的启动时,就会发生 StrictMode 违反事件。

Android13

1.智能家居控制

在安卓 13 中,控制智能家居不需要解锁手机。进行了相关设置后,锁屏界面即可切换到智能家居的开关。不过该选项会默认关闭,以保护隐私和安全。

2.新的照片选择器

在安卓 13 中选择照片,会调用安卓系统本身的组件来读取照片,而不是调用第三方 App。这个特性不仅仅会在安卓 13 中出现,谷歌会将其放置到 Play 商店中,向安卓 11 和安卓 12 设备推送。

3.附近 WiFi 权限

在以前的 Android 版本中,用户需要向您的应用授予 ACCESS_FINE_LOCATION 权限,应用才能完成与热点相关的多个常见 Wi-Fi 用例、Wi-Fi 直连、Wi-Fi RTT 等。

由于用户很难将位置信息权限与 Wi-Fi 功能相关联,因此 Android 13 在 NEARBY_DEVICES 权限组中引入了新的运行时权限,适用于管理设备与附近 Wi-Fi 接入点连接情况的应用。此权限 (NEARBY_WIFI_DEVICES) 可满足这些 Wi-Fi 用例。

只要您的应用不会通过 Wi-Fi API 推导物理位置,那么当您以 Android 13 或更高版本为目标平台并使用 Wi-Fi API 时,就可以请求 NEARBY_WIFI_DEVICES 而不是 ACCESS_FINE_LOCATION

4.通知权限

安卓 13 当中,某个 App 如果想要发出通知,需要用户授权。如此一来,App 乱发通知的情况会得到遏制。

5.存储媒体权限

安卓 12 中,App 想要访问存储在本地的媒体文件,需要发出请求许可,用户授权 READ_EXTERNAL_STORAGE 权限后,App 就可以访问各种媒体,而不仅仅是特定媒体。但在安卓 13 中,用户需要为不同的存储媒体授权,例如可以为音乐播放器只授予访问音频媒体的权限。

6.intent 过滤器会屏蔽不匹配的 intent

当您的应用向以 Android 13 或更高版本为目标平台的其他应用的导出组件发送 intent 时,仅当该 intent 与接收应用中的 <intent-filter> 元素匹配时,系统才会传送该 intent。换言之,系统会屏蔽所有不匹配的 intent,但以下情况除外:

  • 发送给其他应用的未声明任何 intent 过滤器的组件的 intent。
  • 发送给您应用中的其他组件的 intent。
  • 由系统发送的 intent。
  • 由具有根级特权的用户发送的 intent。
7.更安全地导出上下文注册的接收器

为了帮助提高运行时接收器的安全性,Android 13 允许您指定您应用中的特定广播接收器是否应被导出以及是否对设备上的其他应用可见。如果导出广播接收器,其他应用将可以向您的应用发送不受保护的广播。此导出配置在以 Android 13 或更高版本为目标平台的应用中可用,有助于防止一个主要的应用漏洞来源。

在以前的 Android 版本中,设备上的任何应用都可以向动态注册的接收器发送不受保护的广播,除非该接收器受签名权限的保护。

要实现此安全增强措施,请执行以下操作:

  1. 启用 DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED 兼容性框架更改。
  2. 在应用的每个广播接收器中,明确指明其他应用是否可以向其发送广播,如以下代码段所示:
// This broadcast receiver should be able to receive broadcasts from other apps.
// This option causes the same behavior as setting the broadcast receiver's
// "exported" attribute to true in your app's manifest.
context.registerReceiver(sharedBroadcastReceiver, intentFilter,
    RECEIVER_EXPORTED);

// For app safety reasons, this private broadcast receiver should **NOT**
// be able to receive broadcasts from other apps.
context.registerReceiver(privateBroadcastReceiver, intentFilter,
    RECEIVER_NOT_EXPORTED);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Android 14

对隐式intent和待处理intent的限制

对于以 Android 14 为目标平台的应用,Android 会通过以下方式限制应用向内部应用组件发送隐式 intent:

  • 隐式 intent 只能传送到导出的组件。应用必须使用显式 intent 传送到未导出的组件,或将该组件标记为已导出。
  • 如果应用通过未指定组件或软件包的 intent 创建可变待处理 intent,系统现在会抛出异常。

这些变更可防止恶意应用拦截意在供应用内部组件使用的隐式 intent。

例如,下面是可以在应用清单文件中盛名的intent过滤器:

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果应用尝试使用隐式intent启动activity,系统会抛出异常:

// Throws an exception when targeting Android 14.
context.startActivity(new Intent("com.example.action.APP_ACTION"));
  • 1
  • 2

如需启动非导出activity,应用需改用显式intent:

// This makes the intent explicit.
Intent explicitIntent =
        new Intent("com.example.action.APP_ACTION")
explicitIntent.setPackage(context.getPackageName());
context.startActivity(explicitIntent);
  • 1
  • 2
  • 3
  • 4
  • 5
在运行时注册的广播接受器必须指定导出行为

以Android14为目标平台并使用上下文注册的接收器的应用和服务必须指定标识,以指明接收器是否应导出到设备上的所有其他应用。

标识:RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED

仅接收系统广播的接收器的例外情况

如果您的应用仅通过 Context#registerReceiver 方法(例如 [Context#registerReceiver()])针对系统广播注册接收器,那么它在注册接收器时不应指定标志。

更加安全的动态代码加载

如果应用以 Android 14 为目标平台并使用动态代码加载 (DCL) 功能,则必须将所有动态加载的文件标记为只读。否则,系统会抛出异常。

如果必须动态加载代码,可参考官方提供Demo,在动态文件打开并写入任何内容之前立即将其设为只读:

File jar = new File("DYNAMICALLY_LOADED_FILE.jar");
try (FileOutputStream os = new FileOutputStream(jar)) {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly();
    // Then write the actual file content
} catch (IOException e) { ... }
PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

为防止系统对现有动态加载的文件抛出异常,建议先删除并重新创建文件,然后再尝试在应用中重新动态加载这些文件。重新创建文件时,请按照上述指南在写入时将文件标记为只读。或者,可以将现有文件重新标记为只读,但在这种情况下,建议先验证文件的完整性(例如,对照可信值检查文件的签名)以保护应用免遭恶意操作的影响。

压缩路径遍历

对于以 Android 14 为目标平台的应用,Android 会通过以下方式防止 Zip 路径遍历漏洞:如果 Zip 文件条目名称包含“…”或以“/”开头,ZIPFile(String)和ZipInputStream.getNextEntry()会抛出ZipException。

应用可以通过调用dalvik.system.ZipPathValidator.clearCallback() 选择停用此验证。

针对从后台启动 activity 的其他限制

对于以 Android 14 为目标平台的应用,系统会进一步限制允许应用在后台启动 activity 的时间:

当应用使用 PendingIntent#send() 或类似方法发送 PendingIntent 时,如果它想要授予自己的后台 activity 启动待处理 intent 的启动特权,则必须选择启用。如需选择启用,应用应通过 setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED) 传递 ActivityOptions 软件包。
当可见应用使用 bindService() 方法绑定其他在后台应用的服务时,如果可见应用想要授予自己的后台 activity 对绑定服务的启动特权,则必须选择启用。如需选择启用,应用应在调用 bindService() 方法时包含 BIND_ALLOW_ACTIVITY_STARTS 标志。
这些更改扩大了一组现有限制条件的范围,目的是防止恶意应用滥用 API 以在后台启动干扰性活动,从而保护用户。

应用只能终止自己的后台进程

从 Android 14 开始,当您的应用调用 killBackgroundProcesses() 时,该 API 只能终止您自己应用的后台进程。

如果您传入另一个应用的软件包名称,此方法对该应用的后台进程没有影响,并且 Logcat 中会显示以下消息:

Invalid packageName: com.example.anotherapp
  • 1

Android 旨在让缓存应用在后台运行,并在系统需要内存时自动终止它们。

最低可安装的目标 API 级别

从 Android 14 开始,targetSdkVersion 低于 23 的应用无法安装。要求应用满足这些最低目标 API 级别要求有助于提高用户的安全性和隐私性。

恶意软件通常会以较旧的 API 级别为目标平台,以绕过在较新版本 Android 中引入的安全和隐私保护机制。例如,有些恶意软件应用使用 targetSdkVersion 22,以避免受到 Android 6.0 Marshmallow(API 级别 23)在 2015 年引入的运行时权限模型的约束。

在升级到Android 14的设备上,targetSdkVersion 低于 23 的所有应用都将继续保持安装状态。如果需要测试以旧版API级别的应用,可使用如下adb命令:

adb install --bypass-low-target-sdk-block FILENAME.apk
  • 1

可能有用的官方地址

针对非 SDK 接口的限制:https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces?hl=zh-cn

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/228059
推荐阅读
相关标签
  

闽ICP备14008679号