Here are the examples of the java api @android.annotation.SuppressLint(PrivateApi) taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
113 Examples
19
Source : ThemeManager.java
with GNU General Public License v2.0
from yeriomin
with GNU General Public License v2.0
from yeriomin
/**
* Used for pre-lollipop devices
*/
@SuppressLint("PrivateApi")
private String getSystemProperty(String propertyName) {
try {
Clreplaced<?> c = Clreplaced.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.clreplaced);
return (String) get.invoke(c, propertyName);
} catch (Throwable e) {
return "";
}
}
19
Source : AppGlobals.java
with Apache License 2.0
from y1xian
with Apache License 2.0
from y1xian
@SuppressLint("PrivateApi")
public static Application getApplication() {
if (sApplication == null) {
try {
sApplication = (Application) Clreplaced.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null, (Object[]) null);
if (sApplication == null) {
return null;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
return sApplication;
}
19
Source : PlayerUtils.java
with Apache License 2.0
from xusigh
with Apache License 2.0
from xusigh
/**
* 通过反射获取Application
*
* @deprecated 不在使用,后期谷歌可能封掉改接口
*/
@SuppressLint("PrivateApi")
@Deprecated
public static Application getApplication() {
try {
return (Application) Clreplaced.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
19
Source : DeviceUtils.java
with Apache License 2.0
from xuexiangjys
with Apache License 2.0
from xuexiangjys
/**
* 设备类型工具类
*
* @author XUE
* @since 2019/3/22 10:56
*/
@SuppressLint("PrivateApi")
public clreplaced DeviceUtils {
private final static String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
private static final String KEY_FLYME_VERSION_NAME = "ro.build.display.id";
private final static String FLYME = "flyme";
private final static String ZTEC2016 = "zte c2016";
private final static String ZUKZ1 = "zuk z1";
private final static String ESSENTIAL = "essential";
private final static String[] MEIZUBOARD = { "m9", "M9", "mx", "MX" };
private static String sMiuiVersionName;
private static String sFlymeVersionName;
private static boolean sIsTabletChecked = false;
private static boolean sIsTabletValue = false;
private static final String BRAND = Build.BRAND.toLowerCase();
private DeviceUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
static {
Properties properties = new Properties();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// android 8.0,读取 /system/uild.prop 会报 permission denied
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));
properties.load(fileInputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
Utils.closeIOQuietly(fileInputStream);
}
}
Clreplaced<?> clzSystemProperties = null;
try {
clzSystemProperties = Clreplaced.forName("android.os.SystemProperties");
Method getMethod = clzSystemProperties.getDeclaredMethod("get", String.clreplaced);
// miui
sMiuiVersionName = getLowerCaseName(properties, getMethod, KEY_MIUI_VERSION_NAME);
// flyme
sFlymeVersionName = getLowerCaseName(properties, getMethod, KEY_FLYME_VERSION_NAME);
} catch (Exception e) {
e.printStackTrace();
}
}
private static boolean _isTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
/**
* 判断是否为平板设备
*/
public static boolean isTablet(Context context) {
if (sIsTabletChecked) {
return sIsTabletValue;
}
sIsTabletValue = _isTablet(context);
sIsTabletChecked = true;
return sIsTabletValue;
}
/**
* 判断是否是flyme系统
*/
public static boolean isFlyme() {
return !TextUtils.isEmpty(sFlymeVersionName) && sFlymeVersionName.contains(FLYME);
}
/**
* 判断是否是MIUI系统
*/
public static boolean isMIUI() {
return !TextUtils.isEmpty(sMiuiVersionName);
}
public static boolean isMIUIV5() {
return "v5".equals(sMiuiVersionName);
}
public static boolean isMIUIV6() {
return "v6".equals(sMiuiVersionName);
}
public static boolean isMIUIV7() {
return "v7".equals(sMiuiVersionName);
}
public static boolean isMIUIV8() {
return "v8".equals(sMiuiVersionName);
}
public static boolean isMIUIV9() {
return "v9".equals(sMiuiVersionName);
}
public static boolean isFlymeVersionHigher5_2_4() {
// 查不到默认高于5.2.4
boolean isHigher = true;
if (sFlymeVersionName != null && !"".equals(sFlymeVersionName)) {
Pattern pattern = Pattern.compile("(\\d+\\.){2}\\d");
Matcher matcher = pattern.matcher(sFlymeVersionName);
if (matcher.find()) {
String versionString = matcher.group();
if (versionString != null && !"".equals(versionString)) {
String[] version = versionString.split("\\.");
if (version.length == 3) {
if (Integer.parseInt(version[0]) < 5) {
isHigher = false;
} else if (Integer.parseInt(version[0]) > 5) {
isHigher = true;
} else {
if (Integer.parseInt(version[1]) < 2) {
isHigher = false;
} else if (Integer.parseInt(version[1]) > 2) {
isHigher = true;
} else {
if (Integer.parseInt(version[2]) < 4) {
isHigher = false;
} else if (Integer.parseInt(version[2]) >= 5) {
isHigher = true;
}
}
}
}
}
}
}
return isMeizu() && isHigher;
}
public static boolean isMeizu() {
return isPhone(MEIZUBOARD) || isFlyme();
}
/**
* 判断是否为小米
* https://dev.mi.com/doc/?p=254
*/
public static boolean isXiaomi() {
return "xiaomi".equals(Build.MANUFACTURER.toLowerCase());
}
public static boolean isVivo() {
return BRAND.contains("vivo") || BRAND.contains("bbk");
}
public static boolean isOppo() {
return BRAND.contains("oppo");
}
public static boolean isHuawei() {
return BRAND.contains("huawei") || BRAND.contains("honor");
}
public static boolean isEssentialPhone() {
return BRAND.contains("essential");
}
/**
* 判断是否为 ZUK Z1 和 ZTK C2016。
* 两台设备的系统虽然为 android 6.0,但不支持状态栏icon颜色改变,因此经常需要对它们进行额外判断。
*/
public static boolean isZUKZ1() {
final String board = Build.MODEL;
return board != null && board.toLowerCase().contains(ZUKZ1);
}
public static boolean isZTKC2016() {
final String board = Build.MODEL;
return board != null && board.toLowerCase().contains(ZTEC2016);
}
private static boolean isPhone(String[] boards) {
final String board = Build.BOARD;
if (board == null) {
return false;
}
for (String board1 : boards) {
if (board.equals(board1)) {
return true;
}
}
return false;
}
/**
* 判断悬浮窗权限(目前主要用户魅族与小米的检测)。
*/
public static boolean isFloatWindowOpAllowed(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
// 24 是AppOpsManager.OP_SYSTEM_ALERT_WINDOW 的值,该值无法直接访问
return checkOp(context, 24);
} else {
try {
return (context.getApplicationInfo().flags & 1 << 27) == 1 << 27;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
@TargetApi(19)
private static boolean checkOp(Context context, int op) {
final int version = Build.VERSION.SDK_INT;
if (version >= Build.VERSION_CODES.KITKAT) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
Method method = manager.getClreplaced().getDeclaredMethod("checkOp", int.clreplaced, int.clreplaced, String.clreplaced);
int property = (Integer) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
return AppOpsManager.MODE_ALLOWED == property;
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
@Nullable
private static String getLowerCaseName(Properties p, Method get, String key) {
String name = p.getProperty(key);
if (name == null) {
try {
name = (String) get.invoke(null, key);
} catch (Exception ignored) {
}
}
if (name != null) {
name = name.toLowerCase();
}
return name;
}
}
19
Source : BaseActivity.java
with Apache License 2.0
from wuchao226
with Apache License 2.0
from wuchao226
/**
* 获取状态栏高度
*
* @return
*/
@SuppressLint("PrivateApi")
protected int getStatusBarHeight() {
try {
Clreplaced<?> c = Clreplaced.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x = Integer.parseInt(field.get(obj).toString());
return getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
19
Source : Util.java
with GNU General Public License v3.0
from whyorean
with GNU General Public License v3.0
from whyorean
@SuppressLint("PrivateApi")
public static boolean isMiuiOptimizationDisabled() {
if ("0".equals(getSystemProperty("persist.sys.miui_optimization")))
return true;
try {
return (boolean) Clreplaced.forName("android.miui.AppOpsUtils").getDeclaredMethod("isXOptMode").invoke(null);
} catch (Exception e) {
return false;
}
}
19
Source : Util.java
with GNU General Public License v3.0
from whyorean
with GNU General Public License v3.0
from whyorean
@SuppressLint("PrivateApi")
@Nullable
public static String getSystemProperty(String key) {
try {
return (String) Clreplaced.forName("android.os.SystemProperties").getDeclaredMethod("get", String.clreplaced).invoke(null, key);
} catch (Exception e) {
Log.e("Unable to read SystemProperties", e);
return null;
}
}
19
Source : Utils.java
with Apache License 2.0
from whataa
with Apache License 2.0
from whataa
@SuppressLint("PrivateApi")
@NonNull
public static Context getContext() {
return CONTEXT;
}
19
Source : CountryCodeUtil.java
with Mozilla Public License 2.0
from triplebanana
with Mozilla Public License 2.0
from triplebanana
@SuppressLint("PrivateApi")
private static String getCDMACountryIso() {
try {
// Try to get country code from SystemProperties private clreplaced
Clreplaced<?> systemProperties = Clreplaced.forName("android.os.SystemProperties");
Method get = systemProperties.getMethod("get", String.clreplaced);
// Get homeOperator that contain MCC + MNC
String homeOperator = ((String) get.invoke(systemProperties, "ro.cdma.home.operator.numeric"));
// First 3 chars (MCC) from homeOperator represents the country code
int mcc = Integer.parseInt(homeOperator.substring(0, 3));
// Mapping just countries that actually use CDMA networks
switch(mcc) {
case 330:
return "PR";
case 310:
return "US";
case 311:
return "US";
case 312:
return "US";
case 316:
return "US";
case 283:
return "AM";
case 460:
return "CN";
case 455:
return "MO";
case 414:
return "MM";
case 619:
return "SL";
case 450:
return "KR";
case 634:
return "SD";
case 434:
return "UZ";
case 232:
return "AT";
case 204:
return "NL";
case 262:
return "DE";
case 247:
return "LV";
case 255:
return "UA";
}
} catch (Exception e) {
}
return null;
}
19
Source : IPCMain.java
with Apache License 2.0
from topjohnwu
with Apache License 2.0
from topjohnwu
@SuppressLint("PrivateApi")
public static Context getSystemContext() {
try {
synchronized (Looper.clreplaced) {
if (Looper.getMainLooper() == null)
Looper.prepareMainLooper();
}
Clreplaced<?> atClazz = Clreplaced.forName("android.app.ActivityThread");
Method systemMain = atClazz.getMethod("systemMain");
Object activityThread = systemMain.invoke(null);
Method getSystemContext = atClazz.getMethod("getSystemContext");
return (Context) getSystemContext.invoke(activityThread);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
19
Source : Utils.java
with Apache License 2.0
from topjohnwu
with Apache License 2.0
from topjohnwu
@SuppressLint("PrivateApi")
public static synchronized Context getContext() {
if (context == null) {
UiThreadHandler.runAndWait(() -> {
try {
Method currentApplication = Clreplaced.forName("android.app.ActivityThread").getMethod("currentApplication");
context = (Context) currentApplication.invoke(null);
} catch (Exception e) {
// Shall never happen
Utils.err(e);
}
});
}
return context;
}
19
Source : IActivityManager.java
with Apache License 2.0
from termux
with Apache License 2.0
from termux
/**
* Wrapper around android.app.IActivityManager internal interface
*/
@SuppressLint("PrivateApi")
clreplaced IActivityManager {
private Object mAm;
private CrossVersionReflectedMethod mGetProviderMimeType;
private CrossVersionReflectedMethod mStartActivity;
/*
private CrossVersionReflectedMethod mBroadcastIntent;
*/
private CrossVersionReflectedMethod mStartServiceMethod;
private CrossVersionReflectedMethod mStopServiceMethod;
private CrossVersionReflectedMethod mGetIntentSenderMethod;
private CrossVersionReflectedMethod mIntentSenderSendMethod;
IActivityManager() throws Exception {
this("com.termux");
}
IActivityManager(String callingAppName) throws Exception {
try {
try {
mAm = android.app.ActivityManager.clreplaced.getMethod("getService").invoke(null);
} catch (Exception e) {
mAm = Clreplaced.forName("android.app.ActivityManagerNative").getMethod("getDefault").invoke(null);
}
Clreplaced<?> amClreplaced = mAm.getClreplaced();
mGetProviderMimeType = new CrossVersionReflectedMethod(amClreplaced).tryMethodVariantInexact("getProviderMimeType", Uri.clreplaced, "uri", int.clreplaced, "userId");
mStartActivity = new CrossVersionReflectedMethod(amClreplaced).tryMethodVariantInexact("startActivityAsUser", "android.app.IApplicationThread", "caller", null, String.clreplaced, "callingPackage", callingAppName, Intent.clreplaced, "intent", null, String.clreplaced, "resolvedType", null, IBinder.clreplaced, "resultTo", null, String.clreplaced, "resultWho", null, int.clreplaced, "requestCode", -1, int.clreplaced, "flags", 0, // ProfilerInfo profilerInfo, - let's autodetect
Bundle.clreplaced, "options", null, int.clreplaced, "userId", 0);
/*
mBroadcastIntent =
new CrossVersionReflectedMethod(amClreplaced)
.tryMethodVariantInexact(
"broadcastIntent",
"android.app.IApplicationThread", "caller", null,
Intent.clreplaced, "intent", null,
String.clreplaced, "resolvedType", null,
IIntentReceiver.clreplaced, "resultTo", null,
int.clreplaced, "resultCode", -1,
String.clreplaced, "resultData", null,
Bundle.clreplaced, "map", null,
String[].clreplaced, "requiredPermissions", null,
int.clreplaced, "appOp", 0,
Bundle.clreplaced, "options", null,
boolean.clreplaced, "serialized", false,
boolean.clreplaced, "sticky", false,
int.clreplaced, "userId", 0
);
*/
mStartServiceMethod = new CrossVersionReflectedMethod(amClreplaced).tryMethodVariantInexact("startService", "android.app.IApplicationThread", "caller", null, Intent.clreplaced, "service", null, String.clreplaced, "resolvedType", null, boolean.clreplaced, "requireForeground", false, String.clreplaced, "callingPackage", callingAppName, int.clreplaced, "userId", 0).tryMethodVariantInexact("startService", "android.app.IApplicationThread", "caller", null, Intent.clreplaced, "service", null, String.clreplaced, "resolvedType", null, String.clreplaced, "callingPackage", callingAppName, int.clreplaced, "userId", 0).tryMethodVariantInexact("startService", "android.app.IApplicationThread", "caller", null, Intent.clreplaced, "service", null, String.clreplaced, "resolvedType", null, int.clreplaced, "userId", 0);
mStopServiceMethod = new CrossVersionReflectedMethod(amClreplaced).tryMethodVariantInexact("stopService", "android.app.IApplicationThread", "caller", null, Intent.clreplaced, "service", null, String.clreplaced, "resolvedType", null, int.clreplaced, "userId", 0);
mGetIntentSenderMethod = new CrossVersionReflectedMethod(amClreplaced).tryMethodVariantInexact("getIntentSender", int.clreplaced, "type", 0, String.clreplaced, "packageName", callingAppName, IBinder.clreplaced, "token", null, String.clreplaced, "resultWho", null, int.clreplaced, "requestCode", 0, Intent[].clreplaced, "intents", null, String[].clreplaced, "resolvedTypes", null, int.clreplaced, "flags", 0, Bundle.clreplaced, "options", null, int.clreplaced, "userId", 0);
mIntentSenderSendMethod = new CrossVersionReflectedMethod(Clreplaced.forName("android.content.IIntentSender")).tryMethodVariantInexact("send", int.clreplaced, "code", 0, Intent.clreplaced, "intent", null, String.clreplaced, "resolvedType", null, // IBinder.clreplaced, "android.os.IBinder whitelistToken", null,
"android.content.IIntentReceiver", "finishedReceiver", null, String.clreplaced, "requiredPermission", null, Bundle.clreplaced, "options", null).tryMethodVariantInexact("send", int.clreplaced, "code", 0, Intent.clreplaced, "intent", null, String.clreplaced, "resolvedType", null, "android.content.IIntentReceiver", "finishedReceiver", null, String.clreplaced, "requiredPermission", null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
int startActivityAsUser(Intent intent, String resolvedType, int flags, Bundle options, int userId) throws InvocationTargetException {
return (Integer) mStartActivity.invoke(mAm, "intent", intent, "resolvedType", resolvedType, "flags", flags, "options", options, "userId", userId);
}
void broadcastIntent(Intent intent, IIntentReceiver resultTo, String[] requiredPermissions, boolean serialized, boolean sticky, int userId) throws InvocationTargetException {
/*
mBroadcastIntent.invoke(
mAm,
"intent", intent,
"resultTo", resultTo,
"requiredPermissions", requiredPermissions,
"serialized", serialized,
"sticky", sticky,
"userId", userId
);
*/
Object pendingIntent = mGetIntentSenderMethod.invoke(mAm, "type", 1, /*ActivityManager.INTENT_SENDER_BROADCAST*/
"intents", new Intent[] { intent }, "flags", PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT, "userId", userId);
mIntentSenderSendMethod.invoke(pendingIntent, "requiredPermission", (requiredPermissions == null || requiredPermissions.length == 0) ? null : requiredPermissions[0], "finishedReceiver", resultTo);
}
String getProviderMimeType(Uri uri, int userId) throws InvocationTargetException {
return (String) mGetProviderMimeType.invoke(mAm, "uri", uri, "userId", userId);
}
ComponentName startService(Intent service, String resolvedType, int userId) throws InvocationTargetException {
return (ComponentName) mStartServiceMethod.invoke(mAm, "service", service, "resolvedType", resolvedType, "userId", userId);
}
int stopService(Intent service, String resolvedType, int userId) throws InvocationTargetException {
return (Integer) mStopServiceMethod.invoke(mAm, "service", service, "resolvedType", resolvedType, "userId", userId);
}
}
19
Source : TaskMoverSubModule.java
with Apache License 2.0
from starscryer
with Apache License 2.0
from starscryer
@SuppressLint("PrivateApi")
Method methodForTaskMover(XC_LoadPackage.LoadPackageParam lpparam) throws ClreplacedNotFoundException, NoSuchMethodException {
throw new IllegalStateException("Need impl here");
}
19
Source : MemoryFileUtils.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
/**
* Created by rikka on 2017/9/27.
*/
@SuppressLint("PrivateApi")
public clreplaced MemoryFileUtils {
private static Method getFileDescriptorMethod;
static {
try {
getFileDescriptorMethod = MemoryFile.clreplaced.getDeclaredMethod("getFileDescriptor");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static FileDescriptor getFileDescriptor(MemoryFile mf) {
if (getFileDescriptorMethod != null) {
try {
return (FileDescriptor) getFileDescriptorMethod.invoke(mf);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
return null;
}
public static MemoryFile fromreplacedet(replacedetManager am, String filename, int length) {
MemoryFile mf = null;
try {
mf = new MemoryFile(filename, length);
InputStream is = am.open(filename);
OutputStream os = mf.getOutputStream();
IOUtils.copy(is, os);
return mf;
} catch (IOException e) {
if (mf != null) {
mf.close();
}
return null;
}
}
public static MemoryFile fromFile(File file) {
MemoryFile mf = null;
try {
mf = new MemoryFile(file.getName(), (int) file.length());
InputStream is = new FileInputStream(file);
OutputStream os = mf.getOutputStream();
IOUtils.copy(is, os);
return mf;
} catch (IOException e) {
if (mf != null) {
mf.close();
}
return null;
}
}
}
19
Source : TypefaceCompatApi21.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
@SuppressLint("PrivateApi")
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public clreplaced TypefaceCompatApi21 {
private static boolean available = true;
private static Method createFromFamiliesWithDefaultMethod;
static {
try {
createFromFamiliesWithDefaultMethod = Typeface.clreplaced.getDeclaredMethod("createFromFamiliesWithDefault", FontFamilyCompat.getFontFamilyArrayClreplaced());
createFromFamiliesWithDefaultMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
available = false;
}
}
@Nullable
public static Typeface createFromFamiliesWithDefault(Object families) {
if (!available) {
return null;
}
try {
return (Typeface) createFromFamiliesWithDefaultMethod.invoke(null, families);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
}
19
Source : FontFamilyCompat.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
@SuppressLint("PrivateApi")
public clreplaced FontFamilyCompat {
private static Clreplaced<?> cls;
static {
try {
cls = Clreplaced.forName("android.graphics.FontFamily");
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
public static Clreplaced<?> getFontFamilyClreplaced() {
return cls;
}
public static Clreplaced<?> getFontFamilyArrayClreplaced() {
return Array.newInstance(cls, 0).getClreplaced();
}
private static FontFamilyImpl sImpl;
private static FontFamilyImpl getImpl() {
if (sImpl != null) {
return sImpl;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
sImpl = new FontFamilyImpl26();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
sImpl = new FontFamilyImpl24();
} else {
sImpl = new FontFamilyImpl21();
}
return sImpl;
}
private Object mFontFamily;
/**
* Create FontFamily with lang and variant.
*
* @param lang Language
* @param variant Variant (0, 1 - compact, 2 - elegant)
*/
public FontFamilyCompat(String lang, int variant) {
this(getImpl().create(lang, variant));
}
private FontFamilyCompat(Object fontFamily) {
mFontFamily = fontFamily;
}
/**
* Get real android.graphics.FontFamily object.
*
* @return FontFamily object
*/
@Nullable
public Object getFontFamily() {
return mFontFamily;
}
/**
* Add font to this FontFamily.
*
* @param font font file buffer
* @param ttcIndex ttc index
* @param weight The weight of the font.
* @param italic Whether this font is italic.
* @return returns false if some error happens in native code.
*/
public boolean addFont(ByteBuffer font, int ttcIndex, int weight, int italic) {
return getImpl().addFont(getFontFamily(), font, ttcIndex, weight, italic);
}
/**
* Add font to this FontFamily.
*
* @param path font file path
* @param weight The weight of the font.
* @param italic Whether this font is italic.
* @return returns false if some error happens in native code.
*/
public boolean addFont(String path, int weight, int italic) {
return getImpl().addFont(getFontFamily(), path, weight, italic);
}
/**
* Finalize the FontFamily creation, always return true on pre-API 26.
*
* @return boolean returns false if some error happens in native code, e.g. broken font file is
* preplaceded, etc.
*/
public boolean freeze() {
return getImpl().freeze(getFontFamily());
}
}
19
Source : MiuiUtils.java
with GNU General Public License v3.0
from redsolver
with GNU General Public License v3.0
from redsolver
@SuppressLint("PrivateApi")
public static boolean isMiuiOptimizationDisabled() {
if ("0".equals(Utils.getSystemProperty("persist.sys.miui_optimization")))
return true;
try {
return (boolean) Clreplaced.forName("android.miui.AppOpsUtils").getDeclaredMethod("isXOptMode").invoke(null);
} catch (Exception e) {
return false;
}
}
19
Source : MiuiUtils.java
with GNU General Public License v3.0
from MuntashirAkon
with GNU General Public License v3.0
from MuntashirAkon
@SuppressLint("PrivateApi")
public static boolean isMiuiOptimizationDisabled() {
if (!SystemProperties.getBoolean("persist.sys.miui_optimization", true)) {
return true;
}
try {
return (boolean) Clreplaced.forName("android.miui.AppOpsUtils").getDeclaredMethod("isXOptMode").invoke(null);
} catch (Exception e) {
return false;
}
}
19
Source : MainPreferences.java
with GNU General Public License v3.0
from MuntashirAkon
with GNU General Public License v3.0
from MuntashirAkon
@SuppressLint("PrivateApi")
private double getBatteryCapacity() {
double capacity = -1.0;
try {
Object powerProfile = Clreplaced.forName("com.android.internal.os.PowerProfile").getConstructor(Context.clreplaced).newInstance(activity.getApplication());
// noinspection ConstantConditions
capacity = (double) Clreplaced.forName("com.android.internal.os.PowerProfile").getMethod("getAveragePower", String.clreplaced).invoke(powerProfile, "battery.capacity");
} catch (Exception e) {
e.printStackTrace();
}
return capacity;
}
19
Source : CondomProcess.java
with GNU General Public License v3.0
from MiPushFramework
with GNU General Public License v3.0
from MiPushFramework
@SuppressLint("PrivateApi")
private static void installCondomProcessPackageManager(final CondomCore condom) throws ClreplacedNotFoundException, NoSuchFieldException, IllegalAccessException {
final Clreplaced<?> ActivityThread = Clreplaced.forName("android.app.ActivityThread");
final Field ActivityThread_sPackageManager = ActivityThread.getDeclaredField("sPackageManager");
ActivityThread_sPackageManager.setAccessible(true);
final Clreplaced<?> IPackageManager = Clreplaced.forName("android.content.pm.IPackageManager");
final Object pm = ActivityThread_sPackageManager.get(null);
if (Proxy.isProxyClreplaced(pm.getClreplaced()) && Proxy.getInvocationHandler(pm) instanceof CondomProcessPackageManager) {
Log.d(TAG, "CondomPackageManager is already installed in this process.");
return;
}
final Object condom_pm = Proxy.newProxyInstance(condom.mBase.getClreplacedLoader(), new Clreplaced[] { IPackageManager }, new CondomProcessPackageManager(condom, pm));
ActivityThread_sPackageManager.set(null, condom_pm);
}
19
Source : HttpSSLResponseCodec.java
with MIT License
from MegatronKing
with MIT License
from MegatronKing
@SuppressLint("PrivateApi")
private String getAlpnSelectedProtocol() {
if (!mAlpnEnabled) {
return null;
}
String alpnResult = null;
try {
String sslEngineName = mSSLEngine.getClreplaced().getSimpleName();
if (sslEngineName.equals("Java8EngineWrapper")) {
alpnResult = getJava8EngineWrapperAlpn();
} else if (sslEngineName.equals("ConscryptEngine")) {
alpnResult = getConscryptEngineAlpn();
} else {
alpnResult = getOpenSSLEngineImplAlpn();
}
} catch (ClreplacedNotFoundException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
NetBareLog.e(e.getMessage());
}
return alpnResult;
}
19
Source : SystemProperties.java
with Apache License 2.0
from lzls
with Apache License 2.0
from lzls
/**
* @author 刘振林
*/
@SuppressLint("PrivateApi")
public clreplaced SystemProperties {
private SystemProperties() {
}
public static String getString(String key, String def) {
try {
Clreplaced<?> clz = Clreplaced.forName("android.os.SystemProperties");
Method get = clz.getMethod("get", String.clreplaced, String.clreplaced);
return (String) get.invoke(clz, key, def);
} catch (Exception e) {
e.printStackTrace();
}
return def;
}
public static String getString(String key) {
return getString(key, "");
}
public static long getLong(String key, long def) {
try {
Clreplaced<?> clz = Clreplaced.forName("android.os.SystemProperties");
Method getLong = clz.getMethod("getLong", String.clreplaced, long.clreplaced);
Long ret = (Long) getLong.invoke(clz, key, def);
return ret != null ? ret : def;
} catch (Exception e) {
e.printStackTrace();
}
return def;
}
public static long getLong(String key) {
return getLong(key, 0L);
}
public static int getInt(String key, int def) {
try {
Clreplaced<?> clz = Clreplaced.forName("android.os.SystemProperties");
Method getInt = clz.getMethod("getInt", String.clreplaced, int.clreplaced);
Integer ret = (Integer) getInt.invoke(clz, key, def);
return ret != null ? ret : def;
} catch (Exception e) {
e.printStackTrace();
}
return def;
}
public static int getInt(String key) {
return getInt(key, 0);
}
public static boolean getBoolean(String key, boolean def) {
try {
Clreplaced<?> clz = Clreplaced.forName("android.os.SystemProperties");
Method getBoolean = clz.getMethod("getBoolean", String.clreplaced, boolean.clreplaced);
Boolean ret = (Boolean) getBoolean.invoke(clz, key, def);
return ret != null ? ret : def;
} catch (Exception e) {
e.printStackTrace();
}
return def;
}
public static boolean getBoolean(String key) {
return getBoolean(key, false);
}
/**
* 通过反射设置系统属性
*/
public static void setProperty(String key, String value) {
try {
Clreplaced<?> clz = Clreplaced.forName("android.os.SystemProperties");
Method set = clz.getMethod("set", String.clreplaced, String.clreplaced);
set.invoke(clz, key, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
19
Source : ScreenUtil.java
with Apache License 2.0
from lx8421bcd
with Apache License 2.0
from lx8421bcd
/**
* 获取status bar高度
* @return status bar height in px value
*/
@SuppressLint("PrivateApi")
public static int getStatusBarHeight() {
int statusBarHeight = 0;
try {
Clreplaced<?> clazz = Clreplaced.forName("com.android.internal.R$dimen");
Object obj = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height").get(obj).toString());
statusBarHeight = ContextProvider.get().getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusBarHeight;
}
19
Source : ActivityTranslucentUtil.java
with Apache License 2.0
from luckybilly
with Apache License 2.0
from luckybilly
/**
* @author billy.qi
*/
@SuppressLint("PrivateApi")
public clreplaced ActivityTranslucentUtil {
private static Clreplaced mTranslucentConversionListenerClreplaced;
private static Method mMethodConvertFromTranslucent;
private static Method mMethodConvertToTranslucent;
private static Method mMethodGetActivityOptions;
private static boolean mInitialedConvertToTranslucent;
private static boolean mInitialedConvertFromTranslucent;
private Activity mActivity;
private boolean mIsTranslucent;
public ActivityTranslucentUtil(Activity activity) {
this.mActivity = activity;
}
public static void convertWindowToTranslucent(Activity activity) {
if (activity != null) {
View contentView = activity.findViewById(android.R.id.content);
Drawable background = contentView.getBackground();
if (background == null) {
TypedArray a = activity.getTheme().obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
int windowBg = a.getResourceId(0, 0);
a.recycle();
if (windowBg != 0) {
contentView.setBackgroundResource(windowBg);
}
}
Window window = activity.getWindow();
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.getDecorView().setBackgroundDrawable(null);
SmartSwipeWrapper wrapper = SmartSwipe.peekWrapperFor(activity);
if (wrapper != null) {
wrapper.setBackgroundColor(Color.TRANSPARENT);
}
}
}
private MessageQueue.IdleHandler convertActivityToTranslucentIdleHandler = new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
convertActivityToTranslucent();
return false;
}
};
private long convertTranslucentTimeStamp;
public void convertActivityToTranslucent() {
convertActivityToTranslucent(true);
}
public void convertActivityToTranslucent(final boolean retry) {
if (mIsTranslucent || mActivity == null) {
return;
}
if (convertingActivity != null) {
Looper.myQueue().addIdleHandler(convertActivityToTranslucentIdleHandler);
return;
}
convertTranslucentTimeStamp = SystemClock.elapsedRealtime();
final long callbackTimeStamp = convertTranslucentTimeStamp;
convertActivityToTranslucent(mActivity, new ActivityTranslucentUtil.TranslucentCallback() {
@Override
public void onTranslucentCallback(boolean translucent) {
if (callbackTimeStamp == convertTranslucentTimeStamp) {
if (retry && !translucent) {
convertActivityToTranslucent(false);
} else {
setTranslucent(translucent);
}
}
}
});
}
public void convertActivityFromTranslucent() {
convertTranslucentTimeStamp = SystemClock.elapsedRealtime();
convertActivityFromTranslucent(mActivity);
setTranslucent(false);
}
private void setTranslucent(boolean translucent) {
this.mIsTranslucent = translucent;
}
public boolean isTranslucent() {
return mIsTranslucent;
}
/**
* record the converting activity, resolve more than 1 xxUIs add onto the same activity
*/
private static WeakReference<Activity> convertingActivity;
/**
* Reflect call Activity.convertToTranslucent(...)
* @param activity activity
* @param callback callback
*/
public static void convertActivityToTranslucent(Activity activity, final TranslucentCallback callback) {
convertingActivity = new WeakReference<>(activity);
Object mTranslucentConversionListener = null;
try {
if (mTranslucentConversionListenerClreplaced == null) {
Clreplaced[] clazzArray = Activity.clreplaced.getDeclaredClreplacedes();
for (Clreplaced clazz : clazzArray) {
if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
mTranslucentConversionListenerClreplaced = clazz;
}
}
}
// resolve black flash at the beginning:
// Activity.convertToTranslucent(...) will takes tens of milliseconds
// thanks: https://github.com/Simon-Leeeeeeeee/SLWidget/blob/master/swipeback/src/main/java/cn/simonlee/widget/swipeback/SwipeBackHelper.java
if (mTranslucentConversionListenerClreplaced != null) {
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
boolean translucent = false;
if (args != null && args.length == 1) {
translucent = (Boolean) args[0];
}
convertCallback(callback, translucent);
return null;
}
};
mTranslucentConversionListener = Proxy.newProxyInstance(mTranslucentConversionListenerClreplaced.getClreplacedLoader(), new Clreplaced[] { mTranslucentConversionListenerClreplaced }, invocationHandler);
}
if (mMethodConvertToTranslucent == null && mInitialedConvertToTranslucent) {
convertCallback(callback, false);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mMethodConvertToTranslucent == null) {
mInitialedConvertToTranslucent = true;
Method getActivityOptions = Activity.clreplaced.getDeclaredMethod("getActivityOptions");
getActivityOptions.setAccessible(true);
mMethodGetActivityOptions = getActivityOptions;
Method method = Activity.clreplaced.getDeclaredMethod("convertToTranslucent", mTranslucentConversionListenerClreplaced, ActivityOptions.clreplaced);
method.setAccessible(true);
mMethodConvertToTranslucent = method;
}
Object options = mMethodGetActivityOptions.invoke(activity);
mMethodConvertToTranslucent.invoke(activity, mTranslucentConversionListener, options);
} else {
if (mMethodConvertToTranslucent == null) {
mInitialedConvertToTranslucent = true;
Method method = Activity.clreplaced.getDeclaredMethod("convertToTranslucent", mTranslucentConversionListenerClreplaced);
method.setAccessible(true);
mMethodConvertToTranslucent = method;
}
mMethodConvertToTranslucent.invoke(activity, mTranslucentConversionListener);
}
if (mTranslucentConversionListener == null) {
convertCallback(callback, false);
}
} catch (Throwable ignored) {
convertCallback(callback, false);
}
}
private static void convertCallback(TranslucentCallback callback, boolean translucent) {
if (callback != null) {
callback.onTranslucentCallback(translucent);
}
convertingActivity = null;
}
public static void convertActivityFromTranslucent(Activity activity) {
if (activity == null) {
return;
}
if (convertingActivity != null && convertingActivity.get() == activity) {
convertingActivity = null;
}
try {
if (mMethodConvertFromTranslucent == null) {
if (mInitialedConvertFromTranslucent) {
return;
}
mInitialedConvertFromTranslucent = true;
Method method = Activity.clreplaced.getDeclaredMethod("convertFromTranslucent");
method.setAccessible(true);
mMethodConvertFromTranslucent = method;
}
mMethodConvertFromTranslucent.invoke(activity);
} catch (Throwable ignored) {
}
}
public interface TranslucentCallback {
void onTranslucentCallback(boolean translucent);
}
}
19
Source : ShortcutPackageParser.java
with GNU General Public License v3.0
from LawnchairLauncher
with GNU General Public License v3.0
from LawnchairLauncher
@SuppressLint("PrivateApi")
private int loadApkIntoreplacedetManager() throws PackageManager.NameNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(mPackageName, PackageManager.GET_META_DATA | PackageManager.GET_SHARED_LIBRARY_FILES);
Method addreplacedetPath = replacedetManager.clreplaced.getDeclaredMethod("addreplacedetPath", String.clreplaced);
int cookie = (int) addreplacedetPath.invoke(mreplacedets, info.publicSourceDir);
if (cookie == 0) {
throw new RuntimeException("Failed adding replacedet path: " + info.publicSourceDir);
}
return cookie;
}
19
Source : ConfigUtils.java
with GNU General Public License v3.0
from langgithub
with GNU General Public License v3.0
from langgithub
@SuppressLint("PrivateApi")
public static int setFilePermissions(File path, int chmod, int uid, int gid) {
Clreplaced<?> cls;
try {
cls = Clreplaced.forName("android.os.FileUtils");
Method method = cls.getMethod("setPermissions", File.clreplaced, int.clreplaced, int.clreplaced, int.clreplaced);
return (int) method.invoke(null, path, chmod, uid, gid);
} catch (Exception e) {
Log.i("Xposed", Log.getStackTraceString(e));
return 1;
}
}
19
Source : ServiceManager.java
with Apache License 2.0
from huanglqweiwei
with Apache License 2.0
from huanglqweiwei
@SuppressLint("PrivateApi")
public final clreplaced ServiceManager {
private final Method getServiceMethod;
private DisplayManager displayManager;
private InputManager inputManager;
private PowerManager powerManager;
public ServiceManager() {
try {
getServiceMethod = Clreplaced.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.clreplaced);
} catch (Exception e) {
throw new replacedertionError(e);
}
}
private IInterface getService(String service, String type) {
try {
IBinder binder = (IBinder) getServiceMethod.invoke(null, service);
Method asInterfaceMethod = Clreplaced.forName(type + "$Stub").getMethod("asInterface", IBinder.clreplaced);
return (IInterface) asInterfaceMethod.invoke(null, binder);
} catch (Exception e) {
throw new replacedertionError(e);
}
}
public DisplayManager getDisplayManager() {
if (displayManager == null) {
displayManager = new DisplayManager(getService("display", "android.hardware.display.IDisplayManager"));
}
return displayManager;
}
public InputManager getInputManager() {
if (inputManager == null) {
inputManager = new InputManager(getService("input", "android.hardware.input.IInputManager"));
}
return inputManager;
}
public PowerManager getPowerManager() {
if (powerManager == null) {
powerManager = new PowerManager(getService("power", "android.os.IPowerManager"));
}
return powerManager;
}
}
19
Source : BaseActivity.java
with Apache License 2.0
from huanghaibin-dev
with Apache License 2.0
from huanghaibin-dev
/**
* 设置小米黑色状态栏字体
*/
@SuppressLint("PrivateApi")
private void setMIUIStatusBarDarkMode() {
if (isMiUi) {
Clreplaced<? extends Window> clazz = getWindow().getClreplaced();
try {
int darkModeFlag;
Clreplaced<?> layoutParams = Clreplaced.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.clreplaced, int.clreplaced);
extraFlagField.invoke(getWindow(), darkModeFlag, darkModeFlag);
} catch (Exception e) {
e.printStackTrace();
}
}
}
19
Source : Utils.java
with Apache License 2.0
from ExploiTR
with Apache License 2.0
from ExploiTR
@SuppressLint("PrivateApi")
@Nullable
private static Clreplaced<?> getSystemPropertiesClreplaced() {
try {
return Clreplaced.forName("android.os.SystemProperties");
} catch (ClreplacedNotFoundException shouldNotHappen) {
return null;
}
}
19
Source : XOverrideHeadphoneJackDetection.java
with GNU General Public License v3.0
from anton-arnold
with GNU General Public License v3.0
from anton-arnold
@SuppressLint("PrivateApi")
private static Application getApplicationUsingReflection() throws Exception {
return (Application) Clreplaced.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null, (Object[]) null);
}
19
Source : WebViewCompat.java
with Apache License 2.0
from androidx
with Apache License 2.0
from androidx
/**
* Return the PackageInfo of the currently loaded WebView APK. This method uses reflection and
* propagates any exceptions thrown, to the caller.
*/
@SuppressLint("PrivateApi")
private static PackageInfo getLoadedWebViewPackageInfo() throws ClreplacedNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Clreplaced<?> webViewFactoryClreplaced = Clreplaced.forName("android.webkit.WebViewFactory");
return (PackageInfo) webViewFactoryClreplaced.getMethod("getLoadedPackageInfo").invoke(null);
}
19
Source : ProviderHelper23.java
with Apache License 2.0
from androidmalin
with Apache License 2.0
from androidmalin
@SuppressLint("PrivateApi")
clreplaced ProviderHelper23 {
private static final String TAG = "ProviderHelper";
/**
* 在进程内部安装provider, 也就是调用 ActivityThread.installContentProviders方法
*/
@SuppressWarnings("JavaReflectionMemberAccess")
@SuppressLint("DiscouragedPrivateApi")
static void installProviders(Context context, File apkFile) {
try {
List<ProviderInfo> providerInfoList = parseProviders(apkFile);
if (providerInfoList == null) {
Log.e(TAG, "providerInfoList==null");
return;
}
for (ProviderInfo providerInfo : providerInfoList) {
providerInfo.applicationInfo.packageName = context.getPackageName();
}
Log.d(TAG, providerInfoList.toString());
Clreplaced<?> activityThreadClreplaced = Clreplaced.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClreplaced.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// private void installContentProviders(Context context, List<ProviderInfo> providers) {
Method installProvidersMethod = activityThreadClreplaced.getDeclaredMethod("installContentProviders", Context.clreplaced, List.clreplaced);
installProvidersMethod.setAccessible(true);
installProvidersMethod.invoke(currentActivityThread, context, providerInfoList);
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 解析Apk文件中的 <provider>, 并存储起来
* 主要是调用PackageParser类的generateProviderInfo方法
*
* @param apkFile 插件对应的apk文件
*/
@SuppressWarnings("JavaReflectionInvocation")
@SuppressLint("DiscouragedPrivateApi")
private static List<ProviderInfo> parseProviders(File apkFile) {
try {
Clreplaced<?> packageParserClreplaced = Clreplaced.forName("android.content.pm.PackageParser");
// public Package parsePackage(File packageFile, int flags){}//api-23
Method parsePackageMethod = packageParserClreplaced.getDeclaredMethod("parsePackage", File.clreplaced, int.clreplaced);
parsePackageMethod.setAccessible(true);
// public PackageParser() {}//api-23默认构造方法
Object packageParser = packageParserClreplaced.newInstance();
// 首先调用parsePackage获取到apk对象对应的Package对象
Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_PROVIDERS);
if (packageObj == null)
return null;
// android.content.pm.PackageParser$Package
// 读取Package对象里面的services字段
// 接下来要做的就是根据这个List<Provider> 获取到Provider对应的ProviderInfo
// public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
Field providersField = packageObj.getClreplaced().getDeclaredField("providers");
List<?> providers = (List<?>) providersField.get(packageObj);
if (providers == null) {
Log.e(TAG, "providers == null");
return null;
}
// 调用generateProviderInfo 方法, 把PackageParser.Provider转换成ProviderInfo
Clreplaced<?> packageParser$ProviderClreplaced = Clreplaced.forName("android.content.pm.PackageParser$Provider");
Clreplaced<?> packageUserStateClreplaced = Clreplaced.forName("android.content.pm.PackageUserState");
Clreplaced<?> userHandler = Clreplaced.forName("android.os.UserHandle");
// public static final int getCallingUserId(){}
Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId");
getCallingUserIdMethod.setAccessible(true);
Object userIdObj = getCallingUserIdMethod.invoke(null);
if (!(userIdObj instanceof Integer))
return null;
int userId = (Integer) userIdObj;
// public PackageUserState() {}//api-23默认构造方法
Object defaultUserState = packageUserStateClreplaced.newInstance();
// 需要调用 android.content.pm.PackageParser#generateProviderInfo
// public static final ProviderInfo generateProviderInfo(Provider p, int flags,PackageUserState state, int userId) {}//api-23
Method generateProviderInfo = packageParserClreplaced.getDeclaredMethod("generateProviderInfo", packageParser$ProviderClreplaced, int.clreplaced, packageUserStateClreplaced, int.clreplaced);
generateProviderInfo.setAccessible(true);
List<ProviderInfo> ret = new ArrayList<>();
// 解析出intent对应的Provider组件
for (Object service : providers) {
ProviderInfo info = (ProviderInfo) generateProviderInfo.invoke(packageParser, service, 0, defaultUserState, userId);
ret.add(info);
}
return ret;
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
}
19
Source : ProviderHelper.java
with Apache License 2.0
from androidmalin
with Apache License 2.0
from androidmalin
/**
* 目前的bug是:
* 当target>=26时, java.lang.SecurityException: Failed to find provider com.malin.auth.xx for user 0; expected to find a valid ContentProvider for this authority
* target>=26;崩溃的问题;调试方法
* 在ComponentResolver类的ProviderInfo queryProvider(String authority, int flags, int userId) {}方法增加断点;
* 在模拟器上运行,给system_server进程断点;查看发现;调用方法queryProvider时全局变量mProvidersByAuthority中没有插件的Authority;
* 方法返回值为null;在外层调用处,进行了版本判断,target>=26;就异常了;
* mProvidersByAuthority变量的赋值在系统进程中;目前没有解决办法了;
* <p>
* com/android/server/am/ActivityManagerService.java
* 发生在server进程里的public String checkContentProviderAccess(String authority, int userId) {}方法里,
* 调用了 com/android/server/pm/PackageManagerService.java 里的resolveContentProvider(),
* 无法通过hook IPackageManager来解决.因为调用发生在server进程里.
* https://agehua.github.io/2017/07/12/android-noroot-hook/
*/
@SuppressLint("PrivateApi")
clreplaced ProviderHelper {
private static final String TAG = "ProviderHelper";
/**
* 在进程内部安装provider, 也就是调用 ActivityThread.installContentProviders方法
*/
@SuppressWarnings("JavaReflectionMemberAccess")
@SuppressLint("DiscouragedPrivateApi")
static void installProviders(Context context, File apkFile) {
try {
// 1.get ProviderInfo
List<ProviderInfo> providerInfoList = parseProviders(apkFile);
if (providerInfoList == null) {
Log.d(TAG, "providerInfoList==null");
return;
}
String path = apkFile.getCanonicalPath();
int i = 0;
// 2.set packageName
for (ProviderInfo providerInfo : providerInfoList) {
providerInfo.applicationInfo.packageName = context.getPackageName();
ApplicationInfoUtil.fixApplicationInfo(providerInfo.applicationInfo, path);
printProviderInfo(providerInfo, i);
i++;
}
Log.d(TAG, providerInfoList.toString());
// 3.get currentActivityThread
Clreplaced<?> activityThreadClazz = Clreplaced.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClazz.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// 4.call ActivityThread#installContentProviders()
// private void installContentProviders(Context context, List<ProviderInfo> providers) {}//15=<api<=29
Method installContentProvidersMethod = activityThreadClazz.getDeclaredMethod("installContentProviders", Context.clreplaced, List.clreplaced);
installContentProvidersMethod.setAccessible(true);
installContentProvidersMethod.invoke(currentActivityThread, context, providerInfoList);
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 解析Apk文件中的 <provider>, 并存储起来
* 主要是调用PackageParser类的generateProviderInfo方法
*
* @param apkFile 插件对应的apk文件
*/
@SuppressLint("DiscouragedPrivateApi")
@SuppressWarnings({ "JavaReflectionMemberAccess", "JavaReflectionInvocation" })
private static List<ProviderInfo> parseProviders(File apkFile) {
try {
int version = Build.VERSION.SDK_INT;
if (version < 15)
return null;
// 1.获取PackageParser的Clreplaced对象
// package android.content.pm
// public clreplaced PackageParser
Clreplaced<?> packageParserClazz = Clreplaced.forName("android.content.pm.PackageParser");
// 2.获取parsePackage()方法的Method
Method parsePackageMethod;
if (Build.VERSION.SDK_INT >= 20) {
// public Package parsePackage(File packageFile, int flags) throws PackageParserException {}//21=<api<=29
parsePackageMethod = packageParserClazz.getDeclaredMethod("parsePackage", File.clreplaced, int.clreplaced);
} else {
// public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) {}//15=<api<=19
// 15<=Build.VERSION.SDK_INT <=19
parsePackageMethod = packageParserClazz.getDeclaredMethod("parsePackage", File.clreplaced, String.clreplaced, DisplayMetrics.clreplaced, int.clreplaced);
}
parsePackageMethod.setAccessible(true);
// 3.生成PackageParser对象实例
Object packageParser;
if (Build.VERSION.SDK_INT >= 20) {
packageParser = packageParserClazz.newInstance();
} else {
// 15<=Build.VERSION.SDK_INT <=19
// public PackageParser(String archiveSourcePath) {}//15=<api<=19
Constructor<?> constructor = packageParserClazz.getDeclaredConstructor(String.clreplaced);
constructor.setAccessible(true);
String archiveSourcePath = apkFile.getCanonicalPath();
packageParser = constructor.newInstance(archiveSourcePath);
}
// 4.调用parsePackage获取到apk对象对应的Package对象(return information about intent receivers in the package)
// Package为PackageParser的内部类;public final static clreplaced Package implements Parcelable {}
Object packageObj;
if (Build.VERSION.SDK_INT >= 20) {
// public Package parsePackage(File packageFile, int flags) throws PackageParserException {}//21=<api<=29
packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_PROVIDERS);
} else {
// 15<=Build.VERSION.SDK_INT <=19
String destCodePath = apkFile.getCanonicalPath();
DisplayMetrics displayMetrics = new DisplayMetrics();
displayMetrics.setToDefaults();
// public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) {}//15=<api<=19
packageObj = parsePackageMethod.invoke(packageParser, apkFile, destCodePath, displayMetrics, PackageManager.GET_PROVIDERS);
}
if (packageObj == null)
return null;
// android.content.pm.PackageParser$Package
// 读取Package对象里面的providers字段
// 接下来要做的就是根据这个List<Provider> 获取到Provider对应的ProviderInfo
// public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
Field providersField = packageObj.getClreplaced().getDeclaredField("providers");
List<?> providers = (List<?>) providersField.get(packageObj);
if (providers == null) {
Log.d(TAG, "providers == null");
return null;
}
Clreplaced<?> packageParser$ProviderClazz = Clreplaced.forName("android.content.pm.PackageParser$Provider");
// 5.call generateProviderInfo()
// public static final ProviderInfo generateProviderInfo(Provider p, int flags, PackageUserState state, int userId) {}//api-29
// ...
// public static final ProviderInfo generateProviderInfo(Provider p, int flags, PackageUserState state, int userId) {}//api-17
// public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped,int enabledState, int userId) {}//api-16
// public static final ProviderInfo generateProviderInfo(Provider p,int flags) {}//api-15
Method generateProviderInfo;
if (Build.VERSION.SDK_INT >= 17) {
// 调用generateProviderInfo 方法, 把PackageParser.Provider转换成ProviderInfo
Clreplaced<?> packageUserStateClazz = Clreplaced.forName("android.content.pm.PackageUserState");
Clreplaced<?> userHandlerClazz = Clreplaced.forName("android.os.UserHandle");
// public static final int getCallingUserId(){}
Method getCallingUserIdMethod = userHandlerClazz.getDeclaredMethod("getCallingUserId");
getCallingUserIdMethod.setAccessible(true);
Object userIdObj = getCallingUserIdMethod.invoke(null);
if (!(userIdObj instanceof Integer))
return null;
int userId = (Integer) userIdObj;
// public PackageUserState() {}//api-23默认构造方法
Object defaultUserState = packageUserStateClazz.newInstance();
// 需要调用 android.content.pm.PackageParser#generateProviderInfo
// public static final ProviderInfo generateProviderInfo(Provider p, int flags, PackageUserState state, int userId) {}//17=<api<=29
// public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped,int enabledState, int userId) {}//api-16
// public static final ProviderInfo generateProviderInfo(Provider p,int flags) {}//api-15
generateProviderInfo = packageParserClazz.getDeclaredMethod("generateProviderInfo", packageParser$ProviderClazz, int.clreplaced, packageUserStateClazz, int.clreplaced);
generateProviderInfo.setAccessible(true);
List<ProviderInfo> ret = new ArrayList<>();
// 解析出intent对应的Provider组件
for (Object provider : providers) {
ProviderInfo info = (ProviderInfo) generateProviderInfo.invoke(packageParser, provider, 0, defaultUserState, userId);
ret.add(info);
}
return ret;
} else if (Build.VERSION.SDK_INT == 16) {
Clreplaced<?> userIdClazz = Clreplaced.forName("android.os.UserId");
// public static final int getCallingUserId(){}
Method getCallingUserIdMethod = userIdClazz.getDeclaredMethod("getCallingUserId");
getCallingUserIdMethod.setAccessible(true);
Object userIdObj = getCallingUserIdMethod.invoke(null);
if (!(userIdObj instanceof Integer))
return null;
int userId = (Integer) userIdObj;
// public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped,int enabledState, int userId) {}//api-16
generateProviderInfo = packageParserClazz.getDeclaredMethod("generateProviderInfo", packageParser$ProviderClazz, int.clreplaced, boolean.clreplaced, int.clreplaced, int.clreplaced);
generateProviderInfo.setAccessible(true);
List<ProviderInfo> ret = new ArrayList<>();
// 解析出intent对应的Provider组件
for (Object provider : providers) {
int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
ProviderInfo info = (ProviderInfo) generateProviderInfo.invoke(packageParser, provider, 0, false, enabledState, userId);
ret.add(info);
}
return ret;
} else {
// Build.VERSION.SDK_INT==15
// public static final ProviderInfo generateProviderInfo(Provider p,int flags) {}//api-15
generateProviderInfo = packageParserClazz.getDeclaredMethod("generateProviderInfo", packageParser$ProviderClazz, int.clreplaced);
generateProviderInfo.setAccessible(true);
List<ProviderInfo> ret = new ArrayList<>();
// 解析出intent对应的Provider组件
for (Object provider : providers) {
ProviderInfo info = (ProviderInfo) generateProviderInfo.invoke(packageParser, provider, 0);
ret.add(info);
}
return ret;
}
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static void printProviderInfo(ProviderInfo providerInfo, int i) {
String name = providerInfo.name;
String authority = providerInfo.authority;
String readPermission = providerInfo.readPermission;
String writePermission = providerInfo.writePermission;
boolean grantUriPermissions = providerInfo.grantUriPermissions;
boolean multiProcess = providerInfo.multiprocess;
int initOrder = providerInfo.initOrder;
PatternMatcher[] uriPermissionPatterns = providerInfo.uriPermissionPatterns;
PathPermission[] pathPermissions = providerInfo.pathPermissions;
Log.d(TAG, i + "==============");
Log.d(TAG, "name:" + name);
Log.d(TAG, "authority:" + authority);
Log.d(TAG, "readPermission:" + readPermission);
Log.d(TAG, "writePermission:" + writePermission);
Log.d(TAG, "grantUriPermissions:" + grantUriPermissions);
Log.d(TAG, "multiprocess:" + multiProcess);
Log.d(TAG, "initOrder:" + initOrder);
Log.d(TAG, "uriPermissionPatterns:" + Arrays.toString(uriPermissionPatterns));
Log.d(TAG, "pathPermissions:" + Arrays.toString(pathPermissions));
Log.d(TAG, "applicationInfo.packageName:" + providerInfo.applicationInfo.packageName);
Log.d(TAG, "applicationInfo.name:" + providerInfo.applicationInfo.name);
Log.d(TAG, i + "==============");
}
}
19
Source : HookInstrumentation.java
with Apache License 2.0
from androidmalin
with Apache License 2.0
from androidmalin
/**
* Activity插件化 Hook Instrumentation
* 代码参考 android 进阶解密第十五章
*/
@SuppressLint("PrivateApi")
clreplaced HookInstrumentation {
private static final String TARGET_INTENT_CLreplaced = "target_intent_clreplaced";
static void hookInstrumentation(Context context) {
try {
// 1.ContextImpl-->mMainThread
// package android.app
// clreplaced ContextImpl
Clreplaced<?> contextImplClazz = Clreplaced.forName("android.app.ContextImpl");
// final @NonNull ActivityThread mMainThread;
Field mMainThreadField = contextImplClazz.getDeclaredField("mMainThread");
mMainThreadField.setAccessible(true);
// 2.ActivityThread Object
Object activityThreadObj = mMainThreadField.get(context);
// 3.mInstrumentation Object
Clreplaced<?> activityThreadClazz = Clreplaced.forName("android.app.ActivityThread");
// Instrumentation mInstrumentation;
Field mInstrumentationField = activityThreadClazz.getDeclaredField("mInstrumentation");
mInstrumentationField.setAccessible(true);
Instrumentation mInstrumentationObj = (Instrumentation) mInstrumentationField.get(activityThreadObj);
// 4.reset set value
mInstrumentationField.set(activityThreadObj, new InstrumentationProxy(mInstrumentationObj, context.getPackageManager(), StubAppCompatActivity.clreplaced));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
@SuppressWarnings("JavaReflectionMemberAccess")
@SuppressLint("DiscouragedPrivateApi")
private static clreplaced InstrumentationProxy extends Instrumentation {
private final Instrumentation mInstrumentation;
private final PackageManager mPackageManager;
private final Clreplaced<?> mStubActivityClreplaced;
InstrumentationProxy(Instrumentation instrumentation, PackageManager packageManager, Clreplaced<?> stubActivityClreplacedName) {
mInstrumentation = instrumentation;
mPackageManager = packageManager;
mStubActivityClreplaced = stubActivityClreplacedName;
}
/**
* android16-android29
* Instrumentation的execStartActivity方法激活Activity生命周期
* 使用占坑的Activity来通过AMS的验证.
*/
@Keep
@SuppressWarnings("unused")
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
List<ResolveInfo> resolveInfoList = null;
try {
int flags = 0;
if (Build.VERSION.SDK_INT >= 23) {
flags = PackageManager.MATCH_ALL;
}
resolveInfoList = mPackageManager.queryIntentActivities(intent, flags);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
Intent finalIntent = intent;
if (resolveInfoList == null || resolveInfoList.size() == 0) {
// 目标Activity没有在AndroidManifest.xml中注册的话,将目标Activity的ClreplacedName保存到桩Intent中.
finalIntent = new Intent(who, mStubActivityClreplaced);
// public clreplaced Intent implements Parcelable;
// Intent类已经实现了Parcelable接口
finalIntent.putExtra(TARGET_INTENT_CLreplaced, intent);
}
try {
// 通过反射调用execStartActivity方法,这样就可以用桩Activity通过AMS的验证.
Method execStartActivityMethod = Instrumentation.clreplaced.getDeclaredMethod("execStartActivity", Context.clreplaced, IBinder.clreplaced, IBinder.clreplaced, Activity.clreplaced, Intent.clreplaced, int.clreplaced, Bundle.clreplaced);
execStartActivityMethod.setAccessible(true);
return (ActivityResult) execStartActivityMethod.invoke(mInstrumentation, who, contextThread, token, target, finalIntent, requestCode, options);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* just for android-15
* Instrumentation#execStartActivity()方法参数和其他版本不同, 需要单独适配
* Instrumentation的execStartActivity方法激活Activity生命周期
* 使用占坑的Activity来通过AMS的验证.
* http://androidxref.com/4.0.3_r1/xref/frameworks/base/core/java/android/app/Instrumentation.java
*/
@Keep
@SuppressLint("WrongConstant")
@SuppressWarnings("unused")
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {
if (Build.VERSION.SDK_INT != 15)
return null;
List<ResolveInfo> resolveInfoList = null;
try {
int flags = 0;
resolveInfoList = mPackageManager.queryIntentActivities(intent, flags);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
Intent finalIntent = intent;
if (resolveInfoList == null || resolveInfoList.size() == 0) {
// 目标Activity没有在AndroidManifest.xml中注册的话,将目标Activity的ClreplacedName保存到桩Intent中.
finalIntent = new Intent(who, mStubActivityClreplaced);
// public clreplaced Intent implements Parcelable;
// Intent类已经实现了Parcelable接口
finalIntent.putExtra(TARGET_INTENT_CLreplaced, intent);
}
try {
// just for android-15
// 通过反射调用execStartActivity方法,这样就可以用桩Activity通过AMS的验证.
Method execStartActivityMethod = Instrumentation.clreplaced.getDeclaredMethod("execStartActivity", Context.clreplaced, IBinder.clreplaced, IBinder.clreplaced, Activity.clreplaced, Intent.clreplaced, int.clreplaced);
execStartActivityMethod.setAccessible(true);
return (ActivityResult) execStartActivityMethod.invoke(mInstrumentation, who, contextThread, token, target, finalIntent, requestCode);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
/**
* Instrumentation的newActivity方法,用类加载器来创建Activity实例
* 还原目标Activity.
*/
@Keep
@Override
public Activity newActivity(ClreplacedLoader clreplacedLoader, String clreplacedName, Intent intent) throws InstantiationException, IllegalAccessException, ClreplacedNotFoundException {
Intent pluginIntent = intent.getParcelableExtra(TARGET_INTENT_CLreplaced);
boolean pluginIntentClreplacedNameExist = pluginIntent != null && !TextUtils.isEmpty(pluginIntent.getComponent().getClreplacedName());
// 1.clreplacedName
String finalClreplacedName = pluginIntentClreplacedNameExist ? pluginIntent.getComponent().getClreplacedName() : clreplacedName;
// 2.intent
Intent finalIntent = pluginIntentClreplacedNameExist ? pluginIntent : intent;
// 3.clreplacedLoader
File pluginDexFile = MApplication.getInstance().getFileStreamPath(PluginApkNameVersion.PLUGIN_ACTIVITY_APK);
ClreplacedLoader finalClreplacedLoader = pluginIntentClreplacedNameExist ? CustomClreplacedLoader.getPluginClreplacedLoader(pluginDexFile, "com.malin.plugin") : clreplacedLoader;
if (Build.VERSION.SDK_INT >= 28) {
return mInstrumentation.newActivity(finalClreplacedLoader, finalClreplacedName, finalIntent);
}
return super.newActivity(finalClreplacedLoader, finalClreplacedName, finalIntent);
}
}
}
19
Source : HookAMSForServicePlugin.java
with Apache License 2.0
from androidmalin
with Apache License 2.0
from androidmalin
/**
* 启动插件中的Service,需要Hook AMS, 拦截startService,stopService方法,进行代理转发
*/
@SuppressLint("PrivateApi")
clreplaced HookAMSForServicePlugin {
static final String EXTRA_TARGET_INTENT = "service_extra_target_intent";
/**
* Hook AMS
* 主要完成的操作是 "把真正要启动的Service临时替换为在AndroidManifest.xml中声明的替身Service"
* 进而骗过AMS
*/
@SuppressWarnings("JavaReflectionMemberAccess")
static void hookActivityManager() throws ClreplacedNotFoundException, IllegalAccessException, NoSuchFieldException {
Field iActivityManagerSingletonFiled;
if (Build.VERSION.SDK_INT >= 26) {
Clreplaced<?> activityManagerClazz = Clreplaced.forName("android.app.ActivityManager");
iActivityManagerSingletonFiled = activityManagerClazz.getDeclaredField("IActivityManagerSingleton");
} else {
Clreplaced<?> activityManagerNativeClazz = Clreplaced.forName("android.app.ActivityManagerNative");
iActivityManagerSingletonFiled = activityManagerNativeClazz.getDeclaredField("gDefault");
}
iActivityManagerSingletonFiled.setAccessible(true);
// private static final Singleton<IActivityManager> IActivityManagerSingleton
Object iActivityManagerSingletonObj = iActivityManagerSingletonFiled.get(null);
Clreplaced<?> singletonClazz = Clreplaced.forName("android.util.Singleton");
Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object rawIActivityManager = mInstanceField.get(iActivityManagerSingletonObj);
// 创建一个这个对象的代理对象, 然后替换这个字段, 让我们的代理对象帮忙干活
Clreplaced<?> iActivityManagerClazz = Clreplaced.forName("android.app.IActivityManager");
Object iActivityManagerProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClreplacedLoader(), new Clreplaced<?>[] { iActivityManagerClazz }, new IActivityManagerHandler(rawIActivityManager));
mInstanceField.set(iActivityManagerSingletonObj, iActivityManagerProxy);
}
private static clreplaced IActivityManagerHandler implements InvocationHandler {
private static final String TAG = "IActivityManagerHandler";
private final Object mIActivityManagerBase;
IActivityManagerHandler(Object base) {
mIActivityManagerBase = base;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startService".equals(method.getName())) {
// 只拦截这个方法
// public ComponentName startService(IApplicationThread caller, Intent service,String resolvedType, int userId) throws RemoteException
// 找到参数里面的第一个Intent 对象,返回该Intent的索引和该Intent对象
Pair<Integer, Intent> integerIntentPair = foundFirstIntentOfArgs(args);
Intent proxyIntent = new Intent();
// 代理Service的包名, 也就是我们自己的包名
String proxyPackage = MApplication.getInstance().getPackageName();
// 这里我们把启动的Service替换为ProxyService, 让ProxyService接收生命周期回调
ComponentName proxyComponentName = new ComponentName(proxyPackage, PluginProxyService.clreplaced.getName());
proxyIntent.setComponent(proxyComponentName);
// 把我们原始要启动的TargetService先存起来
proxyIntent.putExtra(HookAMSForServicePlugin.EXTRA_TARGET_INTENT, integerIntentPair.second);
// 替换掉Intent, 达到欺骗AMS的目的
args[integerIntentPair.first] = proxyIntent;
Log.d(TAG, "hook method startService success");
return method.invoke(mIActivityManagerBase, args);
}
// public int stopService(IApplicationThread caller, Intent service,String resolvedType, int userId) throws RemoteException
if ("stopService".equals(method.getName())) {
Intent raw = foundFirstIntentOfArgs(args).second;
if (raw != null && raw.getComponent() != null && !TextUtils.equals(MApplication.getInstance().getPackageName(), raw.getComponent().getPackageName())) {
// 插件的intent才做hook
Log.d(TAG, "hook method stopService success");
return ServiceManager.getInstance().stopService(raw);
}
}
return method.invoke(mIActivityManagerBase, args);
}
/**
* 找到参数里面的第一个Intent 对象,返回该Intent的索引和该Intent对象
*/
private Pair<Integer, Intent> foundFirstIntentOfArgs(Object... args) {
int index = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
index = i;
break;
}
}
if (args[index] instanceof Intent) {
return Pair.create(index, (Intent) args[index]);
} else {
return Pair.create(index, null);
}
}
}
}
19
Source : HookActivity.java
with Apache License 2.0
from androidmalin
with Apache License 2.0
from androidmalin
/**
* 对Activity启动流程中的两次拦截
*/
@SuppressLint("PrivateApi")
public clreplaced HookActivity {
private static final String EXTRA_ORIGIN_INTENT = "EXTRA_ORIGIN_INTENT";
@SuppressLint("StaticFieldLeak")
private static IActivityInvocationHandler mIActivityInvocationHandler;
@SuppressLint("StaticFieldLeak")
private static IActivityInvocationHandler mIActivityInvocationHandlerL;
@SuppressLint("StaticFieldLeak")
private static PackageManagerProxyHandler mPackageManagerProxyHandler;
/**
* 对IActivityManager接口中的startActivity方法进行动态代理,发生在app的进程中
* {@link android.app.Activity#startActivity(Intent)}
* {@link android.app.Activity#startActivityForResult(Intent, int, Bundle)}
* android.app.Instrumentation#execStartActivity()
* Activity#startActivityForResult-->Instrumentation#execStartActivity-->ActivityManager.getService().startActivity()-->
* IActivityManager public int startActivity(android.app.IApplicationThread caller, java.lang.String callingPackage, android.content.Intent intent, java.lang.String resolvedType, android.os.IBinder resultTo, java.lang.String resultWho, int requestCode, int flags, android.app.ProfilerInfo profilerInfo, android.os.Bundle options) throws android.os.RemoteException;
*
* @param context context
* @param subActivityClazz 在AndroidManifest.xml中注册了的Activity
*/
@SuppressWarnings("JavaReflectionMemberAccess")
public static void hookStartActivity(Context context, Clreplaced<?> subActivityClazz) {
try {
if (Build.VERSION.SDK_INT >= 29) {
// 1.获取ActivityTaskManager的Clreplaced对象
// package android.app;
// public clreplaced ActivityTaskManager
Clreplaced<?> activityTaskManagerClazz = Clreplaced.forName("android.app.ActivityTaskManager");
// 2.获取ActivityTaskManager的私有静态成员变量IActivityTaskManagerSingleton
// private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton
Field iActivityTaskManagerSingletonField = activityTaskManagerClazz.getDeclaredField("IActivityTaskManagerSingleton");
// 3.取消Java的权限检查
iActivityTaskManagerSingletonField.setAccessible(true);
// 4.获取IActivityManagerSingleton的实例对象
// private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton
// 所有静态对象的反射可以通过传null获取,如果是非静态必须传实例
Object IActivityTaskManagerSingletonObj = iActivityTaskManagerSingletonField.get(null);
// 5.
handleIActivityTaskManager(context, subActivityClazz, IActivityTaskManagerSingletonObj);
} else if (Build.VERSION.SDK_INT >= 26) {
// 1.获取ActivityManager的Clreplaced对象
// package android.app
// public clreplaced ActivityManager
Clreplaced<?> activityManagerClazz = Clreplaced.forName("android.app.ActivityManager");
// 2.获取ActivityManager的私有静态属性IActivityManagerSingleton
// private static final Singleton<IActivityManager> IActivityManagerSingleton
Field iActivityManagerSingletonField = activityManagerClazz.getDeclaredField("IActivityManagerSingleton");
// 3.取消Java的权限检查
iActivityManagerSingletonField.setAccessible(true);
// 4.获取IActivityManagerSingleton的实例对象
// private static final Singleton<IActivityManager> IActivityManagerSingleton
// 所有静态对象的反射可以通过传null获取,如果是非静态必须传实例
handleIActivityManager(context, subActivityClazz, iActivityManagerSingletonField.get(null));
} else {
// 1.获取ActivityManagerNative的Clreplaced对象
// package android.app
// public abstract clreplaced ActivityManagerNative
Clreplaced<?> activityManagerNativeClazz = Clreplaced.forName("android.app.ActivityManagerNative");
// 2.获取 ActivityManagerNative的 私有属性gDefault
// private static final Singleton<IActivityManager> gDefault
Field singletonField = activityManagerNativeClazz.getDeclaredField("gDefault");
// 3.对私有属性gDefault,解除私有限定
singletonField.setAccessible(true);
// 4.获得gDefaultField中对应的属性值(被static修饰了),既得到Singleton<IActivityManager>对象的实例
// 所有静态对象的反射可以通过传null获取
// private static final Singleton<IActivityManager> gDefault
handleIActivityManager(context, subActivityClazz, singletonField.get(null));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
@SuppressWarnings("JavaReflectionMemberAccess")
private static void handleIActivityTaskManager(Context context, Clreplaced<?> subActivityClazz, Object IActivityTaskManagerSingletonObj) {
try {
// 5.获取private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton对象中的属性private T mInstance的值
// 既,为了获取一个IActivityTaskManager的实例对象
// private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() {...}
// 6.获取Singleton类对象
// package android.util
// public abstract clreplaced Singleton<T>
Clreplaced<?> singletonClazz = Clreplaced.forName("android.util.Singleton");
// 7.获取mInstance属性
// private T mInstance;
Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
// 8.取消Java的权限检查
mInstanceField.setAccessible(true);
// 9.获取mInstance属性的值,既IActivityTaskManager的实例
// 从private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton实例对象中获取mInstance属性对应的值,既IActivityTaskManager
Object IActivityTaskManager = mInstanceField.get(IActivityTaskManagerSingletonObj);
// 10.获取IActivityTaskManager接口的类对象
// package android.app
// public interface IActivityTaskManager
Clreplaced<?> IActivityTaskManagerClazz = Clreplaced.forName("android.app.IActivityTaskManager");
if (mIActivityInvocationHandler == null) {
mIActivityInvocationHandler = new IActivityInvocationHandler(IActivityTaskManager, context, subActivityClazz);
} else {
mIActivityInvocationHandler.updateStubActivity(subActivityClazz);
}
// 11.创建一个IActivityTaskManager接口的代理对象
Object IActivityTaskManagerProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClreplacedLoader(), new Clreplaced[] { IActivityTaskManagerClazz }, mIActivityInvocationHandler);
// 11.重新赋值
// 给mInstance属性,赋新值
// 给Singleton<IActivityManager> IActivityManagerSingleton实例对象的属性private T mInstance赋新值
mInstanceField.set(IActivityTaskManagerSingletonObj, IActivityTaskManagerProxy);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
@SuppressWarnings("JavaReflectionMemberAccess")
private static void handleIActivityManager(Context context, Clreplaced<?> subActivityClazz, Object IActivityManagerSingletonObj) {
try {
// 5.获取private static final Singleton<IActivityManager> IActivityManagerSingleton对象中的属性private T mInstance的值
// 既,为了获取一个IActivityManager的实例对象
// private static final Singleton<IActivityManager> IActivityManagerSingleton =new Singleton<IActivityManager>(){...}
// 6.获取Singleton类对象
// package android.util
// public abstract clreplaced Singleton<T>
Clreplaced<?> singletonClazz = Clreplaced.forName("android.util.Singleton");
// 7.获取mInstance属性
// private T mInstance;
Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
// 8.取消Java的权限检查
mInstanceField.setAccessible(true);
// 9.获取mInstance属性的值,既IActivityManager的实例
// 从private static final Singleton<IActivityManager> IActivityManagerSingleton实例对象中获取mInstance属性对应的值,既IActivityManager
Object iActivityManager = mInstanceField.get(IActivityManagerSingletonObj);
// 10.获取IActivityManager接口的类对象
// package android.app
// public interface IActivityManager
Clreplaced<?> iActivityManagerClazz = Clreplaced.forName("android.app.IActivityManager");
if (mIActivityInvocationHandlerL == null) {
mIActivityInvocationHandlerL = new IActivityInvocationHandler(iActivityManager, context, subActivityClazz);
} else {
mIActivityInvocationHandlerL.updateStubActivity(subActivityClazz);
}
// 11.创建一个IActivityManager接口的代理对象
Object iActivityManagerProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClreplacedLoader(), new Clreplaced[] { iActivityManagerClazz }, mIActivityInvocationHandlerL);
// 11.重新赋值
// 给mInstance属性,赋新值
// 给Singleton<IActivityManager> IActivityManagerSingleton实例对象的属性private T mInstance赋新值
mInstanceField.set(IActivityManagerSingletonObj, iActivityManagerProxy);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
/**
* 对IActivityManager/IActivityTaskManager接口进行动态代理
*/
private static clreplaced IActivityInvocationHandler implements InvocationHandler {
private final Object mIActivityManager;
private Clreplaced<?> mSubActivityClazz;
private final Context mContext;
public IActivityInvocationHandler(Object iActivityManager, Context context, Clreplaced<?> subActivityClazz) {
this.mIActivityManager = iActivityManager;
this.mSubActivityClazz = subActivityClazz;
this.mContext = context;
}
public void updateStubActivity(Clreplaced<?> subActivityClazz) {
this.mSubActivityClazz = subActivityClazz;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
if (method.getName().equals("startActivity")) {
int intentIndex = 2;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
intentIndex = i;
break;
}
}
// 将启动的未注册的Activity对应的Intent,替换为安全的注册了的桩Activity的Intent
// 1.将未注册的Activity对应的Intent,改为安全的Intent,既在AndroidManifest.xml中配置了的Activity的Intent
Intent originIntent = (Intent) args[intentIndex];
Intent safeIntent = new Intent(mContext, mSubActivityClazz);
// public clreplaced Intent implements Parcelable;
// Intent类已经实现了Parcelable接口
safeIntent.putExtra(EXTRA_ORIGIN_INTENT, originIntent);
// 2.替换到原来的Intent,欺骗AMS
args[intentIndex] = safeIntent;
// 3.之后,再换回来,启动我们未在AndroidManifest.xml中配置的Activity
// final H mH = new H();
// hook Handler消息的处理,给Handler增加mCallback
}
// public abstract int android.app.IActivityManager.startActivity(android.app.IApplicationThread,java.lang.String,android.content.Intent,java.lang.String,android.os.IBinder,java.lang.String,int,int,android.app.ProfilerInfo,android.os.Bundle) throws android.os.RemoteException
// public abstract int android.app.IActivityTaskManager.startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);
return method.invoke(mIActivityManager, args);
}
}
/**
* 启动未注册的Activity,将之前替换了的Intent,换回去.我们的目标是要启动未注册的Activity
*
* @param context context
* @param subActivityClazz 注册了的Activity的Clreplaced对象
* @param isAppCompat 是否是AppCompatActivity的子类
*/
@SuppressLint("DiscouragedPrivateApi")
public static void hookLauncherActivity(Context context, Clreplaced<?> subActivityClazz, boolean isAppCompat) {
try {
// 1.获取ActivityThread的Clreplaced对象
// package android.app
// public final clreplaced ActivityThread
Clreplaced<?> activityThreadClazz = Clreplaced.forName("android.app.ActivityThread");
// 2.获取currentActivityThread()静态方法;为了保证在多个版本中兼容性,使用该静态方法获取ActivityThread的实例
// public static ActivityThread currentActivityThread(){return sCurrentActivityThread;}
Method currentActivityThreadMethod = activityThreadClazz.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
// 3.获取ActivityThread的对象实例
// public static ActivityThread currentActivityThread(){return sCurrentActivityThread;}
Object activityThreadObj = currentActivityThreadMethod.invoke(null);
// 4.获取ActivityThread 的属性mH
// final H mH = new H();
Field mHField = activityThreadClazz.getDeclaredField("mH");
mHField.setAccessible(true);
// 5.获取mH的值,既获取ActivityThread类中H类的实例对象
// 从ActivityThread实例中获取mH属性对应的值,既mH的值
Object mHObj = mHField.get(activityThreadObj);
// 6.获取Handler的Clreplaced对象
// package android.os
// public clreplaced Handler
Clreplaced<?> handlerClazz = Clreplaced.forName("android.os.Handler");
// 7.获取mCallback属性
// final Callback mCallback;
// Callback是Handler类内部的一个接口
Field mCallbackField = handlerClazz.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
// 8.给mH增加mCallback
// 给mH,既Handler的子类设置mCallback属性,提前对消息进行处理.
if (Build.VERSION.SDK_INT >= 28) {
// android 9.0
mCallbackField.set(mHObj, new HandlerCallbackP(context, subActivityClazz, isAppCompat));
} else {
mCallbackField.set(mHObj, new HandlerCallback(context, subActivityClazz, isAppCompat));
}
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
/**
* 对应<9.0情况,创建一个Handler的Callback接口的实例对象
*/
private static clreplaced HandlerCallback implements Handler.Callback {
private final Context context;
private final Clreplaced<?> subActivityClazz;
private final boolean isAppCompat;
public HandlerCallback(Context context, Clreplaced<?> subActivityClazz, boolean isAppCompat) {
this.context = context;
this.subActivityClazz = subActivityClazz;
this.isAppCompat = isAppCompat;
}
@Override
public boolean handleMessage(@NonNull Message msg) {
handleLaunchActivity(msg, context, subActivityClazz, isAppCompat);
return false;
}
}
private static void handleLaunchActivity(Message msg, Context context, Clreplaced<?> subActivityClazz, boolean isAppCompat) {
int LAUNCH_ACTIVITY = 100;
try {
// 1.获取ActivityThread的内部类H的Clreplaced对象
// package android.app
// public final clreplaced ActivityThread{
// private clreplaced H extends Handler {}
// }
Clreplaced<?> hClazz = Clreplaced.forName("android.app.ActivityThread$H");
// 2.获取LAUNCH_ACTIVITY属性的Field
// public static final int LAUNCH_ACTIVITY = 100;
Field launch_activity_field = hClazz.getField("LAUNCH_ACTIVITY");
// 3.获取LAUNCH_ACTIVITY的值
Object object = launch_activity_field.get(null);
if (object instanceof Integer) {
LAUNCH_ACTIVITY = (int) object;
}
} catch (Exception e) {
e.printStackTrace();
}
if (msg.what != LAUNCH_ACTIVITY)
return;
// private clreplaced H extends Handler {
// public void handleMessage(Message msg) {
// switch (msg.what) {
// case LAUNCH_ACTIVITY: {
// final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
// r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
// handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
// break;
// }
// }
// }
// 1.从msg中获取ActivityClientRecord对象
// android.app.ActivityThread$ActivityClientRecord
// static final clreplaced ActivityClientRecord {}
Object activityClientRecordObj = msg.obj;
try {
// 2.获取ActivityClientRecord的intent属性
// Intent intent;
Field safeIntentField = activityClientRecordObj.getClreplaced().getDeclaredField("intent");
safeIntentField.setAccessible(true);
// 3.获取ActivityClientRecord的intent属性的值,既安全的Intent
Intent safeIntent = (Intent) safeIntentField.get(activityClientRecordObj);
if (safeIntent == null)
return;
// 4.获取原始的Intent
Intent originIntent = safeIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
if (originIntent == null)
return;
// 5.将安全的Intent,替换为原始的Intent,以启动我们要启动的未注册的Activity
safeIntent.setComponent(originIntent.getComponent());
// 6.处理启动的Activity为AppCompatActivity类或者子类的情况
if (!isAppCompat)
return;
hookPackageManager(context, subActivityClazz);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 对Android 9.0的处理
* https://www.cnblogs.com/Jax/p/9521305.html
*/
private static clreplaced HandlerCallbackP implements Handler.Callback {
private final Context context;
private final Clreplaced<?> subActivityClazz;
private final boolean isAppCompat;
public HandlerCallbackP(Context context, Clreplaced<?> subActivityClazz, boolean isAppCompat) {
this.context = context;
this.subActivityClazz = subActivityClazz;
this.isAppCompat = isAppCompat;
}
@Override
public boolean handleMessage(Message msg) {
// android.app.ActivityThread$H.EXECUTE_TRANSACTION = 159
// android 9.0反射,Accessing hidden field Landroid/app/ActivityThread$H;->EXECUTE_TRANSACTION:I (dark greylist, reflection)
// android9.0 深灰名单(dark greylist)则debug版本在会弹出dialog提示框,在release版本会有Toast提示,均提示为"Detected problems with API compatibility"
if (msg.what == 159) {
// 直接写死,不反射了,否则在android9.0的设备上运行会弹出使用了反射的dialog提示框
handleActivity(msg);
}
return false;
}
@SuppressWarnings("JavaReflectionMemberAccess")
private void handleActivity(Message msg) {
try {
// ClientTransaction-->ClientTransaction中的List<ClientTransactionItem> mActivityCallbacks-->集合中的第一个值LaunchActivityItem-->LaunchActivityItem的mIntent
// 这里简单起见,直接取出TargetActivity;
// final ClientTransaction transaction = (ClientTransaction) msg.obj;
// 1.获取ClientTransaction对象
Object clientTransactionObj = msg.obj;
if (clientTransactionObj == null)
return;
// 2.获取ClientTransaction类中属性mActivityCallbacks的Field
// private List<ClientTransactionItem> mActivityCallbacks;
Field mActivityCallbacksField = clientTransactionObj.getClreplaced().getDeclaredField("mActivityCallbacks");
// 3.禁止Java访问检查
mActivityCallbacksField.setAccessible(true);
// 4.获取ClientTransaction类中mActivityCallbacks属性的值,既List<ClientTransactionItem>
List<?> mActivityCallbacks = (List<?>) mActivityCallbacksField.get(clientTransactionObj);
if (mActivityCallbacks == null || mActivityCallbacks.size() <= 0)
return;
if (mActivityCallbacks.get(0) == null)
return;
// 5.ClientTransactionItem的Clreplaced对象
// package android.app.servertransaction;
// public clreplaced LaunchActivityItem extends ClientTransactionItem
Clreplaced<?> launchActivityItemClazz = Clreplaced.forName("android.app.servertransaction.LaunchActivityItem");
// 6.判断集合中第一个元素的值是LaunchActivityItem类型的
if (!launchActivityItemClazz.isInstance(mActivityCallbacks.get(0)))
return;
// 7.获取LaunchActivityItem的实例
// public clreplaced LaunchActivityItem extends ClientTransactionItem
Object launchActivityItem = mActivityCallbacks.get(0);
// 8.ClientTransactionItem的mIntent属性的mIntent的Field
// private Intent mIntent;
Field mIntentField = launchActivityItemClazz.getDeclaredField("mIntent");
// 9.禁止Java访问检查
mIntentField.setAccessible(true);
// 10.获取mIntent属性的值,既桩Intent(安全的Intent)
// 从LaunchActivityItem中获取属性mIntent的值
Intent safeIntent = (Intent) mIntentField.get(launchActivityItem);
if (safeIntent == null)
return;
// 11.获取原始的Intent
Intent originIntent = safeIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
// 12.需要判断originIntent != null
if (originIntent == null)
return;
// 13.将原始的Intent,赋值给clientTransactionItem的mIntent属性
safeIntent.setComponent(originIntent.getComponent());
// 14.处理未注册的Activity为AppCompatActivity类或者子类的情况
if (!isAppCompat)
return;
hookPackageManager(context, subActivityClazz);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 获取包名
*/
private static String getAppPackageName(Context context) {
Context applicationContext = context.getApplicationContext();
return applicationContext.getPackageName();
}
/**
* 1.处理未注册的Activity为AppCompatActivity类或者子类的情况
* 2.hook IPackageManager,处理android 4.3以下(<= 18)启动Activity,在ApplicationPackageManager.getActivityInfo方法中未找到注册的Activity的异常
* <p>
* http://weishu.me/2016/03/07/understand-plugin-framework-ams-pms-hook/
*
* @param context context
* @param subActivityClazz 注册了的Activity的clreplaced对象
*/
@SuppressLint("DiscouragedPrivateApi")
public static void hookPackageManager(Context context, Clreplaced<?> subActivityClazz) {
try {
// 1.获取ActivityThread的值
Clreplaced<?> activityThreadClazz = Clreplaced.forName("android.app.ActivityThread");
// public static ActivityThread currentActivityThread() {
// return sCurrentActivityThread;
// }
Method currentActivityThreadMethod = activityThreadClazz.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object activityThread = currentActivityThreadMethod.invoke(null);
// 2.获取ActivityThread里面原始的 sPackageManager
// static IPackageManager sPackageManager;
Field sPackageManagerField = activityThreadClazz.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
Object sPackageManager = sPackageManagerField.get(activityThread);
if (mPackageManagerProxyHandler == null) {
mPackageManagerProxyHandler = new PackageManagerProxyHandler(sPackageManager, getAppPackageName(context), subActivityClazz.getName());
}
// 3.准备好代理对象, 用来替换原始的对象
Clreplaced<?> iPackageManagerClazz = Clreplaced.forName("android.content.pm.IPackageManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClreplacedLoader(), new Clreplaced<?>[] { iPackageManagerClazz }, mPackageManagerProxyHandler);
// 4.替换掉ActivityThread里面的 sPackageManager 字段
sPackageManagerField.set(activityThread, proxy);
// 5.替换 ApplicationPackageManager里面的 mPM对象
PackageManager packageManager = context.getPackageManager();
// PackageManager的实现类ApplicationPackageManager中的mPM
// private final IPackageManager mPM;
Field mPmField = packageManager.getClreplaced().getDeclaredField("mPM");
mPmField.setAccessible(true);
mPmField.set(packageManager, proxy);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
private static clreplaced PackageManagerProxyHandler implements InvocationHandler {
private final String mSubActivityClazzName;
private final Object mIPackageManagerObj;
private final String mAppPackageName;
public PackageManagerProxyHandler(Object iPackageManagerObj, String appPackageName, String subActivityClazzName) {
this.mIPackageManagerObj = iPackageManagerObj;
this.mSubActivityClazzName = subActivityClazzName;
this.mAppPackageName = appPackageName;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
// public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName clreplacedName, int flags, int userId)
if ("getActivityInfo".equals(method.getName())) {
int index = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof ComponentName) {
index = i;
break;
}
}
ComponentName componentName = new ComponentName(mAppPackageName, mSubActivityClazzName);
args[index] = componentName;
}
if ("getPackageInfo".equals(method.getName())) {
Log.d("getPackageInfo", "getPackageInfo:call");
return new PackageInfo();
}
return method.invoke(mIPackageManagerObj, args);
}
}
}
19
Source : BinderHookHelper.java
with Apache License 2.0
from androidmalin
with Apache License 2.0
from androidmalin
/**
* @author weishu
* malin modify add note
* test android15-android29 通过
* http://weishu.me/2016/02/16/understand-plugin-framework-binder-hook/
* http://www.520monkey.com/archives/861
*/
@SuppressLint("PrivateApi")
clreplaced BinderHookHelper {
@SuppressWarnings("JavaReflectionMemberAccess")
@SuppressLint("DiscouragedPrivateApi")
static void hookClipboardService() throws Exception {
final String CLIPBOARD_SERVICE = "clipboard";
// 下面这一段的意思实际就是: ServiceManager.getService("clipboard");
// 只不过 ServiceManager这个类是@hide的
// package android.os;
// public final clreplaced ServiceManager {}
Clreplaced<?> serviceManagerClazz = Clreplaced.forName("android.os.ServiceManager");
// ServiceManager
// public static IBinder getService(String name) {}
Method getServiceMethod = serviceManagerClazz.getDeclaredMethod("getService", String.clreplaced);
getServiceMethod.setAccessible(true);
// ServiceManager里面管理的原始的Clipboard Binder对象
// 一般来说这是一个Binder代理对象
// public static IBinder getService(String name) {}
IBinder rawBinder = (IBinder) getServiceMethod.invoke(null, CLIPBOARD_SERVICE);
// Hook 掉这个Binder代理对象的 queryLocalInterface 方法
// 然后在 queryLocalInterface 返回一个IInterface对象, hook掉我们感兴趣的方法即可.
IBinder hookedBinder = (IBinder) Proxy.newProxyInstance(serviceManagerClazz.getClreplacedLoader(), new Clreplaced<?>[] { IBinder.clreplaced }, new BinderProxyHookHandler(rawBinder));
// 把这个hook过的Binder代理对象放进ServiceManager的cache里面
// 以后查询的时候 会优先查询缓存里面的Binder, 这样就会使用被我们修改过的Binder了
// android.os.ServiceManager
// private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();
Field sCacheField = serviceManagerClazz.getDeclaredField("sCache");
sCacheField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String, IBinder> cache = (Map<String, IBinder>) sCacheField.get(null);
if (cache == null)
return;
cache.put(CLIPBOARD_SERVICE, hookedBinder);
}
/**
* 由于ServiceManager里面的sCache里面存储的 IBinder类型基本上都是BinderProxy
* 因此, ServiceManager的使用者调用getService之后不会直接使用这个map
* 而是先将他使用asInterface转成需要的接口
* <p/>
* asInterface函数的代码告诉我们, 它会先使用这个BinderPRoxy查询本进程是否有Binder对象
* 如果有就使用本地的, 这里恰好就是一个hook点
* <p/>
* 我们让所有的查询都返回一个"本地Binder"对象
* <p/>
* 当然,这是一个假象, 我们给它返回的Binder对象自然是符合要求的(要么是本地Binder,要么是Binder代理)
* 只不过,我们对需要hook的API做了处理
* <p/>
* 这个类仅仅Hook掉这个关键的 queryLocalInterface 方法
*/
@SuppressLint("PrivateApi")
private static clreplaced BinderProxyHookHandler implements InvocationHandler {
private static final String TAG = "BinderProxyHookHandler";
// 绝大部分情况下,这是一个BinderProxy对象
// 只有当Service和我们在同一个进程的时候才是Binder本地对象
// 这个基本不可能
private final IBinder iBinder;
private Clreplaced<?> stub;
private Clreplaced<?> iInterface;
BinderProxyHookHandler(IBinder iBinder) {
this.iBinder = iBinder;
try {
this.stub = Clreplaced.forName("android.content.IClipboard$Stub");
this.iInterface = Clreplaced.forName("android.content.IClipboard");
} catch (ClreplacedNotFoundException e) {
e.printStackTrace();
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("queryLocalInterface".equals(method.getName())) {
Log.d(TAG, "hook queryLocalInterface");
// public interface IClipboard extends android.os.IInterface {
// abstract clreplaced Stub extends android.os.Binder implements android.content.IClipboard {
// public static android.content.IClipboard asInterface(android.os.IBinder obj) {
// }
// }
// }
Method asInterfaceMethod = stub.getDeclaredMethod("asInterface", IBinder.clreplaced);
// 生成本地端的中间者
Object iClipboardObj = asInterfaceMethod.invoke(null, iBinder);
// 这里直接返回真正被Hook掉的Service接口
// 这里的 queryLocalInterface 就不是原本的意思了
// 我们肯定不会真的返回一个本地接口, 因为我们接管了 asInterface方法的作用
// 因此必须是一个完整的 asInterface 过的 IInterface对象, 既要处理本地对象,也要处理代理对象
// 这只是一个Hook点而已, 它原始的含义已经被我们重定义了; 因为我们会永远确保这个方法不返回null
// 让 IClipboard.Stub.asInterface 永远走到if语句的else分支里面
return Proxy.newProxyInstance(proxy.getClreplaced().getClreplacedLoader(), // asInterface 的时候会检测是否是特定类型的接口然后进行强制转换
// 因此这里的动态代理生成的类型信息的类型必须是正确的
// 这里面Hook的是一个BinderProxy对象(Binder代理) (代理Binder的queryLocalInterface正常情况下是返回null)
// 因此, 正常情况下 在asInterface里面会由于BinderProxy的queryLocalInterface返回null导致系统创建一个匿名的代理对象, 这样我们就无法控制了
// 所以我们要伪造一个对象, 瞒过这个if检测, 使得系统把这个queryLocalInterface返回的对象透传给asInterface的返回值;
// 检测有两个要求, 其一: 非空, 其二, IXXInterface类型。
// 所以, 其实返回的对象不需要是Binder对象, 我们把它当作普通的对象Hook掉就ok(拦截这个对象里面对于IXXInterface相关方法的调用)
// tks [email protected]
new Clreplaced[] { this.iInterface }, new BinderHookHandler(iClipboardObj));
}
Log.d(TAG, "method:" + method.getName());
return method.invoke(iBinder, args);
}
}
public static clreplaced BinderHookHandler implements InvocationHandler {
private static final String TAG = "BinderHookHandler";
// 原始的Service对象 (IInterface)
private Object iClipboard;
BinderHookHandler(Object iClipboard) {
try {
this.iClipboard = iClipboard;
} catch (Exception e) {
e.printStackTrace();
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 把剪切版的内容替换为 "you are hooked"
if ("getPrimaryClip".equals(method.getName())) {
Log.d(TAG, "hook getPrimaryClip");
return ClipData.newPlainText(null, "you are hooked");
}
// 欺骗系统,使之认为剪切版上一直有内容
if ("hasPrimaryClip".equals(method.getName())) {
Log.d(TAG, "hook hasPrimaryClip");
return true;
}
return method.invoke(iClipboard, args);
}
}
}
18
Source : StatesCutoutUtils.java
with Apache License 2.0
from yangchong211
with Apache License 2.0
from yangchong211
/**
* 是否是小米刘海屏机型
*/
@SuppressWarnings("unchecked")
@SuppressLint("PrivateApi")
private static boolean hasCutoutXIAOMI(Activity activity) {
if (!Build.MANUFACTURER.equalsIgnoreCase("xiaomi")) {
return false;
}
try {
ClreplacedLoader cl = activity.getClreplacedLoader();
Clreplaced SystemProperties = cl.loadClreplaced("android.os.SystemProperties");
Clreplaced[] paramTypes = new Clreplaced[2];
paramTypes[0] = String.clreplaced;
paramTypes[1] = int.clreplaced;
Method getInt = SystemProperties.getMethod("getInt", paramTypes);
// 参数
Object[] params = new Object[2];
params[0] = "ro.miui.notch";
params[1] = 0;
int hasCutout = (int) getInt.invoke(SystemProperties, params);
return hasCutout == 1;
} catch (Exception e) {
return false;
}
}
18
Source : StatesCutoutUtils.java
with Apache License 2.0
from yangchong211
with Apache License 2.0
from yangchong211
/**
* 是否是vivo刘海屏机型
*/
@SuppressWarnings("unchecked")
@SuppressLint("PrivateApi")
private static boolean hasCutoutVIVO(Activity activity) {
if (!Build.MANUFACTURER.equalsIgnoreCase("vivo")) {
return false;
}
try {
ClreplacedLoader cl = activity.getClreplacedLoader();
Clreplaced ftFeatureUtil = cl.loadClreplaced("android.util.FtFeature");
if (ftFeatureUtil != null) {
Method get = ftFeatureUtil.getMethod("isFeatureSupport", int.clreplaced);
return (boolean) get.invoke(ftFeatureUtil, 0x00000020);
}
return false;
} catch (Exception e) {
return false;
}
}
18
Source : SecurityKeyboard.java
with Apache License 2.0
from xiaohaibin
with Apache License 2.0
from xiaohaibin
/**
* @param popupWindow popupWindow 的touch事件传递
* @param touchModal true代表拦截,事件不向下一层传递,false表示不拦截,事件向下一层传递
*/
@SuppressLint("PrivateApi")
private void setPopupWindowTouchModal(PopupWindow popupWindow, boolean touchModal) {
Method method;
try {
method = PopupWindow.clreplaced.getDeclaredMethod("setTouchModal", boolean.clreplaced);
method.setAccessible(true);
method.invoke(popupWindow, touchModal);
} catch (Exception e) {
e.printStackTrace();
}
}
18
Source : TaskMoverSubModuleV28.java
with Apache License 2.0
from starscryer
with Apache License 2.0
from starscryer
@SuppressLint("PrivateApi")
@Override
Method methodForTaskMover(XC_LoadPackage.LoadPackageParam lpparam) throws ClreplacedNotFoundException, NoSuchMethodException {
String clazzName = OSUtil.isQOrAbove() ? "com.android.server.wm.TaskRecord" : "com.android.server.am.TaskRecord";
@SuppressLint("PrivateApi")
Clreplaced taskRecordClreplaced = Clreplaced.forName(clazzName, false, lpparam.clreplacedLoader);
String superVisorClazzName = OSUtil.isQOrAbove() ? "com.android.server.wm.ActivityStackSupervisor" : "com.android.server.am.ActivityStackSupervisor";
@SuppressLint("PrivateApi")
final Method moveToFront = Clreplaced.forName(superVisorClazzName, false, lpparam.clreplacedLoader).getDeclaredMethod("findTaskToMoveToFront", taskRecordClreplaced, int.clreplaced, ActivityOptions.clreplaced, String.clreplaced, boolean.clreplaced);
return moveToFront;
}
18
Source : TaskMoverSubModuleV24.java
with Apache License 2.0
from starscryer
with Apache License 2.0
from starscryer
@SuppressLint("PrivateApi")
@Override
Method methodForTaskMover(XC_LoadPackage.LoadPackageParam lpparam) throws ClreplacedNotFoundException, NoSuchMethodException {
@SuppressLint("PrivateApi")
Clreplaced taskRecordClreplaced = Clreplaced.forName("com.android.server.am.TaskRecord", false, lpparam.clreplacedLoader);
@SuppressLint("PrivateApi")
final Method moveToFront = Clreplaced.forName("com.android.server.am.ActivityStackSupervisor", false, lpparam.clreplacedLoader).getDeclaredMethod("findTaskToMoveToFrontLocked", taskRecordClreplaced, int.clreplaced, ActivityOptions.clreplaced, String.clreplaced, boolean.clreplaced);
return moveToFront;
}
18
Source : TaskMoverSubModuleV23.java
with Apache License 2.0
from starscryer
with Apache License 2.0
from starscryer
@SuppressLint("PrivateApi")
@Override
Method methodForTaskMover(XC_LoadPackage.LoadPackageParam lpparam) throws ClreplacedNotFoundException, NoSuchMethodException {
@SuppressLint("PrivateApi")
Clreplaced taskRecordClreplaced = Clreplaced.forName("com.android.server.am.TaskRecord", false, lpparam.clreplacedLoader);
return Clreplaced.forName("com.android.server.am.ActivityStackSupervisor", false, lpparam.clreplacedLoader).getDeclaredMethod("findTaskToMoveToFrontLocked", taskRecordClreplaced, int.clreplaced, Bundle.clreplaced, String.clreplaced);
}
18
Source : TaskMoverSubModuleV22.java
with Apache License 2.0
from starscryer
with Apache License 2.0
from starscryer
@SuppressLint("PrivateApi")
@Override
Method methodForTaskMover(XC_LoadPackage.LoadPackageParam lpparam) throws ClreplacedNotFoundException, NoSuchMethodException {
Clreplaced taskRecordClreplaced = Clreplaced.forName("com.android.server.am.TaskRecord", false, lpparam.clreplacedLoader);
return Clreplaced.forName("com.android.server.am.ActivityStackSupervisor", false, lpparam.clreplacedLoader).getDeclaredMethod("findTaskToMoveToFrontLocked", taskRecordClreplaced, int.clreplaced, Bundle.clreplaced, String.clreplaced);
}
18
Source : TaskMoverSubModuleV21.java
with Apache License 2.0
from starscryer
with Apache License 2.0
from starscryer
@SuppressLint("PrivateApi")
@Override
Method methodForTaskMover(XC_LoadPackage.LoadPackageParam lpparam) throws ClreplacedNotFoundException, NoSuchMethodException {
@SuppressLint("PrivateApi")
Clreplaced taskRecordClreplaced = Clreplaced.forName("com.android.server.am.TaskRecord", false, lpparam.clreplacedLoader);
return Clreplaced.forName("com.android.server.am.ActivityStackSupervisor", false, lpparam.clreplacedLoader).getDeclaredMethod("findTaskToMoveToFrontLocked", taskRecordClreplaced, int.clreplaced, Bundle.clreplaced);
}
18
Source : SystemServiceHelper.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
@SuppressLint("PrivateApi")
public clreplaced SystemServiceHelper {
private static final Map<String, IBinder> SYSTEM_SERVICE_CACHE = new HashMap<>();
private static final Map<String, Integer> TRANSACT_CODE_CACHE = new HashMap<>();
private static Method getService;
static {
try {
Clreplaced<?> sm = Clreplaced.forName("android.os.ServiceManager");
getService = sm.getMethod("getService", String.clreplaced);
} catch (ClreplacedNotFoundException | NoSuchMethodException e) {
Log.w("SystemServiceHelper", Log.getStackTraceString(e));
}
}
/**
* Returns a reference to a service with the given name.
*
* @param name the name of the service to get such as "package" for android.content.pm.IPackageManager
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
public static IBinder getSystemService(@NonNull String name) {
IBinder binder = SYSTEM_SERVICE_CACHE.get(name);
if (binder == null) {
try {
binder = (IBinder) getService.invoke(null, name);
} catch (IllegalAccessException | InvocationTargetException e) {
Log.w("SystemServiceHelper", Log.getStackTraceString(e));
}
SYSTEM_SERVICE_CACHE.put(name, binder);
}
return binder;
}
/**
* Returns transaction code from given clreplaced and method name.
*
* @param clreplacedName clreplaced name such as "android.content.pm.IPackageManager$Stub"
* @param methodName method name such as "getInstalledPackages"
* @return transaction code, or <code>null</code> if the clreplaced or the method doesn't exist
*/
public static Integer getTransactionCode(@NonNull String clreplacedName, @NonNull String methodName) {
final String fieldName = "TRANSACTION_" + methodName;
final String key = clreplacedName + "." + fieldName;
Integer value = TRANSACT_CODE_CACHE.get(key);
if (value != null)
return value;
try {
final Clreplaced<?> cls = Clreplaced.forName(clreplacedName);
Field declaredField = null;
try {
declaredField = cls.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
for (Field f : cls.getDeclaredFields()) {
if (f.getType() != int.clreplaced)
continue;
String name = f.getName();
if (name.startsWith(fieldName + "_") && TextUtils.isDigitsOnly(name.substring(fieldName.length() + 1))) {
declaredField = f;
break;
}
}
}
if (declaredField == null) {
return null;
}
declaredField.setAccessible(true);
value = declaredField.getInt(cls);
TRANSACT_CODE_CACHE.put(key, value);
return value;
} catch (ClreplacedNotFoundException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* Obtain a new data parcel for {@link Shizuku#transactRemote(Parcel, Parcel, int)}.
*
* @param serviceName system service name
* @param interfaceName clreplaced name for reflection
* @param methodName method name for reflection
* @return data parcel
* @throws NullPointerException can't get system service or transaction code
*/
public static Parcel obtainParcel(@NonNull String serviceName, @NonNull String interfaceName, @NonNull String methodName) {
return obtainParcel(serviceName, interfaceName, interfaceName + "$Stub", methodName);
}
/**
* Obtain a new data parcel for {@link Shizuku#transactRemote(Parcel, Parcel, int)}.
*
* @param serviceName system service name
* @param interfaceName interface name
* @param clreplacedName clreplaced name for reflection
* @param methodName method name for reflection
* @return data parcel
* @throws NullPointerException can't get system service or transaction code
*/
public static Parcel obtainParcel(@NonNull String serviceName, @NonNull String interfaceName, @NonNull String clreplacedName, @NonNull String methodName) {
IBinder binder = getSystemService(serviceName);
Integer code = getTransactionCode(clreplacedName, methodName);
Objects.requireNonNull(binder, "can't find system service " + serviceName);
Objects.requireNonNull(code, "can't find transaction code of " + methodName + " in " + clreplacedName);
Parcel data = Parcel.obtain();
data.writeInterfaceToken(ShizukuApiConstants.BINDER_DESCRIPTOR);
data.writeStrongBinder(binder);
data.writeInt(code);
data.writeInterfaceToken(interfaceName);
return data;
}
}
18
Source : Light.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
@SuppressWarnings({ "JavaReflectionMemberAccess", "DiscouragedPrivateApi" })
@SuppressLint("PrivateApi")
clreplaced Light {
/**
* Android uses <code>displaySize.x / 2 - windowLeft</code> as the x-coordinate of light source (<a href="http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/ThreadedRenderer.java#1021">source code</a>).
* <br>If the window is on the left of the screen, the light source will be at the right to the window
* causing shadow on the left side. This make our PopupWindow looks weird.
* <p>This method reset the x-coordinate of light source to <code>windowLeft + 56dp</code> by using multiply reflections.
*
* @param window PopupWindow
*/
static void resetLightCenterForPopupWindow(PopupWindow window) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
try {
Clreplaced<?> threadedRendererClreplaced = Clreplaced.forName("android.view.ThreadedRenderer");
Clreplaced<?> attachInfoClreplaced = Clreplaced.forName("android.view.View$AttachInfo");
View view = window.getContentView().getRootView();
Method getThreadedRendererMethod = View.clreplaced.getDeclaredMethod("getThreadedRenderer");
getThreadedRendererMethod.setAccessible(true);
Object threadedRenderer = getThreadedRendererMethod.invoke(view);
Field attachInfoField = View.clreplaced.getDeclaredField("mAttachInfo");
attachInfoField.setAccessible(true);
Object attachInfo = attachInfoField.get(view);
Field pointField = attachInfoClreplaced.getDeclaredField("mPoint");
pointField.setAccessible(true);
Point displaySize = (Point) pointField.get(attachInfo);
Field displayField = attachInfoClreplaced.getDeclaredField("mDisplay");
displayField.setAccessible(true);
Display display = (Display) displayField.get(attachInfo);
display.getRealSize(displaySize);
Field windowLeftField = attachInfoClreplaced.getDeclaredField("mWindowLeft");
windowLeftField.setAccessible(true);
int mWindowLeft = windowLeftField.getInt(attachInfo);
Field windowTopField = attachInfoClreplaced.getDeclaredField("mWindowTop");
windowTopField.setAccessible(true);
int mWindowTop = windowTopField.getInt(attachInfo);
Field lightYField = threadedRendererClreplaced.getDeclaredField("mLightY");
lightYField.setAccessible(true);
float mLightY = lightYField.getFloat(threadedRenderer);
Field lightZField = threadedRendererClreplaced.getDeclaredField("mLightZ");
lightZField.setAccessible(true);
float mLightZ = lightZField.getFloat(threadedRenderer);
Field lightRadiusField = threadedRendererClreplaced.getDeclaredField("mLightRadius");
lightRadiusField.setAccessible(true);
float mLightRadius = lightRadiusField.getFloat(threadedRenderer);
final float lightX = mWindowLeft;
final float lightY = mLightY - mWindowTop;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
((HardwareRenderer) threadedRenderer).setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius);
} else {
Field nativeProxyField = threadedRendererClreplaced.getDeclaredField("mNativeProxy");
nativeProxyField.setAccessible(true);
long mNativeProxy = nativeProxyField.getLong(threadedRenderer);
Method nSetLightCenterMethod = threadedRendererClreplaced.getDeclaredMethod("nSetLightCenter", long.clreplaced, float.clreplaced, float.clreplaced, float.clreplaced);
nSetLightCenterMethod.setAccessible(true);
nSetLightCenterMethod.invoke(null, mNativeProxy, lightX, lightY, mLightZ);
}
} catch (Throwable tr) {
tr.printStackTrace();
}
}
}
18
Source : TypefaceCompatApi26.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
@SuppressLint("PrivateApi")
@RequiresApi(api = Build.VERSION_CODES.O)
public clreplaced TypefaceCompatApi26 {
private static boolean available = true;
private static Method createFromFamiliesWithDefaultMethod;
static {
try {
createFromFamiliesWithDefaultMethod = Typeface.clreplaced.getDeclaredMethod("createFromFamiliesWithDefault", FontFamilyCompat.getFontFamilyArrayClreplaced(), Integer.TYPE, Integer.TYPE);
createFromFamiliesWithDefaultMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
available = false;
}
}
@Nullable
public static Typeface createFromFamiliesWithDefault(Object families, int weight, int italic) {
if (!available) {
return null;
}
try {
return (Typeface) createFromFamiliesWithDefaultMethod.invoke(null, families, weight, italic);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
}
18
Source : TypefaceCompat.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
@SuppressLint("PrivateApi")
public clreplaced TypefaceCompat {
private static boolean available = true;
private static Field sFallbackFontsField;
private static Field sSystemFontMapField;
private static Method createFromFamiliesMethod;
private static Method setDefaultMethod;
private static Method nativeCreateWeightAliasMethod;
private static Constructor constructor;
private static Field nativeInstanceField;
static {
try {
sFallbackFontsField = Typeface.clreplaced.getDeclaredField("sFallbackFonts");
sFallbackFontsField.setAccessible(true);
sSystemFontMapField = Typeface.clreplaced.getDeclaredField("sSystemFontMap");
sSystemFontMapField.setAccessible(true);
createFromFamiliesMethod = Typeface.clreplaced.getDeclaredMethod("createFromFamilies", FontFamilyCompat.getFontFamilyArrayClreplaced());
createFromFamiliesMethod.setAccessible(true);
setDefaultMethod = Typeface.clreplaced.getDeclaredMethod("setDefault", Typeface.clreplaced);
setDefaultMethod.setAccessible(true);
nativeCreateWeightAliasMethod = Typeface.clreplaced.getDeclaredMethod("nativeCreateWeightAlias", Long.TYPE, Integer.TYPE);
nativeCreateWeightAliasMethod.setAccessible(true);
constructor = Typeface.clreplaced.getDeclaredConstructor(Long.TYPE);
constructor.setAccessible(true);
nativeInstanceField = Typeface.clreplaced.getDeclaredField("native_instance");
nativeInstanceField.setAccessible(true);
} catch (NoSuchFieldException | NoSuchMethodException e) {
e.printStackTrace();
available = false;
}
}
/**
* Return Typeface.sFallbackFonts.
*
* @return Typeface.sFallbackFonts
*/
@Nullable
public static Object getFallbackFontsArray() {
if (!available) {
return null;
}
try {
return sFallbackFontsField.get(null);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
/**
* Set Typeface.sFallbackFonts
*
* @param array FontFamily[]
*/
public static void setFallbackFontsArray(Object array) {
if (!available) {
return;
}
try {
sFallbackFontsField.set(null, array);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static Map<String, Typeface> sSystemFontMap;
/**
* Return Typeface.sSystemFontMap.
*
* @return Typeface.sSystemFontMap
*/
@SuppressWarnings("unchecked")
@Nullable
public static Map<String, Typeface> getSystemFontMap() {
if (!available) {
return null;
}
if (sSystemFontMap == null) {
try {
sSystemFontMap = (Map<String, Typeface>) sSystemFontMapField.get(null);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
return sSystemFontMap;
}
public static void setDefault(Typeface typeface) {
if (!available) {
return;
}
try {
setDefaultMethod.invoke(null, typeface);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
private static long nativeCreateWeightAlias(long native_instance, int weight) {
if (!available) {
return -1;
}
try {
return (long) nativeCreateWeightAliasMethod.invoke(null, native_instance, weight);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return -1;
}
}
@Nullable
public static Typeface create(long ni) {
if (!available) {
return null;
}
try {
return (Typeface) constructor.newInstance(ni);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
/**
* Create new Typeface instance with weigh alias from given Typeface.
* <br>
* Use this on pre-Oreo to not breaking font fallback of other languages.
*
* @param family base Typeface
* @param weight font weight
* @return new Typeface
*/
public static Typeface createWeightAlias(Typeface family, int weight) {
if (!available) {
return family;
}
try {
return (Typeface) constructor.newInstance(nativeCreateWeightAlias(getNativeInstance(family), weight));
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return family;
}
}
/**
* Create Typeface with the order of your fontFamilies.
*
* @param families FontFamily array Object
* @return Typeface object
*/
@Nullable
public static Typeface createFromFamilies(Object families) {
if (!available) {
return null;
}
try {
return (Typeface) createFromFamiliesMethod.invoke(null, families);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
/**
* Create a new typeface from an array of font families, including
* also the font families in the fallback list.
*
* @param weight the weight for this family, only required on API 26+.
* @param italic the italic information for this family, only required on API 26+.
* @param families array of font families.
* @return Typeface object
*/
@Nullable
public static Typeface createFromFamiliesWithDefault(Object families, int weight, int italic) {
if (Build.VERSION.SDK_INT >= 26) {
return TypefaceCompatApi26.createFromFamiliesWithDefault(families, weight, italic);
} else {
return TypefaceCompatApi21.createFromFamiliesWithDefault(families);
}
}
/**
* Get native_instance of a Typeface.
*
* @param typeface Typeface instance
* @return Typeface.native_instance
* @throws IllegalAccessException native_instance not accessible
*/
public static long getNativeInstance(Typeface typeface) throws IllegalAccessException {
return (long) nativeInstanceField.get(typeface);
}
}
18
Source : FontFamilyImpl26.java
with MIT License
from RikkaApps
with MIT License
from RikkaApps
@SuppressLint("PrivateApi")
@RequiresApi(api = Build.VERSION_CODES.O)
public clreplaced FontFamilyImpl26 implements FontFamilyImpl {
private static boolean available = true;
private static Constructor constructor;
private static Method freezeMethod;
private static Method addFontFromreplacedetManagerMethod;
private static Method addFontFromBufferMethod;
static {
try {
constructor = FontFamilyCompat.getFontFamilyClreplaced().getDeclaredConstructor(String.clreplaced, int.clreplaced);
addFontFromreplacedetManagerMethod = FontFamilyCompat.getFontFamilyClreplaced().getDeclaredMethod("addFontFromreplacedetManager", replacedetManager.clreplaced, String.clreplaced, Integer.TYPE, Boolean.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE, FontVariationAxis[].clreplaced);
addFontFromBufferMethod = FontFamilyCompat.getFontFamilyClreplaced().getDeclaredMethod("addFontFromBuffer", ByteBuffer.clreplaced, Integer.TYPE, FontVariationAxis[].clreplaced, Integer.TYPE, Integer.TYPE);
freezeMethod = FontFamilyCompat.getFontFamilyClreplaced().getMethod("freeze");
} catch (NullPointerException | NoSuchMethodException e) {
e.printStackTrace();
available = false;
}
}
@Override
@Nullable
public Object create(String lang, int variant) {
if (!available) {
return null;
}
try {
return constructor.newInstance(lang, variant);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
return null;
}
}
@Override
@Nullable
public boolean addFont(Object fontFamily, ByteBuffer font, int ttcIndex, int weight, int italic) {
try {
return (Boolean) addFontFromBufferMethod.invoke(fontFamily, font, ttcIndex, null, weight, italic);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return false;
}
}
@Override
public boolean addFont(Object fontFamily, String path, int weight, int italic) {
throw new UnsupportedOperationException();
}
@Override
public boolean freeze(Object fontFamily) {
try {
return (Boolean) freezeMethod.invoke(fontFamily);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return false;
}
}
/*public boolean addFontFromreplacedetManager(replacedetManager mgr, String path, int cookie,
boolean isreplacedet, int ttcIndex, int weight, int isItalic,
FontVariationAxis[] axes) {
try {
return (Boolean) addFontFromreplacedetManagerMethod.invoke(getFontFamily(),
mgr, path, cookie, isreplacedet, ttcIndex, weight, isItalic, axes);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return false;
}
}*/
}
See More Examples