docs: SPEC §5.3.1 — document Shizuku v12+ integration on RayNeo X3 Pro
- Replace obsolete moe.shizuku.permission.SHIZUKU (v11) with the v12+
moe.shizuku.manager.permission.API_V23 in the GlassesApp permission list.
- Document the rikka.shizuku.ShizukuProvider provider block required by
the Shizuku-API guide; without it the binder never arrives.
- Add §5.3.1 'Интеграция с Shizuku' explaining:
* why dev.rikka.shizuku:provider is required (ContentProvider.onCreate
pulls the binder via IPC);
* the activity-side listener pattern (addBinderReceivedListenerSticky +
addRequestPermissionResultListener);
* the RayNeo system launcher race condition (PID 24482
com.ffalconxr.mercury.launcher, UID system, forceStopPackage on
RequestPermissionActivity within ~14ms).
This commit is contained in:
+64
-3
@@ -915,8 +915,21 @@ class AudioPlaybackService : Service() {
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <!-- AudioPlaybackService -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ для foreground notification -->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- PARTIAL_WAKE_LOCK для AudioPlaybackService -->
|
||||
<!-- Shizuku permission для VM-сервиса -->
|
||||
<uses-permission android:name="moe.shizuku.permission.SHIZUKU" />
|
||||
<!-- Shizuku permission v12+ (BinderSender проверяет requestedPermissions на наличие
|
||||
этого permission; старое moe.shizuku.permission.SHIZUKU v11 не работает). -->
|
||||
<uses-permission android:name="moe.shizuku.manager.permission.API_V23" />
|
||||
```
|
||||
|
||||
**Shizuku Provider (v12+ обязательно, см. ниже §5.3.1):**
|
||||
|
||||
```xml
|
||||
<provider
|
||||
android:name="rikka.shizuku.ShizukuProvider"
|
||||
android:authorities="${applicationId}.shizuku"
|
||||
android:multiprocess="false"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||
```
|
||||
|
||||
**PhoneApp (`app-phone-vm/AndroidManifest.xml`):**
|
||||
@@ -934,9 +947,57 @@ class AudioPlaybackService : Service() {
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- для BLE scan на Android 6-11 -->
|
||||
<!-- Shizuku permission (необязательно, у нас только Mercury-канал) -->
|
||||
<uses-permission android:name="moe.shizuku.permission.SHIZUKU" />
|
||||
<uses-permission android:name="moe.shizuku.manager.permission.API_V23" />
|
||||
```
|
||||
|
||||
### 5.3.1. Интеграция с Shizuku
|
||||
|
||||
**Цель.** GlassesApp использует Shizuku (см. память #4779) как обёртку над `IDisplayManager.createVirtualDisplay` без флага `OWN_CONTENT_ONLY` — единственный способ создать VirtualDisplay, на который можно стартовать чужие Activity (`ActivityOptions.setLaunchDisplayId`).
|
||||
|
||||
**Зависимости (`gradle/libs.versions.toml`):**
|
||||
|
||||
```toml
|
||||
shizukuApi = "13.1.5"
|
||||
shizukuProvider = "13.1.5"
|
||||
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizukuApi" }
|
||||
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizukuProvider" }
|
||||
```
|
||||
|
||||
В `app-glasses-vm/build.gradle.kts` — `implementation(libs.shizuku.api)` + `implementation(libs.shizuku.provider)`.
|
||||
|
||||
**Манифест — обязательная структура (см. https://github.com/RikkaApps/Shizuku-API):**
|
||||
|
||||
1. `<uses-permission android:name="moe.shizuku.manager.permission.API_V23"/>` (v12+). Старое `moe.shizuku.permission.SHIZUKU` (v11) НЕ работает — BinderSender на стороне сервера проверяет, что в `requestedPermissions` есть именно `API_V23`.
|
||||
2. `<provider android:name="rikka.shizuku.ShizukuProvider" android:authorities="${applicationId}.shizuku" android:exported="true" android:permission="android.permission.INTERACT_ACROSS_USERS_FULL"/>` — этот ContentProvider из либы `rikka.shizuku:provider` через свой `onCreate` сам вытаскивает binder у Shizuku-сервера через ContentProvider IPC. **Без него binder к нам никогда не придёт.** Кастомные ContentProvider'ы (например, наш `ShizukuInitProvider`) этого **не заменяют** — у `rikka.shizuku.ShizukuProvider` специальные системные AIDL-хуки.
|
||||
3. `<queries><package android:name="moe.shizuku.privileged.api"/></queries>` — для Android 11+ package visibility (`bindService` к сервису внутри пакета Shizuku-менеджера иначе возвращает false).
|
||||
|
||||
**Activity-side (MainActivity.onCreate, строго после `super.onCreate`):**
|
||||
|
||||
```kotlin
|
||||
Shizuku.addBinderReceivedListenerSticky(object : Shizuku.OnBinderReceivedListener {
|
||||
override fun onBinderReceived() { refresh() }
|
||||
})
|
||||
Shizuku.addRequestPermissionResultListener { _, grant -> refresh() }
|
||||
if (Shizuku.pingBinder()) refresh() else state.value = AllowState.Waiting
|
||||
// где refresh():
|
||||
// running = Shizuku.pingBinder(); perm = Shizuku.checkSelfPermission()
|
||||
// если perm == GRANTED -> Granted, иначе NeedsPermission + requestPermission(code)
|
||||
```
|
||||
|
||||
И override `onRequestPermissionsResult(...)` в Activity (нужен для прокидывания результата диалога).
|
||||
|
||||
**Запрос разрешения и диалог.** Когда пользователь первый раз запускает GlassesApp:
|
||||
1. `Shizuku.checkSelfPermission()` возвращает `PERMISSION_DENIED`.
|
||||
2. `Shizuku.requestPermission(code)` → Shizuku-сервер стартует `RequestPermissionActivity` от `moe.shizuku.privileged.api`.
|
||||
3. Activity показывает диалог «Allow rayneo-vm to use Shizuku?». После Allow — `onRequestPermissionResult` выстреливает, `refresh()` ставит state=Granted.
|
||||
|
||||
**Race condition на RayNeo X3 Pro (см. память #4778).** Системный лаунчер `com.ffalconxr.mercury.launcher` (PID 24482, UID 1000) **иногда** принудительно убивает (`forceStopPackage`) только что запущенную `RequestPermissionActivity` в течение ~14мс. То есть диалог либо показывается, либо нет — гонка. Workaround: при `state==NeedsPermission` после рестарта активности пользователь тапнет ещё раз. В коде: в `refresh()` если `requestPermission()` бросил — повторить на следующем `onResume()`.
|
||||
|
||||
**Что НЕ работает:**
|
||||
- Кастомный ContentProvider вместо `rikka.shizuku.ShizukuProvider` — binder не придёт.
|
||||
- `addBinderReceivedListener` без `Sticky` — пропустим событие, если binder пришёл до того, как мы зарегистрировались.
|
||||
- `requestPermission()` без Activity-контекста — сервер стартует Activity, но если она умерла до того, как пользователь нажал Allow, результат не вернётся.
|
||||
|
||||
### 5.4. Дефолты (фиксировано для ночной сессии)
|
||||
|
||||
**Версии — latest stable на сентябрь 2026 (по правилу «брать последнее по возможности»):**
|
||||
|
||||
Reference in New Issue
Block a user