Skip to content

Commit 36ec596

Browse files
refactor(module): dynamically resolve system packages (#85)
* fix(module): resolve SystemUI package instead of hardcoding com.android.systemui * fix(module): resolve SystemUI and Settings packages dynamically * ui: add contributor * fix: remove SystemUI package fallback * restore legacy system package fallback * fix: refresh package metadata --------- Co-authored-by: XiaoTong6666 <xiaotong6666666666@gmail.com>
1 parent 39e4089 commit 36ec596

18 files changed

Lines changed: 498 additions & 148 deletions

File tree

module/src/main/cpp/core/main_zygisk.cpp

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include <zygisk.hpp>
2+
#include <cstdlib>
23
#include <cstring>
34
#include <cerrno>
5+
#include <limits>
46
#include <logging.h>
57
#include <cstdio>
68
#include <sys/socket.h>
@@ -177,28 +179,78 @@ class ZygiskModule : public zygisk::ModuleBase {
177179

178180
static int dex_mem_fd = -1;
179181
static size_t dex_size = 0;
180-
static uid_t manager_uid = -1, settings_uid = -1;
181-
static char manager_process[kProcessNameMax], settings_process[kProcessNameMax];
182182

183-
static void ReadApplicationInfo(const char* package, uid_t& uid, char* process) {
183+
struct AppIdentity {
184+
char package[kProcessNameMax]{};
185+
uid_t uid = static_cast<uid_t>(-1);
186+
char process[kProcessNameMax]{};
187+
};
188+
189+
static AppIdentity manager, settings;
190+
191+
static bool ReadLine(const uint8_t* bytes, size_t size, size_t& offset, char* value,
192+
size_t value_size) {
193+
if (offset >= size || value_size == 0) {
194+
return false;
195+
}
196+
197+
size_t end = offset;
198+
while (end < size && bytes[end] != '\r' && bytes[end] != '\n') {
199+
++end;
200+
}
201+
202+
size_t length = end - offset;
203+
if (length == 0 || length >= value_size) {
204+
return false;
205+
}
206+
memcpy(value, bytes + offset, length);
207+
value[length] = '\0';
208+
209+
while (end < size && (bytes[end] == '\r' || bytes[end] == '\n')) {
210+
++end;
211+
}
212+
offset = end;
213+
return true;
214+
}
215+
216+
static bool ReadApplicationInfo(const char* name, AppIdentity& identity) {
184217
char buf[PATH_MAX];
185-
snprintf(buf, PATH_MAX, "/data/adb/modules/%s/%s", ZYGISK_MODULE_ID, package);
218+
snprintf(buf, PATH_MAX, "/data/adb/modules/%s/%s", ZYGISK_MODULE_ID, name);
186219
auto file = Buffer(buf);
187220
auto bytes = file.data();
188221
auto size = file.size();
189222
if (bytes == nullptr || size == 0) {
190223
LOGW("ReadApplicationInfo: failed to read %s", buf);
191-
return;
224+
return false;
192225
}
193-
for (int i = 0; i < size; ++i) {
194-
if (bytes[i] == '\n') {
195-
memset(process, 0, kProcessNameMax);
196-
size_t process_size = std::min<size_t>(size - i - 1, kProcessNameMax - 1);
197-
memcpy(process, bytes + i + 1, process_size);
198-
bytes[i] = 0;
199-
uid = atoi((char*)bytes);
200-
break;
201-
}
226+
227+
char uid_string[32]{};
228+
size_t offset = 0;
229+
if (!ReadLine(bytes, size, offset, identity.package, sizeof(identity.package)) ||
230+
!ReadLine(bytes, size, offset, uid_string, sizeof(uid_string)) ||
231+
!ReadLine(bytes, size, offset, identity.process, sizeof(identity.process))) {
232+
LOGW("ReadApplicationInfo: invalid data in %s", buf);
233+
return false;
234+
}
235+
236+
char* end = nullptr;
237+
errno = 0;
238+
unsigned long uid = strtoul(uid_string, &end, 10);
239+
if (errno != 0 || end == uid_string || *end != '\0' ||
240+
uid > std::numeric_limits<uid_t>::max()) {
241+
LOGW("ReadApplicationInfo: invalid uid in %s", buf);
242+
return false;
243+
}
244+
identity.uid = static_cast<uid_t>(uid);
245+
return true;
246+
}
247+
248+
static void RefreshApplicationInfo() {
249+
if (manager.uid == static_cast<uid_t>(-1)) {
250+
ReadApplicationInfo(MANAGER_APPLICATION_INFO, manager);
251+
}
252+
if (settings.uid == static_cast<uid_t>(-1)) {
253+
ReadApplicationInfo(SETTINGS_APPLICATION_INFO, settings);
202254
}
203255
}
204256

@@ -236,11 +288,11 @@ static bool PrepareCompanion() {
236288

237289
LOGI("Companion: dex fd is %d", dex_mem_fd);
238290

239-
ReadApplicationInfo(MANAGER_APPLICATION_ID, manager_uid, manager_process);
240-
ReadApplicationInfo(SETTINGS_APPLICATION_ID, settings_uid, settings_process);
291+
ReadApplicationInfo(MANAGER_APPLICATION_INFO, manager);
292+
ReadApplicationInfo(SETTINGS_APPLICATION_INFO, settings);
241293

242-
LOGI("Companion: SystemUI %d %s", manager_uid, manager_process);
243-
LOGI("Companion: Settings %d %s", settings_uid, settings_process);
294+
LOGI("Companion: SystemUI %s %d %s", manager.package, manager.uid, manager.process);
295+
LOGI("Companion: Settings %s %d %s", settings.package, settings.uid, settings.process);
244296

245297
result = true;
246298

@@ -259,6 +311,8 @@ static void CompanionEntry(int socket) {
259311
return;
260312
}
261313

314+
RefreshApplicationInfo();
315+
262316
char process_name[kProcessNameMax]{0};
263317
Identity whoami;
264318

@@ -270,10 +324,10 @@ static void CompanionEntry(int socket) {
270324
read_full(socket, process_name, kProcessNameMax);
271325

272326
LOGI("SuiCompanion: Checking app: uid=%d, process=%s", uid, process_name);
273-
if (uid == manager_uid && strcmp(process_name, manager_process) == 0) {
327+
if (uid == manager.uid && strcmp(process_name, manager.process) == 0) {
274328
whoami = Identity::SYSTEM_UI;
275329
LOGI("SuiCompanion: Matched SYSTEM_UI!");
276-
} else if (uid == settings_uid && strcmp(process_name, settings_process) == 0) {
330+
} else if (uid == settings.uid && strcmp(process_name, settings.process) == 0) {
277331
whoami = Identity::SETTINGS;
278332
LOGI("SuiCompanion: Matched SETTINGS!");
279333
} else {

module/src/main/cpp/include/config.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
#pragma once
2121

22-
#define MANAGER_APPLICATION_ID "com.android.systemui"
23-
#define SETTINGS_APPLICATION_ID "com.android.settings"
22+
#define MANAGER_APPLICATION_INFO "system_ui"
23+
#define SETTINGS_APPLICATION_INFO "settings"
2424

2525
#define DEX_NAME "sui.dex"
2626
#define SYSTEM_PROCESS_CLASSNAME "rikka/sui/systemserver/SystemProcess"

module/src/main/cpp/main/uninstall_main.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ static int uninstall_main(int argc, char** argv) {
5454

5555
wait_for_zygote();
5656

57-
app_process("/dev/sui.dex", "/dev", "rikka.sui.installer.Uninstaller", "sui_uninstaller");
57+
app_process("/dev/sui.dex", "/dev", "rikka.sui.installer.Uninstaller", "sui_uninstaller",
58+
root_path);
5859
unlink("/dev/sui.dex");
5960

6061
return EXIT_SUCCESS;

module/src/main/java/rikka/sui/installer/Installer.java

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,49 +19,98 @@
1919

2020
package rikka.sui.installer;
2121

22-
import android.content.pm.ApplicationInfo;
22+
import android.app.ActivityThread;
23+
import android.content.Context;
24+
import android.os.Looper;
2325
import java.io.File;
2426
import java.io.FileWriter;
2527
import java.io.IOException;
2628
import java.util.Locale;
27-
import rikka.hidden.compat.PackageManagerApis;
28-
import rikka.sui.util.SettingsPackages;
29+
import rikka.sui.util.SystemPackages;
30+
import rikka.sui.util.SystemPackages.SystemPackage;
2931

3032
public class Installer {
3133

32-
private static void saveApplicationInfoToFile(String path, String packageName, String fileName, String name)
33-
throws IOException {
34-
ApplicationInfo ai = PackageManagerApis.getApplicationInfoNoThrow(packageName, 0, 0);
35-
if (ai == null) {
36-
System.out.println("! Can't fetch application info for package " + packageName);
37-
return;
34+
private static final int PACKAGE_INFO_RETRY_COUNT = 120;
35+
36+
private static boolean saveApplicationInfoToFile(
37+
String path, String fileName, String name, SystemPackage systemPackage) throws IOException {
38+
if (systemPackage == null) {
39+
System.out.println("! Can't resolve the " + name + " package");
40+
return false;
3841
}
39-
int uid = ai.uid;
40-
String processName = ai.processName != null ? ai.processName : packageName;
41-
System.out.println("- " + name + ": uid=" + uid + ", processName=" + processName);
42+
43+
System.out.println("- " + name + ": packageName=" + systemPackage.packageName + ", uid=" + systemPackage.uid
44+
+ ", processName=" + systemPackage.processName);
4245

4346
File file = new File(path, fileName);
44-
if (!file.exists() && !file.createNewFile()) {
45-
System.out.println("! Can't create " + file);
46-
return;
47+
File temporaryFile = new File(path, fileName + ".new");
48+
if (temporaryFile.exists() && !temporaryFile.delete()) {
49+
throw new IOException("Can't delete " + temporaryFile);
50+
}
51+
52+
try (FileWriter writer = new FileWriter(temporaryFile)) {
53+
writer.write(String.format(
54+
Locale.ENGLISH,
55+
"%s\n%d\n%s",
56+
systemPackage.packageName,
57+
systemPackage.uid,
58+
systemPackage.processName));
59+
}
60+
61+
if (!temporaryFile.renameTo(file)) {
62+
temporaryFile.delete();
63+
throw new IOException("Can't replace " + file);
64+
}
65+
return true;
66+
}
67+
68+
private static SystemPackage[] resolvePackages(Context context) throws InterruptedException {
69+
SystemPackage systemUi = null;
70+
SystemPackage settings = null;
71+
72+
for (int attempt = 0; attempt < PACKAGE_INFO_RETRY_COUNT; ++attempt) {
73+
if (systemUi == null) {
74+
systemUi = SystemPackages.resolveSystemUi(context);
75+
}
76+
if (settings == null) {
77+
settings = SystemPackages.resolveSettings(context);
78+
}
79+
if (systemUi != null && settings != null) {
80+
break;
81+
}
82+
83+
if (attempt == 0 || (attempt + 1) % 10 == 0) {
84+
System.out.println(
85+
"- Waiting for PackageManager (" + (attempt + 1) + "/" + PACKAGE_INFO_RETRY_COUNT + ")");
86+
}
87+
Thread.sleep(1000);
4788
}
4889

49-
FileWriter writer = new FileWriter(file);
50-
writer.write(String.format(Locale.ENGLISH, "%d\n%s", uid, processName));
51-
writer.flush();
52-
writer.close();
90+
return new SystemPackage[] {systemUi, settings};
5391
}
5492

55-
public static void main(String[] args) throws IOException {
93+
@SuppressWarnings("deprecation")
94+
public static void main(String[] args) throws IOException, InterruptedException {
5695
System.out.println("- AppProcess: main");
57-
saveApplicationInfoToFile(args[0], "com.android.systemui", "com.android.systemui", "SystemUI");
58-
59-
String settingsPackageName = SettingsPackages.resolveInstalledSettingsPackage();
60-
if (settingsPackageName == null) {
61-
System.out.println("! Can't fetch application info for settings packages "
62-
+ java.util.Arrays.toString(SettingsPackages.SETTINGS_CANDIDATES));
63-
} else {
64-
saveApplicationInfoToFile(args[0], settingsPackageName, SettingsPackages.SETTINGS, "Settings");
96+
97+
if (Looper.getMainLooper() == null) {
98+
Looper.prepareMainLooper();
99+
}
100+
Context context = ActivityThread.systemMain().getSystemContext();
101+
SystemPackage[] packages = resolvePackages(context);
102+
103+
if (packages[0] == null || packages[1] == null) {
104+
System.out.println("! PackageManager did not resolve all required packages");
105+
System.exit(1);
106+
return;
107+
}
108+
109+
if (!saveApplicationInfoToFile(args[0], "system_ui", "SystemUI", packages[0])
110+
|| !saveApplicationInfoToFile(args[0], "settings", "Settings", packages[1])) {
111+
System.out.println("! Failed to save package metadata");
112+
System.exit(1);
113+
return;
65114
}
66115
System.out.println("- AppProcess: exit");
67116
}

module/src/main/java/rikka/sui/installer/Uninstaller.java

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package rikka.sui.installer;
2121

22+
import android.app.ActivityThread;
23+
import android.content.Context;
2224
import android.content.pm.IShortcutService;
2325
import android.content.pm.IShortcutServiceV31;
2426
import android.os.Build;
@@ -30,20 +32,44 @@
3032
import android.system.ErrnoException;
3133
import android.system.Os;
3234
import android.util.Log;
35+
import androidx.annotation.Nullable;
3336
import androidx.annotation.RequiresApi;
3437
import dev.rikka.tools.refine.Refine;
38+
import java.io.BufferedReader;
39+
import java.io.File;
40+
import java.io.FileReader;
3541
import java.io.IOException;
3642
import java.util.ArrayList;
3743
import java.util.List;
3844
import rikka.sui.shortcut.ShortcutConstants;
39-
import rikka.sui.util.SettingsPackages;
45+
import rikka.sui.util.SystemPackages;
46+
import rikka.sui.util.SystemPackages.SystemPackage;
4047

4148
@RequiresApi(Build.VERSION_CODES.O)
4249
public class Uninstaller {
4350

4451
private static final String TAG = "SuiUninstaller";
4552

46-
private static void removeShortcuts() throws InterruptedException, RemoteException {
53+
private static @Nullable String readInstalledSettingsPackage(@Nullable String rootPath) {
54+
if (rootPath == null) {
55+
return null;
56+
}
57+
58+
File file = new File(rootPath, "settings");
59+
if (!file.isFile()) {
60+
return null;
61+
}
62+
63+
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
64+
return reader.readLine();
65+
} catch (IOException e) {
66+
Log.w(TAG, "Can't read installed Settings package", e);
67+
return null;
68+
}
69+
}
70+
71+
private static void removeShortcuts(Context context, @Nullable String rootPath)
72+
throws InterruptedException, RemoteException {
4773
IShortcutService shortcutService = null;
4874
IUserManager userManager = null;
4975

@@ -67,7 +93,23 @@ private static void removeShortcuts() throws InterruptedException, RemoteExcepti
6793
List<String> list = new ArrayList<>();
6894
list.add(ShortcutConstants.SHORTCUT_ID);
6995

70-
for (String packageName : SettingsPackages.SETTINGS_CANDIDATES) {
96+
List<String> packageNames = new ArrayList<>();
97+
String installedPackageName = readInstalledSettingsPackage(rootPath);
98+
if (installedPackageName != null) {
99+
packageNames.add(installedPackageName);
100+
}
101+
102+
SystemPackage settingsPackage = SystemPackages.resolveSettings(context);
103+
while (settingsPackage == null && packageNames.isEmpty()) {
104+
Thread.sleep(1000);
105+
Log.v(TAG, "wait for Settings package 1s");
106+
settingsPackage = SystemPackages.resolveSettings(context);
107+
}
108+
if (settingsPackage != null && !packageNames.contains(settingsPackage.packageName)) {
109+
packageNames.add(settingsPackage.packageName);
110+
}
111+
112+
for (String packageName : packageNames) {
71113
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
72114
Refine.<IShortcutServiceV31>unsafeCast(shortcutService).removeDynamicShortcuts(packageName, list, 0);
73115
} else {
@@ -88,10 +130,12 @@ public static void main(String[] args) throws IOException, ErrnoException {
88130
if (Looper.myLooper() == null) {
89131
Looper.prepare();
90132
}
133+
Context context = ActivityThread.systemMain().getSystemContext();
134+
String rootPath = args.length > 0 ? args[0] : null;
91135

92136
new Handler(Looper.myLooper()).post(() -> {
93137
try {
94-
removeShortcuts();
138+
removeShortcuts(context, rootPath);
95139
} catch (Throwable e) {
96140
Log.e(TAG, Log.getStackTraceString(e));
97141
}

0 commit comments

Comments
 (0)