在前几天的Google I/O 2019大会上,发布了Android Q版本(Android 10)。Android Q带来了许多新特性,也增强安全隐私保护,包括支持折叠屏、非SDK接口限制、共享内存、分区存储、系统二进制文件映射到只执行内存、WLAN直连广播、全屏Intent的权限变更、夜间主题模式等等。
1、非SDK接口限制
为了确保应用稳定性与兼容性,Android平台开始限制我们的应用可在Android 9以上使用哪些非 SDK 接口。Android Q包含更新后的受限非SDK接口列表。目前我们还可以使用灰名单来访问非SDK接口,但如果使用任何非SDK方法或字段,可能会导致应用程序无法运行(通过反射机制来访问SDK方法或字段将会失效)。
2、共享内存
Ashmem修改了/proc/ASharedMemory
类来访问共享内存。另外,应用无法对现有的Ashmem文件描述符进行IOCTL,必须改为NDK的ASharedMemory类或者Android Java API来创建共享内存区域。这个变更可以提高访问共享内存的安全性与稳定性。
3、支持折叠屏
Android Q包含可折叠屏和大屏设备。当应用在Android Q平台运行时,onResume()和onPause()方法的工作原理是不同的。当多个应用同时在多窗口或多显示屏模式下显示时,可见堆栈中所有可设置为焦点的顶层Activity都处于“已恢复”状态,但实际上焦点仅位于其中一个Activity。在Android Q之前版本运行时,一次只能恢复系统中的一个Activity,而所有其他可见Activity都处于暂停状态。
在Android Q中,我们可以订阅onTopResumedActivityChanged()回调,以便在Activity获取或失去最顶层处于恢复状态的位置后收到通知。
resizeableActivity
清单属性的行为也发生了变化。如果设置了resizeableActivity=false,但没有设置固定屏幕方向或者宽高比,则屏幕尺寸、屏幕方向变化会导致应用调整大小以占满整个屏幕。如果设置了resizeableActivity=false,也设置固定屏幕方向或宽高比,那么屏幕发生变化后,应用会显示黑边并调整大小以保持相应的宽高比。如果设置为resizeableActivity=true,应用会保持原样,并调整大小。
应用可以声明 1:1 的宽高比,并且可以使用新属性 android:minAspectRatio
4、系统二进制文件映射到只执行内存
从Android Q开始,系统二进制文件和库会映射到只执行(不可读取)内存中,作为应对代码重用攻击的安全强化技术。如果读入已标记为只执行的内存段会抛出SIGSEGV异常,无论此读入行为来自错误、漏洞或内存自省都不例外。我们可以通过检查/data/tombstones/的tombstones文件来确定崩溃是否由更改所导致。崩溃消息:
Cause: execute-only (no-read) memory access error; likely due to data in .text.
要解决此问题,我们可以调用mprotect()将只执行内存段标记为“读取+执行”,例如用于内存执行检查。但是,Google官方建议我们,保留为只执行属性。
5、SYSTEM_ALERT_WINDOW弹窗
在Android Q设备上运行的应用无法获取SYSTEM_ALERT_WINDOW
权限。这是因为绘制叠加层窗口使用过多内存,这对于低内存设备十分不利。如果应用发送具有ACTION_MANAGE_OVERLAY_PERMISSION的Intent请求,则系统默认拒绝此请求,并将用户转到设置屏幕,显示不允许授予此权限,因为它降低设备速度。
6、全局夜间主题模式(Dark Theme)
从Android Q开始,用户可通过以下三种途径激活新的全局夜间模式:
(1)点击设置,进入显示;
(2)新的快捷设置;
(3)启动省电模式;
在夜间模式下,系统界面会变暗,而提供支持的应用也会同时启用夜间模式。我们可为应用开发专属的夜间主题,或者开启"强制变暗"(Force Dark)功能,让操作系统为现有主题重新创建一个夜间版本。我们只需要在应用的当前主题内设置android:forceDarkAllowed="true"即可。
7、WLAN直连广播
在Android Q中,与 WLAN 直连相关的广播不再具有粘性:
WIFI_P2P_CONNECTION_CHANGED_ACTION
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
如果需要用到这些广播,请在初始化时用get()方法获取。
8、全屏Intent的权限变更
使用全屏Intent的应用,必须在其应用的清单文件中请求 USE_FULL_SCREEN_INTENT
权限。如果没声明USE_FULL_SCREEN_INTENT
,则系统会忽略此全屏 Intent 并输出以下日志消息:Package [pkg]: Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission。
9、分区存储
为了让用户更好地控制自己的文件,并限制文件出现混乱,Android更改了应用访问设备外部存储空间中文件的方式。Android Q用更精细的媒体特定权限来代替READ_EXTERNAL_STORAGE
和 WRITE_EXTERNAL_STORAGE权限,并且无需特定权限,应用即可访问自己在外部存储设备的文件。
对于每个应用,Android Q会创建一个"隔离存储沙盒"。应用可以将文件存储于自己沙盒中,也可以存储于媒体和下载内容的通用集合中。
10、Location位置权限
Android Q可让用户更好控制应用何时能够访问设备位置信息。当在Android Q上运行的应用请求位置访问权限时,会弹出图1对话框。此对话框可让用户将位置信息访问权限授予到两个不同的范围:在使用中(仅限前台)或始终(前台和后台)。
Android Q引入新的位置权限:ACCESS_BACKGROUND_LOCATION。与现有ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限不同的是,新权限仅会影响应用在后台运行时对位置信息的访问权。除非应用的某个 Activity 可见或应用正在运行前台服务,否则应用将被视为在后台运行。可用如下代码来检测位置权限:
boolean permissionAccessCoarseLocationApproved =
ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (permissionAccessCoarseLocationApproved) {
boolean backgroundLocationPermissionApproved =
ActivityCompat.checkSelfPermission(this,
permission.ACCESS_BACKGROUND_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (backgroundLocationPermissionApproved) {
// 可在前台和后台访问位置信息
} else {
// 只能在前台访问位置信息
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_BACKGROUND_LOCATION},
your-permission-request-code);
}
} else {
// 没有访问位置信息的权限,需要申请
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
},
your-permission-request-code);
}
11、后台Activity启动
Android Q对应用可启动Activity的事件作了限制。此变更能最大限度减少对用户的中断,并且可以让用户更好地控制屏幕显示的内容。在Android Q运行的应用,只有满足以下一个或多个条件才可以启动Activity:
PendingIntent
。示例包括发送菜单项待定 intent 的自定义标签页提供程序。PendingIntent
,例如点按通知。只有应用应启动界面的待定 intent 才可以免除。SECRET_CODE_ACTION
。只有应用应启动界面的特定广播才可以免除。几乎所有情况下,后台都应该创建通知以便向用户提供信息,而不是直接启动Activity。
12、数据和标识符变更
在Android Q中,对访问数据和系统标识符作了限制,包括:联系人亲密程度、随机选择MAC地址、访问/proc/net文件系统、访问USB串行设备需要用户授权等。
①联系人亲密程度
从Android Q开始,平台不再跟踪联系人的互动亲密程度。因此,我们的应用对用户的联系人进行搜索,系统不再按互动频率对搜索结果排序。
②随机选择MAC地址
默认情况下,Android Q设备会传输随机选择的MAC地址。新增了两个API:
getRandomizedMacAddress()
检索分配给特定网络的随机选择 MAC 地址。getWifiMacAddress()
检索设备的实际硬件 MAC 地址。此方法对于跟踪设备队列非常有用。③访问/proc/net文件系统
Android Q 撤消了 /proc/net
访问权限,其中包含有关设备网络状态的信息。需要访问此信息的应用(如 VPN)应引用 NetworkStatsManager
和 ConnectivityManager
类。
④访问USB串行设备需要用户授权
以 Android Q 为目标的平台,我们的应用只能在用户授予其访问 USB 设备或配件的权限后才能读取序列号。
13、网络权限变更
①访问所有相机信息都需要权限
Android Q 更改了 getCameraCharacteristics()
方法默认返回的信息的广度。具体而言就是,您的应用必须具有 CAMERA
权限才能访问此方法的返回值中可能包含的设备特定元数据。
②启动与停用WLAN的限制
在Android Q上运行的应用无法启用或停用WLAN。WifiManager.setWifiEnabled()方法始终会返回false。如果需要启用或停用WLAN,需要使用设置面板提示用户启用和停用 WLAN。
③WLAN网络配置限制
为了保护用户隐私,现在只能对手动配置系统的 WLAN 网络列表。如果您的应用以 Android Q 为目标平台,则下列方法将不再返回有用数据:
getConfiguredNetworks()
方法始终返回空列表。addNetwork()
和 updateNetwork()
)始终返回 -1。removeNetwork()
、reassociate()
、enableNetwork()
、disableNetwork()
、reconnect()
和 disconnect()
)始终返回 false
。如果应用程序需要连接到 WLAN 网络,请使用以下备用方法:
NetworkRequest
对象中使用 WifiNetworkSpecifier
。WifiManager.addNetworkSuggestions()
和 WifiManager.removeNetworkSuggestions()
添加和移除显示在自动连接网络选择对话框中的网络。这些方法不需要任何位置权限。