fix(android): gate the wifi read on ACCESS_WIFI_STATE, and declare it
Reported from the phone's diag log: status: crashed: SecurityException: WifiService: Neither user 10519 nor current process has android.permission.ACCESS_WIFI_STATE. at android.os.Parcel.createExceptionOrNull `PhoneSensors.wifiSsid` read `WifiManager.connectionInfo` behind nothing but the location grant, but WifiService gates every WifiManager call on ACCESS_WIFI_STATE — and it enforces that by throwing SecurityException, not by answering null. The permission was never declared, so the read always threw. The cost is larger than the missing SSID: the throw travels out of `readSnapshot` into the worker's catch, which logs "status: crashed" and returns failure — so one undeclared permission took the battery, network, DND and location topics down with it, and the fleet's rows went stale while the app looked healthy. Two halves, both needed: - the manifest declares ACCESS_WIFI_STATE (a normal permission: declaring it is the whole grant, no runtime prompt). An install that predates the line keeps the grant set it was installed with, so this alone does not stop the crash on an existing phone; - `wifiSsid` returns null unless the permission is actually held, and wraps the read in `runCatching`, so the status report degrades to "no wifi name" instead of dying whole. The check is a `hasWifiState` beside the existing `hasLocation`, same idiom.
This commit is contained in:
1 parent
52ee642eee
commit
6ae21568d0
2 files changed
+21
-2
No files matched your search
@@ -68,6 +68,11 @@ object PhoneSensors {
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
|
||||
/** WifiService's gate (a normal permission, declared in the manifest). */
|
||||
fun hasWifiState(context: Context): Boolean =
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_WIFI_STATE) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
|
||||
/** Usage access is a special-app grant (a settings toggle, like DND access). */
|
||||
fun hasUsageAccess(context: Context): Boolean {
|
||||
val appOps = context.getSystemService(AppOpsManager::class.java) ?: return false
|
||||
@@ -209,8 +214,15 @@ object PhoneSensors {
|
||||
// Reading an SSID is treated as location by the OS: without the
|
||||
// grant the answer is a placeholder, so do not post it.
|
||||
if (!hasLocation(context)) return null
|
||||
val wifi = context.getSystemService(WifiManager::class.java) ?: return null
|
||||
val info = wifi.connectionInfo ?: return null
|
||||
// And every WifiManager call is gated on ACCESS_WIFI_STATE, which
|
||||
// WifiService enforces by throwing — an install that predates the
|
||||
// manifest declaration keeps the grant set it was installed with,
|
||||
// and that throw travels out of this read into the whole status
|
||||
// report: one missing permission used to cost every topic.
|
||||
if (!hasWifiState(context)) return null
|
||||
val info = runCatching {
|
||||
context.getSystemService(WifiManager::class.java)?.connectionInfo
|
||||
}.getOrNull() ?: return null
|
||||
return info.ssid
|
||||
?.removeSurrounding("\"")
|
||||
?.takeIf { ssid ->
|
||||
|
||||
Reference in new issue
Block a user