@android.annotation.SuppressLint(PrivateApi)

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 7

19 Source : ThemeManager.java
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

@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

/**
 * 通过反射获取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

/**
 * 设备类型工具类
 *
 * @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

/**
 * 获取状态栏高度
 *
 * @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

@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

@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

@SuppressLint("PrivateApi")
@NonNull
public static Context getContext() {
    return CONTEXT;
}

19 Source : CountryCodeUtil.java
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

@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

@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

/**
 * 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

@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

/**
 * 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

@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

@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

@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

@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

@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

@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

@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

/**
 * @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

/**
 * 获取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

/**
 * @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

@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

@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

@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

/**
 * 设置小米黑色状态栏字体
 */
@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

@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

@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

/**
 * 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

@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

/**
 * 目前的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

/**
 * 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

/**
 * 启动插件中的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

/**
 * 对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

/**
 * @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

/**
 * 是否是小米刘海屏机型
 */
@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

/**
 * 是否是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

/**
 * @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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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