termux-app

Форк
0
143 строки · 6.8 Кб
1
package com.termux.shared.android;
2

3
import android.content.Context;
4
import android.content.pm.PackageManager;
5

6
import androidx.annotation.NonNull;
7
import androidx.annotation.Nullable;
8

9
import com.termux.shared.logger.Logger;
10
import com.termux.shared.reflection.ReflectionUtils;
11

12
import java.lang.reflect.Method;
13

14
public class UserUtils {
15

16
    public 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
27
    public static String getNameForUid(@NonNull Context context, int uid) {
28
        String name = getNameForUidFromPackageManager(context, uid);
29
        if (name == null)
30
            name = getNameForUidFromLibcore(uid);
31
        return 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
49
    public static String getNameForUidFromPackageManager(@NonNull Context context, int uid) {
50
        if (uid < 0) return null;
51

52
        try {
53
            String name = context.getPackageManager().getNameForUid(uid);
54
            if (name != null && name.endsWith(":" + uid))
55
                name = name.replaceAll(":" + uid + "$", ""); // Remove ":<uid>" suffix
56
            return name;
57
        } catch (Exception e) {
58
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get name for uid \"" + uid + "\" from package manager", e);
59
            return 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
87
    public static String getNameForUidFromLibcore(int uid) {
88
        if (uid < 0) return null;
89

90
        ReflectionUtils.bypassHiddenAPIReflectionRestrictions();
91
        try {
92
            String libcoreClassName = "libcore.io.Libcore";
93
            Class<?> clazz = Class.forName(libcoreClassName);
94
            Object os; // libcore.io.BlockGuardOs
95
            try {
96
                os = ReflectionUtils.invokeField(Class.forName(libcoreClassName), "os", null).value;
97
            } catch (Exception e) {
98
                // ClassCastException may be thrown
99
                Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"os\" field value for " + libcoreClassName + " class", e);
100
                return null;
101
            }
102

103
            if (os == null) {
104
                Logger.logError(LOG_TAG, "Failed to get BlockGuardOs class obj from Libcore");
105
                return null;
106
            }
107

108
            clazz = os.getClass().getSuperclass();  // libcore.io.ForwardingOs
109
            if (clazz == null) {
110
                Logger.logError(LOG_TAG, "Failed to find super class ForwardingOs from object of class " + os.getClass().getName());
111
                return null;
112
            }
113

114
            Object structPasswd; // android.system.StructPasswd
115
            try {
116
                Method getpwuidMethod = ReflectionUtils.getDeclaredMethod(clazz, "getpwuid", int.class);
117
                if (getpwuidMethod == null) return null;
118
                structPasswd = ReflectionUtils.invokeMethod(getpwuidMethod, os, uid).value;
119
            } catch (Exception e) {
120
                Logger.logStackTraceWithMessage(LOG_TAG, "Failed to invoke getpwuid() method of " + clazz.getName() + " class", e);
121
                return null;
122
            }
123

124
            if (structPasswd == null) {
125
                Logger.logError(LOG_TAG, "Failed to get StructPasswd obj from call to ForwardingOs.getpwuid()");
126
                return null;
127
            }
128

129
            try {
130
                clazz = structPasswd.getClass();
131
                return (String) ReflectionUtils.invokeField(clazz, "pw_name", structPasswd).value;
132
            } catch (Exception e) {
133
                // ClassCastException may be thrown
134
                Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"pw_name\" field value for " + clazz.getName() + " class", e);
135
                return null;
136
            }
137
        } catch (Exception e) {
138
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get name for uid \"" + uid + "\" from Libcore", e);
139
            return null;
140
        }
141
    }
142

143
}
144

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.