termux-app

Форк
0
282 строки · 10.7 Кб
1
package com.termux.shared.reflection;
2

3
import android.os.Build;
4

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

8
import com.termux.shared.logger.Logger;
9

10
import org.lsposed.hiddenapibypass.HiddenApiBypass;
11

12
import java.lang.reflect.Constructor;
13
import java.lang.reflect.Field;
14
import java.lang.reflect.Method;
15
import java.util.Arrays;
16

17
public class ReflectionUtils {
18

19
    private static boolean HIDDEN_API_REFLECTION_RESTRICTIONS_BYPASSED = Build.VERSION.SDK_INT < Build.VERSION_CODES.P;
20

21
    private static final String LOG_TAG = "ReflectionUtils";
22

23
    /**
24
     * Bypass android hidden API reflection restrictions.
25
     * https://github.com/LSPosed/AndroidHiddenApiBypass
26
     * https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces
27
     */
28
    public static void bypassHiddenAPIReflectionRestrictions() {
29
        if (!HIDDEN_API_REFLECTION_RESTRICTIONS_BYPASSED && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
30
            Logger.logDebug(LOG_TAG, "Bypassing android hidden api reflection restrictions");
31
            try {
32
                HiddenApiBypass.addHiddenApiExemptions("");
33
            } catch (Throwable t) {
34
                Logger.logStackTraceWithMessage(LOG_TAG, "Failed to bypass hidden API reflection restrictions", t);
35
            }
36

37
            HIDDEN_API_REFLECTION_RESTRICTIONS_BYPASSED = true;
38
        }
39
    }
40

41
    /** Check if android hidden API reflection restrictions are bypassed. */
42
    public static boolean areHiddenAPIReflectionRestrictionsBypassed() {
43
        return HIDDEN_API_REFLECTION_RESTRICTIONS_BYPASSED;
44
    }
45

46

47

48

49

50
    /**
51
     * Get a {@link Field} for the specified class.
52
     *
53
     * @param clazz The {@link Class} for which to return the field.
54
     * @param fieldName The name of the {@link Field}.
55
     * @return Returns the {@link Field} if getting the it was successful, otherwise {@code null}.
56
     */
57
    @Nullable
58
    public static Field getDeclaredField(@NonNull Class<?> clazz, @NonNull String fieldName) {
59
        try {
60
            Field field = clazz.getDeclaredField(fieldName);
61
            field.setAccessible(true);
62
            return field;
63
        } catch (Exception e) {
64
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"" + fieldName + "\" field for \"" + clazz.getName() + "\" class", e);
65
            return null;
66
        }
67
    }
68

69

70

71
    /** Class that represents result of invoking a field. */
72
    public static class FieldInvokeResult {
73
        public boolean success;
74
        public Object value;
75

76
        FieldInvokeResult(boolean success, Object value) {
77
            this.value = success;
78
            this.value = value;
79
        }
80
    }
81

82
    /**
83
     * Get a value for a {@link Field} of an object for the specified class.
84
     *
85
     * Trying to access {@code null} fields will result in {@link NoSuchFieldException}.
86
     *
87
     * @param clazz The {@link Class} to which the object belongs to.
88
     * @param fieldName The name of the {@link Field}.
89
     * @param object The {@link Object} instance from which to get the field value.
90
     * @return Returns the {@link FieldInvokeResult} of invoking the field. The
91
     * {@link FieldInvokeResult#success} will be {@code true} if invoking the field was successful,
92
     * otherwise {@code false}. The {@link FieldInvokeResult#value} will contain the field
93
     * {@link Object} value.
94
     */
95
    @NonNull
96
    public static <T> FieldInvokeResult invokeField(@NonNull Class<? extends T> clazz, @NonNull String fieldName, T object) {
97
        try {
98
            Field field = getDeclaredField(clazz, fieldName);
99
            if (field == null) return new FieldInvokeResult(false, null);
100
            return new FieldInvokeResult(true, field.get(object));
101
        } catch (Exception e) {
102
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"" + fieldName + "\" field value for \"" + clazz.getName() + "\" class", e);
103
            return new FieldInvokeResult(false, null);
104
        }
105
    }
106

107

108

109

110

111
    /**
112
     * Wrapper for {@link #getDeclaredMethod(Class, String, Class[])} without parameters.
113
     */
114
    @Nullable
115
    public static Method getDeclaredMethod(@NonNull Class<?> clazz, @NonNull String methodName) {
116
        return getDeclaredMethod(clazz, methodName, new Class<?>[0]);
117
    }
118

119
    /**
120
     * Get a {@link Method} for the specified class with the specified parameters.
121
     *
122
     * @param clazz The {@link Class} for which to return the method.
123
     * @param methodName The name of the {@link Method}.
124
     * @param parameterTypes The parameter types of the method.
125
     * @return Returns the {@link Method} if getting the it was successful, otherwise {@code null}.
126
     */
127
    @Nullable
128
    public static Method getDeclaredMethod(@NonNull Class<?> clazz, @NonNull String methodName, Class<?>... parameterTypes) {
129
        try {
130
            Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
131
            method.setAccessible(true);
132
            return method;
133
        } catch (Exception e) {
134
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"" + methodName + "\" method for \"" + clazz.getName() + "\" class with parameter types: " + Arrays.toString(parameterTypes), e);
135
            return null;
136
        }
137
    }
138

139

140

141
    /**
142
     * Wrapper for {@link #invokeVoidMethod(Method, Object, Object...)} without arguments.
143
     */
