termux-app
143 строки · 6.8 Кб
1package com.termux.shared.android;
2
3import android.content.Context;
4import android.content.pm.PackageManager;
5
6import androidx.annotation.NonNull;
7import androidx.annotation.Nullable;
8
9import com.termux.shared.logger.Logger;
10import com.termux.shared.reflection.ReflectionUtils;
11
12import java.lang.reflect.Method;
13
14public class UserUtils {
15
16public static final String LOG_TAG = "UserUtils";
17
18/**
19* Get the user name for user id with a call to {@link #getNameForUidFromPackageManager(Context, int)}
20* and if that fails, then a call to {@link #getNameForUidFromLibcore(int)}.
21*
22* @param context The {@link Context} for operations.
23* @param uid The user id.
24* @return Returns the user name if found, otherwise {@code null}.
25*/
26@Nullable
27public static String getNameForUid(@NonNull Context context, int uid) {
28String name = getNameForUidFromPackageManager(context, uid);
29if (name == null)
30name = getNameForUidFromLibcore(uid);
31return name;
32}
33
34/**
35* Get the user name for user id with a call to {@link PackageManager#getNameForUid(int)}.
36*
37* This will not return user names for non app user id like for root user 0, use {@link #getNameForUidFromLibcore(int)}
38* to get those.
39*
40* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:frameworks/base/core/java/android/content/pm/PackageManager.java;l=5556
41* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:frameworks/base/core/java/android/app/ApplicationPackageManager.java;l=1028
42* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java;l=10293
43*
44* @param context The {@link Context} for operations.
45* @param uid The user id.
46* @return Returns the user name if found, otherwise {@code null}.
47*/
48@Nullable
49public static String getNameForUidFromPackageManager(@NonNull Context context, int uid) {
50if (uid < 0) return null;
51
52try {
53String name = context.getPackageManager().getNameForUid(uid);
54if (name != null && name.endsWith(":" + uid))
55name = name.replaceAll(":" + uid + "$", ""); // Remove ":<uid>" suffix
56return name;
57} catch (Exception e) {
58Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get name for uid \"" + uid + "\" from package manager", e);
59return null;
60}
61}
62
63/**
64* Get the user name for user id with a call to `Libcore.os.getpwuid()`.
65*
66* This will return user names for non app user id like for root user 0 as well, but this call
67* is expensive due to usage of reflection, and requires hidden API bypass, check
68* {@link ReflectionUtils#bypassHiddenAPIReflectionRestrictions()} for details.
69*
70* `BlockGuardOs` implements the `Os` interface and its instance is stored in `Libcore` class static `os` field.
71* The `getpwuid` method is implemented by `ForwardingOs`, which is the super class of `BlockGuardOs`.
72* The `getpwuid` method returns `StructPasswd` object whose `pw_name` contains the user name for id.
73*
74* https://stackoverflow.com/a/28057167/14686958
75* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:libcore/luni/src/main/java/libcore/io/Libcore.java;l=39
76* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:libcore/luni/src/main/java/libcore/io/Os.java;l=279
77* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:libcore/luni/src/main/java/libcore/io/BlockGuardOs.java
78* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:libcore/luni/src/main/java/libcore/io/ForwardingOs.java;l=340
79* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:libcore/luni/src/main/java/android/system/StructPasswd.java
80* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:bionic/libc/bionic/grp_pwd.cpp;l=553
81* https://cs.android.com/android/platform/superproject/+/android-12.0.0_r32:system/core/libcutils/include/private/android_filesystem_config.h;l=43
82*
83* @param uid The user id.
84* @return Returns the user name if found, otherwise {@code null}.
85*/
86@Nullable
87public static String getNameForUidFromLibcore(int uid) {
88if (uid < 0) return null;
89
90ReflectionUtils.bypassHiddenAPIReflectionRestrictions();
91try {
92String libcoreClassName = "libcore.io.Libcore";
93Class<?> clazz = Class.forName(libcoreClassName);
94Object os; // libcore.io.BlockGuardOs
95try {
96os = ReflectionUtils.invokeField(Class.forName(libcoreClassName), "os", null).value;
97} catch (Exception e) {
98// ClassCastException may be thrown
99Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"os\" field value for " + libcoreClassName + " class", e);
100return null;
101}
102
103if (os == null) {
104Logger.logError(LOG_TAG, "Failed to get BlockGuardOs class obj from Libcore");
105return null;
106}
107
108clazz = os.getClass().getSuperclass(); // libcore.io.ForwardingOs
109if (clazz == null) {
110Logger.logError(LOG_TAG, "Failed to find super class ForwardingOs from object of class " + os.getClass().getName());
111return null;
112}
113
114Object structPasswd; // android.system.StructPasswd
115try {
116Method getpwuidMethod = ReflectionUtils.getDeclaredMethod(clazz, "getpwuid", int.class);
117if (getpwuidMethod == null) return null;
118structPasswd = ReflectionUtils.invokeMethod(getpwuidMethod, os, uid).value;
119} catch (Exception e) {
120Logger.logStackTraceWithMessage(LOG_TAG, "Failed to invoke getpwuid() method of " + clazz.getName() + " class", e);
121return null;
122}
123
124if (structPasswd == null) {
125Logger.logError(LOG_TAG, "Failed to get StructPasswd obj from call to ForwardingOs.getpwuid()");
126return null;
127}
128
129try {
130clazz = structPasswd.getClass();
131return (String) ReflectionUtils.invokeField(clazz, "pw_name", structPasswd).value;
132} catch (Exception e) {
133// ClassCastException may be thrown
134Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"pw_name\" field value for " + clazz.getName() + " class", e);
135return null;
136}
137} catch (Exception e) {
138Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get name for uid \"" + uid + "\" from Libcore", e);
139return null;
140}
141}
142
143}
144