144
    public static boolean invokeVoidMethod(@NonNull Method method, Object obj) {
145
        return invokeVoidMethod(method, obj, new Object[0]);
146
    }
147

148
    /**
149
     * Invoke a {@link Method} on the specified object with the specified arguments that returns
150
     * {@code void}.
151
     *
152
     * @param method The {@link Method} to invoke.
153
     * @param obj The {@link Object} the method should be invoked from.
154
     * @param args The arguments to pass to the method.
155
     * @return Returns {@code true} if invoking the method was successful, otherwise {@code false}.
156
     */
157
    public static boolean invokeVoidMethod(@NonNull Method method, Object obj, Object... args) {
158
        try {
159
            method.setAccessible(true);
160
            method.invoke(obj, args);
161
            return true;
162
        } catch (Exception e) {
163
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to invoke \"" + method.getName() + "\" method with object \"" + obj + "\" and args: " + Arrays.toString(args), e);
164
            return false;
165
        }
166
    }
167

168

169

170
    /** Class that represents result of invoking a method that has a non-void return type. */
171
    public static class MethodInvokeResult {
172
        public boolean success;
173
        public Object value;
174

175
        MethodInvokeResult(boolean success, Object value) {
176
            this.value = success;
177
            this.value = value;
178
        }
179
    }
180

181
    /**
182
     * Wrapper for {@link #invokeMethod(Method, Object, Object...)} without arguments.
183
     */
184
    @NonNull
185
    public static MethodInvokeResult invokeMethod(@NonNull Method method, Object obj) {
186
        return invokeMethod(method, obj, new Object[0]);
187
    }
188

189
    /**
190
     * Invoke a {@link Method} on the specified object with the specified arguments.
191
     *
192
     * @param method The {@link Method} to invoke.
193
     * @param obj The {@link Object} the method should be invoked from.
194
     * @param args The arguments to pass to the method.
195
     * @return Returns the {@link MethodInvokeResult} of invoking the method. The
196
     * {@link MethodInvokeResult#success} will be {@code true} if invoking the method was successful,
197
     * otherwise {@code false}. The {@link MethodInvokeResult#value} will contain the {@link Object}
198
     * returned by the method.
199
     */
200
    @NonNull
201
    public static MethodInvokeResult invokeMethod(@NonNull Method method, Object obj, Object... args) {
202
        try {
203
            method.setAccessible(true);
204
            return new MethodInvokeResult(true, method.invoke(obj, args));
205
        } catch (Exception e) {
206
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to invoke \"" + method.getName() + "\" method with object \"" + obj + "\" and args: " + Arrays.toString(args), e);
207
            return new MethodInvokeResult(false, null);
208
        }
209
    }
210

211

212

213
    /**
214
     * Wrapper for {@link #getConstructor(String, Class[])} without parameters.
215
     */
216
    @Nullable
217
    public static Constructor<?> getConstructor(@NonNull String className) {
218
        return getConstructor(className, new Class<?>[0]);
219
    }
220

221
    /**
222
     * Wrapper for {@link #getConstructor(Class, Class[])} to get a {@link Constructor} for the
223
     * {@code className}.
224
     */
225
    @Nullable
226
    public static Constructor<?> getConstructor(@NonNull String className, Class<?>... parameterTypes) {
227
        try {
228
            return getConstructor(Class.forName(className), parameterTypes);
229
        } catch (Exception e) {
230
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get constructor for \"" + className + "\" class with parameter types: " + Arrays.toString(parameterTypes), e);
231
            return null;
232
        }
233
    }
234

235
    /**
236
     * Get a {@link Constructor} for the specified class with the specified parameters.
237
     *
238
     * @param clazz The {@link Class} for which to return the constructor.
239
     * @param parameterTypes The parameter types of the constructor.
240
     * @return Returns the {@link Constructor} if getting the it was successful, otherwise {@code null}.
241
     */
242
    @Nullable
243
    public static Constructor<?> getConstructor(@NonNull Class<?> clazz, Class<?>... parameterTypes) {
244
        try {
245
            Constructor<?> constructor = clazz.getConstructor(parameterTypes);
246
            constructor.setAccessible(true);
247
            return constructor;
248
        } catch (Exception e) {
249
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get constructor for \"" + clazz.getName() + "\" class with parameter types: " + Arrays.toString(parameterTypes), e);
250
            return null;
251
        }
252
    }
253

254

255

256
    /**
257
     * Wrapper for {@link #invokeConstructor(Constructor, Object...)} without arguments.
258
     */
259
    @Nullable
260
    public static Object invokeConstructor(@NonNull Constructor<?> constructor) {
261
        return invokeConstructor(constructor, new Object[0]);
262
    }
263

264
    /**
265
     * Invoke a {@link Constructor} with the specified arguments.
266
     *
267
     * @param constructor The {@link Constructor} to invoke.
268
     * @param args The arguments to pass to the constructor.
269
     * @return Returns the new instance if invoking the constructor was successful, otherwise {@code null}.
270
     */
271
    @Nullable
272
    public static Object invokeConstructor(@NonNull Constructor<?> constructor, Object... args) {
273
        try {
274
            constructor.setAccessible(true);
275
            return constructor.newInstance(args);
276
        } catch (Exception e) {
277
            Logger.logStackTraceWithMessage(LOG_TAG, "Failed to invoke \"" + constructor.getName() + "\" constructor with args: " + Arrays.toString(args), e);
278
            return null;
279
        }
280
    }
281

282
}
283

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

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

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

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