grantedPermissions, final PackageUserState state, final int userId) {
+ throw new RuntimeException("Stub!");
+ }
+
+ /**
+ * Parse only lightweight details about the package at the given location.
+ * Automatically detects if the package is a monolithic style (single APK
+ * file) or cluster style (directory of APKs).
+ *
+ * This performs sanity checking on cluster style packages, such as
+ * requiring identical package name and version codes, a single base APK,
+ * and unique split names.
+ *
+ * @see PackageParser#parsePackage(File, int)
+ */
+ public static PackageLite parsePackageLite(final File packageFile, final int flags) throws PackageParserException {
+ throw new RuntimeException("Stub!");
+ }
+
+ /**
+ * Parse the package at the given location. Automatically detects if the
+ * package is a monolithic style (single APK file) or cluster style
+ * (directory of APKs).
+ *
+ * This performs sanity checking on cluster style packages, such as
+ * requiring identical package name and version codes, a single base APK,
+ * and unique split names.
+ *
+ * Note that this does not perform signature verification; that
+ * must be done separately in {@link #collectCertificates(Package, int)}.
+ *
+ * @see #parsePackageLite(File, int)
+ * @since Android 5.0+
+ */
+ public Package parsePackage(final File packageFile, final int flags) throws PackageParserException {
+ throw new RuntimeException("Stub!");
+ }
+
+ /**
+ *
+ * @param sourceFile
+ * @param destCodePath
+ * @param metrics
+ * @param flags
+ * @return
+ * @since Android 2.3+
+ */
+ public Package parsePackage(final File sourceFile, final String destCodePath, final DisplayMetrics metrics, final int flags) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public void collectManifestDigest(final Package pkg) throws PackageParserException {
+ throw new RuntimeException("Stub!");
+ }
+
+ public void collectCertificates(final Package pkg, final int flags) throws PackageParserException {
+ throw new RuntimeException("Stub!");
+ }
+
+ /**
+ * Utility method that retrieves lightweight details about a single APK
+ * file, including package name, split name, and install location.
+ *
+ * @param apkFile path to a single APK
+ * @param flags optional parse flags, such as
+ * {@link #PARSE_COLLECT_CERTIFICATES}
+ */
+ public static ApkLite parseApkLite(final File apkFile, final int flags) throws PackageParserException {
+ throw new RuntimeException("Stub!");
+ }
+
+ /**
+ * Representation of a full package parsed from APK files on disk. A package
+ * consists of a single base APK, and zero or more split APKs.
+ */
+ public final static class Package {
+
+ public String packageName;
+
+ /** Names of any split APKs, ordered by parsed splitName */
+ public String[] splitNames;
+
+ // TODO: work towards making these paths invariant
+
+ public String volumeUuid;
+
+ /**
+ * Path where this package was found on disk. For monolithic packages
+ * this is path to single base APK file; for cluster packages this is
+ * path to the cluster directory.
+ */
+ public String codePath;
+
+ /** Path of base APK */
+ public String baseCodePath;
+ /** Paths of any split APKs, ordered by parsed splitName */
+ public String[] splitCodePaths;
+
+ /** Revision code of base APK */
+ public int baseRevisionCode;
+ /** Revision codes of any split APKs, ordered by parsed splitName */
+ public int[] splitRevisionCodes;
+
+ /** Flags of any split APKs; ordered by parsed splitName */
+ public int[] splitFlags;
+
+ /**
+ * Private flags of any split APKs; ordered by parsed splitName.
+ *
+ * {@hide}
+ */
+ public int[] splitPrivateFlags;
+
+ public boolean baseHardwareAccelerated;
+
+ // For now we only support one application per package.
+ public final ApplicationInfo applicationInfo = new ApplicationInfo();
+
+ public final ArrayList permissions = new ArrayList(0);
+ public final ArrayList permissionGroups = new ArrayList(0);
+ public final ArrayList activities = new ArrayList(0);
+ public final ArrayList receivers = new ArrayList(0);
+ public final ArrayList providers = new ArrayList(0);
+ public final ArrayList services = new ArrayList(0);
+ public final ArrayList instrumentation = new ArrayList(0);
+
+ public final ArrayList requestedPermissions = new ArrayList();
+
+ public ArrayList protectedBroadcasts;
+
+ public ArrayList libraryNames = null;
+ public ArrayList usesLibraries = null;
+ public ArrayList usesOptionalLibraries = null;
+ public String[] usesLibraryFiles = null;
+
+ public ArrayList preferredActivityFilters = null;
+
+ public ArrayList mOriginalPackages = null;
+ public String mRealPackage = null;
+ public ArrayList mAdoptPermissions = null;
+
+ // We store the application meta-data independently to avoid multiple unwanted references
+ public Bundle mAppMetaData = null;
+
+ // The version code declared for this package.
+ public int mVersionCode;
+
+ // The version name declared for this package.
+ public String mVersionName;
+
+ // The shared user id that this package wants to use.
+ public String mSharedUserId;
+
+ // The shared user label that this package wants to use.
+ public int mSharedUserLabel;
+
+ // Signatures that were read from the package.
+ public Signature[] mSignatures;
+ public SigningDetails mSigningDetails;
+ public Certificate[][] mCertificates;
+
+ // For use by package manager service for quick lookup of
+ // preferred up order.
+ public int mPreferredOrder = 0;
+
+ // For use by package manager to keep track of where it needs to do dexopt.
+// public final ArraySet mDexOptPerformed = new ArraySet<>(4);
+
+ // For use by package manager to keep track of when a package was last used.
+ public long mLastPackageUsageTimeInMills;
+
+ // // User set enabled state.
+ // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ //
+ // // Whether the package has been stopped.
+ // public boolean mSetStopped = false;
+
+ // Additional data supplied by callers.
+ public Object mExtras;
+
+ // Applications hardware preferences
+ public ArrayList configPreferences = null;
+
+ // Applications requested features
+ public ArrayList reqFeatures = null;
+
+ // Applications requested feature groups
+ public ArrayList featureGroups = null;
+
+ public int installLocation;
+
+ public boolean coreApp;
+
+ /* An app that's required for all users and cannot be uninstalled for a user */
+ public boolean mRequiredForAllUsers;
+
+ /* The restricted account authenticator type that is used by this application */
+ public String mRestrictedAccountType;
+
+ /* The required account type without which this application will not function */
+ public String mRequiredAccountType;
+
+ /**
+ * Digest suitable for comparing whether this package's manifest is the
+ * same as another.
+ */
+ public ManifestDigest manifestDigest;
+
+ public String mOverlayTarget;
+ public int mOverlayPriority;
+ public boolean mTrustedOverlay;
+
+ /**
+ * Data used to feed the KeySetManagerService
+ */
+ public ArraySet mSigningKeys;
+ public ArraySet mUpgradeKeySets;
+ public ArrayMap> mKeySetMapping;
+
+ /**
+ * The install time abi override for this package, if any.
+ *
+ * TODO: This seems like a horrible place to put the abiOverride because
+ * this isn't something the packageParser parsers. However, this fits in with
+ * the rest of the PackageManager where package scanning randomly pushes
+ * and prods fields out of {@code this.applicationInfo}.
+ */
+ public String cpuAbiOverride;
+
+ public Package(String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public List getAllCodePaths() {
+ throw new RuntimeException("Stub!");
+ }
+
+ /**
+ * Filtered set of {@link #getAllCodePaths()} that excludes
+ * resource-only APKs.
+ */
+ public List getAllCodePathsExcludingResourceOnly() {
+ throw new RuntimeException("Stub!");
+ }
+
+ public void setPackageName(final String newName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public boolean hasComponentClassName(final String name) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public boolean isForwardLocked() {
+ throw new RuntimeException("Stub!");
+ }
+
+ public boolean isSystemApp() {
+ throw new RuntimeException("Stub!");
+ }
+
+ public boolean isPrivilegedApp() {
+ throw new RuntimeException("Stub!");
+ }
+
+ public boolean isUpdatedSystemApp() {
+ throw new RuntimeException("Stub!");
+ }
+
+ public boolean canHaveOatDir() {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public static class Component {
+ public final Package owner;
+ public final ArrayList intents;
+ public final String className;
+ public Bundle metaData;
+
+ ComponentName componentName;
+ String componentShortName;
+
+ public Component(final Package owner) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public Component(final Component clone) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public ComponentName getComponentName() {
+ throw new RuntimeException("Stub!");
+ }
+
+ public void appendComponentShortName(final StringBuilder sb) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public void printComponentShortName(final PrintWriter pw) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public void setPackageName(final String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public final static class Permission extends Component {
+ public final PermissionInfo info;
+ public boolean tree;
+ public PermissionGroup group;
+
+ public Permission(final Package owner) {
+ super(owner);
+ throw new RuntimeException("Stub!");
+ }
+
+ public Permission(final Package owner, final PermissionInfo info) {
+ super(owner);
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public void setPackageName(final String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public final static class PermissionGroup extends Component {
+ public final PermissionGroupInfo info;
+
+ public PermissionGroup(final Package owner) {
+ super(owner);
+ throw new RuntimeException("Stub!");
+ }
+
+ public PermissionGroup(final Package owner, final PermissionGroupInfo info) {
+ super(owner);
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public void setPackageName(final String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public final static class Activity extends Component {
+ public final ActivityInfo info;
+
+ public Activity(final ParseComponentArgs args, final ActivityInfo info) {
+ super(args, info);
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public void setPackageName(final String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public final static class Service extends Component {
+ public final ServiceInfo info;
+
+ public Service(final ParseComponentArgs args, final ServiceInfo info) {
+ super(args, info);
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public void setPackageName(final String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public final static class Provider extends Component {
+ public final ProviderInfo info;
+ public boolean syncable;
+
+ public Provider(final ParseComponentArgs args, final ProviderInfo info) {
+ super(args, info);
+ throw new RuntimeException("Stub!");
+ }
+
+ public Provider(final Provider existingProvider) {
+ super(existingProvider);
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public void setPackageName(final String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public final static class Instrumentation extends Component {
+ public final InstrumentationInfo info;
+
+ public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo info) {
+ super(args, info);
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public void setPackageName(final String packageName) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ @SuppressLint("ParcelCreator")
+ public static class IntentInfo extends IntentFilter {
+ public boolean hasDefault;
+ public int labelRes;
+ public CharSequence nonLocalizedLabel;
+ public int icon;
+ public int logo;
+ public int banner;
+ public int preferred;
+ }
+
+ @SuppressLint("ParcelCreator")
+ public final static class ActivityIntentInfo extends IntentInfo {
+ public final Activity activity;
+
+ public ActivityIntentInfo(final Activity activity) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ @SuppressLint("ParcelCreator")
+ public final static class ServiceIntentInfo extends IntentInfo {
+ public final Service service;
+
+ public ServiceIntentInfo(final Service service) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ @SuppressLint("ParcelCreator")
+ public static final class ProviderIntentInfo extends IntentInfo {
+ public final Provider provider;
+
+ public ProviderIntentInfo(final Provider provider) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public String toString() {
+ throw new RuntimeException("Stub!");
+ }
+ }
+
+ public static class PackageParserException extends Exception {
+
+ public PackageParserException(int error, String detailMessage) {
+ super(detailMessage);
+ throw new RuntimeException("Stub!");
+ }
+
+ public PackageParserException(int error, String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ throw new RuntimeException("Stub!");
+ }
+
+ }
+
+ public static class SigningDetails {
+ public static final SigningDetails UNKNOWN = null;
+ public Signature[] signatures;
+ }
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/android/content/pm/PackageUserState.java b/Bcore/black-fake/src/main/java/android/content/pm/PackageUserState.java
new file mode 100644
index 00000000..6dfaf259
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/android/content/pm/PackageUserState.java
@@ -0,0 +1,38 @@
+package android.content.pm;
+
+import android.util.ArraySet;
+
+/**
+ * Created by Milk on 2021/5/7.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class PackageUserState {
+
+ public boolean stopped;
+ public boolean notLaunched;
+ public boolean installed;
+ public boolean hidden; // Is the app restricted by owner / admin
+ public int enabled;
+ public boolean blockUninstall;
+
+ public String lastDisableAppCaller;
+
+ public ArraySet disabledComponents;
+ public ArraySet enabledComponents;
+
+ public int domainVerificationStatus;
+ public int appLinkGeneration;
+
+ public PackageUserState() {
+ throw new RuntimeException("Stub!");
+ }
+
+ public PackageUserState(final PackageUserState o) {
+ throw new RuntimeException("Stub!");
+ }
+
+}
diff --git a/Bcore/black-fake/src/main/java/android/content/pm/VerifierInfo.java b/Bcore/black-fake/src/main/java/android/content/pm/VerifierInfo.java
new file mode 100644
index 00000000..a8bfabc3
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/android/content/pm/VerifierInfo.java
@@ -0,0 +1,45 @@
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.security.PublicKey;
+
+/**
+ * Created by Milk on 2021/5/7.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class VerifierInfo implements Parcelable {
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public VerifierInfo createFromParcel(final Parcel source) {
+ return new VerifierInfo(source);
+ }
+
+ public VerifierInfo[] newArray(final int size) {
+ return new VerifierInfo[size];
+ }
+ };
+
+ public VerifierInfo(final String packageName, final PublicKey publicKey) {
+ throw new RuntimeException("Stub!");
+ }
+
+ private VerifierInfo(final Parcel source) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public int describeContents() {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ throw new RuntimeException("Stub!");
+ }
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/android/location/LocationRequest.java b/Bcore/black-fake/src/main/java/android/location/LocationRequest.java
new file mode 100644
index 00000000..6737f2f4
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/android/location/LocationRequest.java
@@ -0,0 +1,33 @@
+package android.location;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public final class LocationRequest implements Parcelable {
+
+ public String getProvider() {
+ return null;
+ }
+
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public LocationRequest createFromParcel(Parcel in) {
+ return null;
+ }
+
+ @Override
+ public LocationRequest[] newArray(int size) {
+ return null;
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/android/os/ParcelableException.java b/Bcore/black-fake/src/main/java/android/os/ParcelableException.java
new file mode 100644
index 00000000..52830cb4
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/android/os/ParcelableException.java
@@ -0,0 +1,60 @@
+package android.os;
+
+import android.annotation.TargetApi;
+
+import java.io.IOException;
+
+/**
+ * Wrapper class that offers to transport typical {@link Throwable} across a
+ * {@link Binder} call. This class is typically used to transport exceptions
+ * that cannot be modified to add {@link Parcelable} behavior, such as
+ * {@link IOException}.
+ *
+ * The wrapped throwable must be defined as system class (that is, it must
+ * be in the same {@link ClassLoader} as {@link Parcelable}).
+ * The wrapped throwable must support the
+ * {@link Throwable#Throwable(String)} constructor.
+ * The receiver side must catch any thrown {@link ParcelableException} and
+ * call {@link #maybeRethrow(Class)} for all expected exception types.
+ *
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public final class ParcelableException extends RuntimeException implements Parcelable {
+ public ParcelableException(Throwable t) {
+ super(t);
+ }
+
+ public void maybeRethrow(Class clazz) throws T {
+ throw new RuntimeException("Stub!");
+ }
+
+ public static Throwable readFromParcel(Parcel in) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public static void writeToParcel(Parcel out, Throwable t) {
+ throw new RuntimeException("Stub!");
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ throw new RuntimeException("Stub!");
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ParcelableException createFromParcel(Parcel source) {
+ return new ParcelableException(readFromParcel(source));
+ }
+
+ @Override
+ public ParcelableException[] newArray(int size) {
+ return new ParcelableException[size];
+ }
+ };
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/MirrorReflection.java b/Bcore/black-fake/src/main/java/mirror/MirrorReflection.java
new file mode 100644
index 00000000..8dbc69a2
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/MirrorReflection.java
@@ -0,0 +1,398 @@
+package mirror;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * Created by canyie on 2019/10/24.
+ */
+@SuppressWarnings({"unchecked", "unused", "WeakerAccess"})
+public final class MirrorReflection {
+
+ private Class> clazz;
+
+ private MirrorReflection( Class> clazz) {
+ this.clazz = clazz;
+ }
+
+
+ public Class> getClazz() {
+ return clazz;
+ }
+
+ public static MirrorReflection on( String name) {
+ return new MirrorReflection(findClass(name));
+ }
+
+ public static MirrorReflection on( String name, ClassLoader loader) {
+ return new MirrorReflection(findClass(name, loader));
+ }
+
+ public static MirrorReflection on( Class clazz) {
+ return new MirrorReflection(clazz);
+ }
+
+ public static MethodWrapper wrap( Method method) {
+ return new MethodWrapper(method);
+ }
+
+ public static StaticMethodWrapper wrapStatic( Method method) {
+ return new StaticMethodWrapper(method);
+ }
+
+ public MethodWrapper method( String name, Class>... parameterTypes) {
+ return method(clazz, name, parameterTypes);
+ }
+
+ public static MethodWrapper method( String className, String name, Class>... parameterTypes) {
+ return method(findClass(className), name, parameterTypes);
+ }
+
+ public static MethodWrapper method( Class> clazz, String name, Class>... parameterTypes) {
+ Method method = getMethod(clazz, name, parameterTypes);
+ if ((parameterTypes == null || parameterTypes.length == 0) && method == null) {
+ method = findMethodNoChecks(clazz, name);
+ }
+ return wrap(method);
+ }
+
+
+ public StaticMethodWrapper staticMethod( String name, Class>... parameterTypes) {
+ return staticMethod(clazz, name, parameterTypes);
+ }
+
+ public static StaticMethodWrapper staticMethod( String className, String name, Class>... parameterTypes) {
+ return staticMethod(findClass(className), name, parameterTypes);
+ }
+
+ public static StaticMethodWrapper staticMethod( Class> clazz, String name, Class>... parameterTypes) {
+ Method method = getMethod(clazz, name, parameterTypes);
+ if ((parameterTypes == null || parameterTypes.length == 0) && method == null) {
+ method = findMethodNoChecks(clazz, name);
+ }
+ return wrapStatic(method);
+ }
+
+ public static FieldWrapper wrap( Field field) {
+ return new FieldWrapper<>(field);
+ }
+
+ public FieldWrapper field( String name) {
+ return field(clazz, name);
+ }
+
+ public static FieldWrapper field( String className, String name) {
+ return field(findClass(className), name);
+ }
+
+ public static FieldWrapper field( Class> clazz, String name) {
+ return wrap(getField(clazz, name));
+ }
+
+ public static ConstructorWrapper wrap( Constructor constructor) {
+ return new ConstructorWrapper<>(constructor);
+ }
+
+ public ConstructorWrapper constructor( Class>... parameterTypes) {
+ return wrap(getConstructor(clazz, parameterTypes));
+ }
+
+
+
+ public static Class> findClassOrNull( String name) {
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+
+ public static Class> findClassOrNull( String name, ClassLoader loader) {
+ try {
+ return Class.forName(name, true, loader);
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+
+
+ public static Class> findClass( String name) {
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ public static Class> findClass( String name, ClassLoader loader) {
+ try {
+ return Class.forName(name, true, loader);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static Method getMethod( Class> clazz, String name, Class>... parameterTypes) {
+ return findMethod(clazz, name, parameterTypes);
+ }
+
+ public static Method getMethod( Class> clazz, String name) {
+ return findMethod(clazz, name);
+ }
+
+ private static String getParameterTypesMessage( Class>[] parameterTypes) {
+ if (parameterTypes == null || parameterTypes.length == 0) {
+ return "()";
+ }
+ StringBuilder sb = new StringBuilder("(");
+ boolean isFirst = true;
+ for (Class> type : parameterTypes) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ sb.append(",");
+ }
+ sb.append(type.getName());
+ }
+ return sb.append(')').toString();
+ }
+
+
+ public static Method findMethod( Class> clazz, String name, Class>... parameterTypes) {
+ checkForFindMethod(clazz, name, parameterTypes);
+ return findMethodNoChecks(clazz, name, parameterTypes);
+ }
+
+
+ public static Method findMethodNoChecks(Class> clazz, String name, Class>... parameterTypes) {
+ while (clazz != null) {
+ try {
+ Method method = clazz.getDeclaredMethod(name, parameterTypes);
+ method.setAccessible(true);
+ return method;
+ } catch (NoSuchMethodException ignored) {
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return null;
+ }
+
+
+ public static Method findMethodNoChecks(Class> clazz, String name) {
+ try {
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method method : methods) {
+ if (method.getName().equals(name)) {
+ method.setAccessible(true);
+ return method;
+ }
+ }
+ } catch (Throwable ignored) {
+ }
+ return null;
+ }
+
+ private static void checkForFindMethod(Class> clazz, String name, Class>... parameterTypes) {
+ if (parameterTypes != null) {
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (parameterTypes[i] == null) {
+ throw new NullPointerException("parameterTypes[" + i + "] == null");
+ }
+ }
+ }
+
+ }
+
+
+ public static Field getField( Class> clazz, String name) {
+ return findField(clazz, name);
+ }
+
+
+ public static Field findField(Class> clazz, String name) {
+ return findFieldNoChecks(clazz, name);
+ }
+
+
+ public static Field findFieldNoChecks( Class> clazz, String name) {
+ while (clazz != null) {
+ try {
+ Field field = clazz.getDeclaredField(name);
+ field.setAccessible(true);
+ return field;
+ } catch (NoSuchFieldException ignored) {
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return null;
+ }
+
+ public static Constructor getConstructor( Class> clazz, Class>... parameterTypes) {
+ return findConstructor(clazz, parameterTypes);
+ }
+
+ public static Constructor findConstructor( Class> clazz, Class>... parameterTypes) {
+ checkForFindConstructor(clazz, parameterTypes);
+ return findConstructorNoChecks(clazz, parameterTypes);
+ }
+
+ public static Constructor findConstructorNoChecks( Class> clazz, Class>... parameterTypes) {
+ try {
+ Constructor constructor = (Constructor) clazz.getDeclaredConstructor(parameterTypes);
+ constructor.setAccessible(true);
+ return constructor;
+ } catch (NoSuchMethodException ignored) {
+ }
+ return null;
+ }
+
+ private static void checkForFindConstructor(Class> clazz, Class>... parameterTypes) {
+ if (parameterTypes != null) {
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (parameterTypes[i] == null) {
+ throw new NullPointerException("parameterTypes[" + i + "] == null");
+ }
+ }
+ }
+ }
+
+ public boolean isInstance( Object instance) {
+ return clazz.isInstance(instance);
+ }
+
+ public int getModifiers() {
+ return clazz.getModifiers();
+ }
+
+ public boolean isLambdaClass() {
+ return isLambdaClass(clazz);
+ }
+
+
+ public static boolean isLambdaClass(Class> clazz) {
+ return clazz.getName().contains("$$Lambda$");
+ }
+
+ public static boolean isProxyClass(Class> clazz) {
+ return Proxy.isProxyClass(clazz);
+ }
+
+ public static void throwUnchecked(Throwable e) throws T {
+ throw (T) e;
+ }
+
+ public static class MemberWrapper {
+ M member;
+
+ MemberWrapper(M member) {
+ if (member == null)
+ return;
+ member.setAccessible(true);
+ this.member = member;
+ }
+
+
+ public final M unwrap() {
+ return member;
+ }
+
+ public final int getModifiers() {
+ return member.getModifiers();
+ }
+
+ public final Class> getDeclaringClass() {
+ return member.getDeclaringClass();
+ }
+ }
+
+ public static class MethodWrapper extends MemberWrapper {
+ MethodWrapper(Method method) {
+ super(method);
+ }
+
+ public T call(Object instance, Object... args) {
+ try {
+ return (T) member.invoke(instance, args);
+ } catch (Throwable ignored) {
+ }
+ return null;
+ }
+
+ public T callWithException(Object instance, Object... args) throws Throwable {
+ return (T) member.invoke(instance, args);
+ }
+ }
+
+ public static class StaticMethodWrapper extends MemberWrapper {
+ StaticMethodWrapper(Method method) {
+ super(method);
+ }
+
+ public T call(Object... args) {
+ try {
+ return (T) member.invoke(null, args);
+ } catch (Throwable ignored) {
+ }
+ return null;
+ }
+
+ public T callWithException(Object... args) throws Throwable {
+ return (T) member.invoke(null, args);
+ }
+ }
+
+ public static class FieldWrapper extends MemberWrapper {
+ FieldWrapper(Field field) {
+ super(field);
+ }
+
+ public T get(Object instance) {
+ try {
+ return (T) member.get(instance);
+ } catch (Throwable ignored) {
+ return null;
+ }
+ }
+
+ public T get() {
+ return get(null);
+ }
+
+ public void set(Object instance, Object value) {
+ try {
+ member.set(instance, value);
+ } catch (Throwable ignored) {
+ }
+ }
+
+ public void set(Object value) {
+ set(null, value);
+ }
+
+ public Class> getType() {
+ return member.getType();
+ }
+ }
+
+ public static class ConstructorWrapper extends MemberWrapper> {
+ ConstructorWrapper(Constructor constructor) {
+ super(constructor);
+ }
+
+ public T newInstance(Object... args) {
+ try {
+ return member.newInstance(args);
+ } catch (Throwable ignored) {
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/ActivityManagerNative.java b/Bcore/black-fake/src/main/java/mirror/android/app/ActivityManagerNative.java
new file mode 100644
index 00000000..737efd69
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/ActivityManagerNative.java
@@ -0,0 +1,21 @@
+package mirror.android.app;
+
+
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 5/20/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ActivityManagerNative {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.ActivityManagerNative");
+
+ public static MirrorReflection.FieldWrapper gDefault = REF.field("gDefault");
+ public static MirrorReflection.StaticMethodWrapper getDefault = REF.staticMethod("getDefault");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/ActivityManagerOreo.java b/Bcore/black-fake/src/main/java/mirror/android/app/ActivityManagerOreo.java
new file mode 100644
index 00000000..4f880dea
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/ActivityManagerOreo.java
@@ -0,0 +1,20 @@
+package mirror.android.app;
+
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 5/20/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ActivityManagerOreo {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.ActivityManager");
+
+ public static MirrorReflection.MethodWrapper getService = REF.method("getService");
+ public static MirrorReflection.FieldWrapper IActivityManagerSingleton = REF.field("IActivityManagerSingleton");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/ActivityThread.java b/Bcore/black-fake/src/main/java/mirror/android/app/ActivityThread.java
new file mode 100644
index 00000000..1bb95e14
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/ActivityThread.java
@@ -0,0 +1,63 @@
+package mirror.android.app;
+
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ProviderInfo;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+
+import java.util.List;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 5/20/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ActivityThread {
+ public static final String NAME = "android.app.ActivityThread";
+ public static final MirrorReflection REF = MirrorReflection.on(NAME);
+
+ public static MirrorReflection.StaticMethodWrapper currentActivityThread = REF.staticMethod("currentActivityThread");
+ public static MirrorReflection.FieldWrapper mBoundApplication = REF.field("mBoundApplication");
+ public static MirrorReflection.FieldWrapper mH = REF.field("mH");
+ public static MirrorReflection.FieldWrapper mInitialApplication = REF.field("mInitialApplication");
+ public static MirrorReflection.FieldWrapper mInstrumentation = REF.field("mInstrumentation");
+ public static MirrorReflection.FieldWrapper sPackageManager = REF.field("sPackageManager");
+ public static MirrorReflection.MethodWrapper getApplicationThread = REF.method("getApplicationThread");
+ public static MirrorReflection.MethodWrapper getSystemContext = REF.method("getSystemContext");
+
+
+ public static class ActivityClientRecord {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.ActivityThread$ActivityClientRecord");
+ public static MirrorReflection.FieldWrapper activity = REF.field("activity");
+ public static MirrorReflection.FieldWrapper activityInfo = REF.field("activityInfo");
+ public static MirrorReflection.FieldWrapper intent = REF.field("intent");
+ }
+
+ public static class AppBindData {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.ActivityThread$AppBindData");
+ public static MirrorReflection.FieldWrapper appInfo = REF.field("appInfo");
+ public static MirrorReflection.FieldWrapper info = REF.field("info");
+ public static MirrorReflection.FieldWrapper processName = REF.field("processName");
+ public static MirrorReflection.FieldWrapper instrumentationName = REF.field("instrumentationName");
+ public static MirrorReflection.FieldWrapper> providers = REF.field("providers");
+ }
+
+ public static class H {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.ActivityThread$H");
+ public static MirrorReflection.FieldWrapper LAUNCH_ACTIVITY = REF.field("LAUNCH_ACTIVITY");
+ public static MirrorReflection.FieldWrapper EXECUTE_TRANSACTION = REF.field("EXECUTE_TRANSACTION");
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/AppOpsManager.java b/Bcore/black-fake/src/main/java/mirror/android/app/AppOpsManager.java
new file mode 100644
index 00000000..b7fe594a
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/AppOpsManager.java
@@ -0,0 +1,18 @@
+package mirror.android.app;
+
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 5/20/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class AppOpsManager {
+ public static final MirrorReflection REF = MirrorReflection.on(android.app.AppOpsManager.class);
+ public static MirrorReflection.FieldWrapper mService = REF.field("mService");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/ApplicationThreadNative.java b/Bcore/black-fake/src/main/java/mirror/android/app/ApplicationThreadNative.java
new file mode 100644
index 00000000..26173cef
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/ApplicationThreadNative.java
@@ -0,0 +1,20 @@
+package mirror.android.app;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 5/20/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ApplicationThreadNative {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.ApplicationThreadNative");
+
+ public static MirrorReflection.MethodWrapper asInterface = REF.method("asInterface", IBinder.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/ContextImpl.java b/Bcore/black-fake/src/main/java/mirror/android/app/ContextImpl.java
new file mode 100644
index 00000000..174d75b7
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/ContextImpl.java
@@ -0,0 +1,15 @@
+package mirror.android.app;
+
+
+import android.content.pm.PackageManager;
+
+import mirror.MirrorReflection;
+
+public class ContextImpl {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.ContextImpl");
+
+ public static MirrorReflection.FieldWrapper mBasePackageName = REF.field("mBasePackageName");
+ public static MirrorReflection.FieldWrapper mPackageInfo = REF.field("mPackageInfo");
+ public static MirrorReflection.FieldWrapper mPackageManager = REF.field("mPackageManager");
+ public static MirrorReflection.FieldWrapper mOpPackageName = REF.field("mOpPackageName");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/IActivityManager.java b/Bcore/black-fake/src/main/java/mirror/android/app/IActivityManager.java
new file mode 100644
index 00000000..be895e4d
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/IActivityManager.java
@@ -0,0 +1,9 @@
+package mirror.android.app;
+
+import mirror.MirrorReflection;
+
+public class IActivityManager {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.IActivityManager");
+
+ public static MirrorReflection.MethodWrapper startActivity = REF.method("startActivity");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/IActivityTaskManager.java b/Bcore/black-fake/src/main/java/mirror/android/app/IActivityTaskManager.java
new file mode 100644
index 00000000..63deb14f
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/IActivityTaskManager.java
@@ -0,0 +1,15 @@
+package mirror.android.app;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class IActivityTaskManager {
+
+ public static class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.IActivityTaskManager$Stub");
+
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/IApplicationThreadOreo.java b/Bcore/black-fake/src/main/java/mirror/android/app/IApplicationThreadOreo.java
new file mode 100644
index 00000000..e76093e8
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/IApplicationThreadOreo.java
@@ -0,0 +1,13 @@
+package mirror.android.app;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class IApplicationThreadOreo {
+ public static final class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.IApplicationThread$Stub");
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/LoadedApk.java b/Bcore/black-fake/src/main/java/mirror/android/app/LoadedApk.java
new file mode 100644
index 00000000..da79ac54
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/LoadedApk.java
@@ -0,0 +1,14 @@
+package mirror.android.app;
+
+import android.app.Application;
+import android.app.Instrumentation;
+import android.content.pm.ApplicationInfo;
+import mirror.MirrorReflection;
+
+public class LoadedApk {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.LoadedApk");
+ public static MirrorReflection.FieldWrapper mApplicationInfo = REF.field("mApplicationInfo");
+ public static MirrorReflection.MethodWrapper makeApplication = REF.method("makeApplication", boolean.class, Instrumentation.class);
+
+ public static MirrorReflection.FieldWrapper mSecurityViolation = REF.field("mSecurityViolation");
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/job/IJobScheduler.java b/Bcore/black-fake/src/main/java/mirror/android/app/job/IJobScheduler.java
new file mode 100644
index 00000000..c90c642e
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/job/IJobScheduler.java
@@ -0,0 +1,13 @@
+package mirror.android.app.job;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class IJobScheduler {
+ public static class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.job.IJobScheduler$Stub");
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/servertransaction/ClientTransaction.java b/Bcore/black-fake/src/main/java/mirror/android/app/servertransaction/ClientTransaction.java
new file mode 100644
index 00000000..4af075cf
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/servertransaction/ClientTransaction.java
@@ -0,0 +1,11 @@
+package mirror.android.app.servertransaction;
+
+import java.util.List;
+
+import mirror.MirrorReflection;
+
+public class ClientTransaction {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.servertransaction.ClientTransaction");
+
+ public static MirrorReflection.FieldWrapper> mActivityCallbacks = REF.field("mActivityCallbacks");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/app/servertransaction/LaunchActivityItem.java b/Bcore/black-fake/src/main/java/mirror/android/app/servertransaction/LaunchActivityItem.java
new file mode 100644
index 00000000..cb5ea4bc
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/app/servertransaction/LaunchActivityItem.java
@@ -0,0 +1,11 @@
+package mirror.android.app.servertransaction;
+
+import android.content.Intent;
+
+import mirror.MirrorReflection;
+
+public class LaunchActivityItem {
+ public static final MirrorReflection REF = MirrorReflection.on("android.app.servertransaction.LaunchActivityItem");
+
+ public static MirrorReflection.FieldWrapper mIntent = REF.field("mIntent");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/ApplicationInfoL.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ApplicationInfoL.java
new file mode 100644
index 00000000..1edfa17f
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ApplicationInfoL.java
@@ -0,0 +1,14 @@
+package mirror.android.content.pm;
+
+import android.content.pm.ApplicationInfo;
+
+import mirror.MirrorReflection;
+
+public class ApplicationInfoL {
+ public static final MirrorReflection REF = MirrorReflection.on(ApplicationInfo.class);
+ public static MirrorReflection.FieldWrapper primaryCpuAbi = REF.field("primaryCpuAbi");
+ public static MirrorReflection.FieldWrapper scanPublicSourceDir = REF.field("scanPublicSourceDir");
+ public static MirrorReflection.FieldWrapper scanSourceDir = REF.field("scanSourceDir");
+ public static MirrorReflection.FieldWrapper secondaryCpuAbi = REF.field("secondaryCpuAbi");
+ public static MirrorReflection.FieldWrapper splitPublicSourceDirs = REF.field("splitPublicSourceDirs");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/ApplicationInfoN.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ApplicationInfoN.java
new file mode 100644
index 00000000..aacc210f
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ApplicationInfoN.java
@@ -0,0 +1,14 @@
+package mirror.android.content.pm;
+
+import android.content.pm.ApplicationInfo;
+
+import mirror.MirrorReflection;
+
+public class ApplicationInfoN {
+ public static final MirrorReflection REF = MirrorReflection.on(ApplicationInfo.class);
+
+ public static MirrorReflection.FieldWrapper deviceProtectedDataDir = REF.field("deviceProtectedDataDir");
+ public static MirrorReflection.FieldWrapper deviceEncryptedDataDir = REF.field("deviceEncryptedDataDir");
+ public static MirrorReflection.FieldWrapper credentialProtectedDataDir = REF.field("credentialProtectedDataDir");
+ public static MirrorReflection.FieldWrapper credentialEncryptedDataDir = REF.field("credentialEncryptedDataDir");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/ILauncherApps.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ILauncherApps.java
new file mode 100644
index 00000000..30733801
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ILauncherApps.java
@@ -0,0 +1,13 @@
+package mirror.android.content.pm;
+
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class ILauncherApps {
+
+ public static final class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("android.content.pm.ILauncherApps$Stub");
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface");
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParser.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParser.java
new file mode 100644
index 00000000..b91cae33
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParser.java
@@ -0,0 +1,13 @@
+package mirror.android.content.pm;
+
+import android.util.DisplayMetrics;
+import java.io.File;
+import mirror.MirrorReflection;
+
+public class PackageParser {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+
+ public static MirrorReflection.MethodWrapper collectCertificates = REF.method("collectCertificates", android.content.pm.PackageParser.Package.class, int.class);
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor(String.class);
+ public static MirrorReflection.MethodWrapper parsePackage = REF.method("parsePackage", File.class, String.class, DisplayMetrics.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserJellyBean.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserJellyBean.java
new file mode 100644
index 00000000..df9326c7
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserJellyBean.java
@@ -0,0 +1,16 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+import android.util.DisplayMetrics;
+
+import java.io.File;
+
+import mirror.MirrorReflection;
+
+public class PackageParserJellyBean {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+
+ public static MirrorReflection.MethodWrapper collectCertificates = REF.method("collectCertificates", PackageParser.Package.class, int.class);
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor(String.class);
+ public static MirrorReflection.MethodWrapper parsePackage = REF.method("parsePackage", File.class, String.class, DisplayMetrics.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserJellyBean17.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserJellyBean17.java
new file mode 100644
index 00000000..51a9d981
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserJellyBean17.java
@@ -0,0 +1,15 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+import android.util.DisplayMetrics;
+
+import java.io.File;
+
+import mirror.MirrorReflection;
+
+public class PackageParserJellyBean17 {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+ public static MirrorReflection.MethodWrapper collectCertificates = REF.method("collectCertificates", PackageParser.Package.class, int.class);
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor(String.class);
+ public static MirrorReflection.MethodWrapper parsePackage = REF.method("parsePackage", File.class, String.class, DisplayMetrics.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserLollipop.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserLollipop.java
new file mode 100644
index 00000000..0b403a5e
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserLollipop.java
@@ -0,0 +1,15 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+
+import java.io.File;
+
+import mirror.MirrorReflection;
+
+public class PackageParserLollipop {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+
+ public static MirrorReflection.MethodWrapper collectCertificates = REF.method("collectCertificates", PackageParser.Package.class, int.class);
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor();
+ public static MirrorReflection.MethodWrapper parsePackage = REF.method("parsePackage", File.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserLollipop22.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserLollipop22.java
new file mode 100644
index 00000000..b8088edc
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserLollipop22.java
@@ -0,0 +1,15 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+
+import java.io.File;
+
+import mirror.MirrorReflection;
+
+public class PackageParserLollipop22 {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+
+ public static MirrorReflection.MethodWrapper collectCertificates = REF.method("collectCertificates", PackageParser.Package.class, int.class);
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor();
+ public static MirrorReflection.MethodWrapper parsePackage = REF.method("parsePackage", File.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserMarshmallow.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserMarshmallow.java
new file mode 100644
index 00000000..d5ebf6d0
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserMarshmallow.java
@@ -0,0 +1,15 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+
+import java.io.File;
+
+import mirror.MirrorReflection;
+
+public class PackageParserMarshmallow {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+
+ public static MirrorReflection.MethodWrapper collectCertificates = REF.method("collectCertificates", PackageParser.Package.class, int.class);
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor();
+ public static MirrorReflection.MethodWrapper parsePackage = REF.method("parsePackage", File.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserNougat.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserNougat.java
new file mode 100644
index 00000000..bce0f1fa
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserNougat.java
@@ -0,0 +1,10 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+
+import mirror.MirrorReflection;
+
+public class PackageParserNougat {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+ public static MirrorReflection.StaticMethodWrapper collectCertificates = REF.staticMethod("collectCertificates", PackageParser.Package.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserPie.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserPie.java
new file mode 100644
index 00000000..a63c77d4
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/PackageParserPie.java
@@ -0,0 +1,11 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+
+import mirror.MirrorReflection;
+
+public class PackageParserPie {
+ public static final MirrorReflection REF = MirrorReflection.on(android.content.pm.PackageParser.class);
+
+ public static MirrorReflection.StaticMethodWrapper collectCertificates = REF.staticMethod("collectCertificates", PackageParser.Package.class, boolean.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/ParceledListSlice.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ParceledListSlice.java
new file mode 100644
index 00000000..d8400d01
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ParceledListSlice.java
@@ -0,0 +1,13 @@
+package mirror.android.content.pm;
+
+import android.os.Parcelable;
+
+import mirror.MirrorReflection;
+
+public class ParceledListSlice {
+ public static final MirrorReflection REF = MirrorReflection.on("android.content.pm.ParceledListSlice");
+ public static MirrorReflection.MethodWrapper append = REF.method("append");
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor();
+
+ public static MirrorReflection.MethodWrapper setLastSlice = REF.method("setLastSlice");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/ParceledListSliceJBMR2.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ParceledListSliceJBMR2.java
new file mode 100644
index 00000000..cd1f8b2b
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/ParceledListSliceJBMR2.java
@@ -0,0 +1,12 @@
+package mirror.android.content.pm;
+
+import android.os.Parcelable;
+
+import java.util.List;
+
+import mirror.MirrorReflection;
+
+public class ParceledListSliceJBMR2 {
+ public static final MirrorReflection REF = MirrorReflection.on("android.content.pm.ParceledListSlice");
+ public static MirrorReflection.ConstructorWrapper constructor = REF.constructor(List.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/content/pm/SigningInfo.java b/Bcore/black-fake/src/main/java/mirror/android/content/pm/SigningInfo.java
new file mode 100644
index 00000000..5f15a6eb
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/content/pm/SigningInfo.java
@@ -0,0 +1,19 @@
+package mirror.android.content.pm;
+
+import android.content.pm.PackageParser;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 4/16/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class SigningInfo {
+ public static final MirrorReflection REF = MirrorReflection.on("android.content.pm.SigningInfo");
+
+ public static MirrorReflection.FieldWrapper mSigningDetails = REF.field("mSigningDetails");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/BaseBundle.java b/Bcore/black-fake/src/main/java/mirror/android/os/BaseBundle.java
new file mode 100644
index 00000000..f3d9c6d4
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/BaseBundle.java
@@ -0,0 +1,10 @@
+package mirror.android.os;
+
+import android.os.Parcel;
+
+import mirror.MirrorReflection;
+
+public class BaseBundle {
+ public static final MirrorReflection REF = MirrorReflection.on("android.os.BaseBundle");
+ public static MirrorReflection.FieldWrapper mParcelledData = REF.field("mParcelledData");
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/Bundle.java b/Bcore/black-fake/src/main/java/mirror/android/os/Bundle.java
new file mode 100644
index 00000000..5cf55e43
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/Bundle.java
@@ -0,0 +1,13 @@
+package mirror.android.os;
+
+import android.os.IBinder;
+
+import mirror.MirrorReflection;
+
+public class Bundle {
+ public static final MirrorReflection REF = MirrorReflection.on(android.os.Bundle.class);
+
+ public static MirrorReflection.MethodWrapper putIBinder = REF.method("putIBinder", String.class, IBinder.class);
+
+ public static MirrorReflection.MethodWrapper getIBinder = REF.method("getIBinder", String.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/BundleICS.java b/Bcore/black-fake/src/main/java/mirror/android/os/BundleICS.java
new file mode 100644
index 00000000..d9bc44ac
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/BundleICS.java
@@ -0,0 +1,10 @@
+package mirror.android.os;
+
+import android.os.Parcel;
+
+import mirror.MirrorReflection;
+
+public class BundleICS {
+ public static final MirrorReflection REF = MirrorReflection.on(android.os.Bundle.class);
+ public static MirrorReflection.FieldWrapper mParcelledData = REF.field("mParcelledData");
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/Handler.java b/Bcore/black-fake/src/main/java/mirror/android/os/Handler.java
new file mode 100644
index 00000000..cd9fd551
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/Handler.java
@@ -0,0 +1,9 @@
+package mirror.android.os;
+
+import mirror.MirrorReflection;
+
+public class Handler {
+ public static final MirrorReflection REF = MirrorReflection.on(android.os.Handler.class);
+
+ public static MirrorReflection.FieldWrapper mCallback = REF.field("mCallback");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/IDeviceIdentifiersPolicyService.java b/Bcore/black-fake/src/main/java/mirror/android/os/IDeviceIdentifiersPolicyService.java
new file mode 100644
index 00000000..e646b0a8
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/IDeviceIdentifiersPolicyService.java
@@ -0,0 +1,13 @@
+package mirror.android.os;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class IDeviceIdentifiersPolicyService {
+ public static class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("android.os.IDeviceIdentifiersPolicyService$Stub");
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/ServiceManager.java b/Bcore/black-fake/src/main/java/mirror/android/os/ServiceManager.java
new file mode 100644
index 00000000..7746cd15
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/ServiceManager.java
@@ -0,0 +1,16 @@
+package mirror.android.os;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import java.util.Map;
+
+import mirror.MirrorReflection;
+
+public class ServiceManager {
+ public static final MirrorReflection REF = MirrorReflection.on("android.os.ServiceManager");
+ public static MirrorReflection.StaticMethodWrapper addService = REF.staticMethod("addService", String.class, IBinder.class);
+ public static MirrorReflection.StaticMethodWrapper getIServiceManager = REF.staticMethod("getIServiceManager");
+ public static MirrorReflection.StaticMethodWrapper getService = REF.staticMethod("getService");
+ public static MirrorReflection.FieldWrapper> sCache = REF.field("sCache");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/mount/IMountService.java b/Bcore/black-fake/src/main/java/mirror/android/os/mount/IMountService.java
new file mode 100644
index 00000000..04cce04f
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/mount/IMountService.java
@@ -0,0 +1,13 @@
+package mirror.android.os.mount;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class IMountService {
+ public static class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("android.os.storage.IMountService$Stub");
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/storage/IStorageManager.java b/Bcore/black-fake/src/main/java/mirror/android/os/storage/IStorageManager.java
new file mode 100644
index 00000000..206c09af
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/storage/IStorageManager.java
@@ -0,0 +1,14 @@
+package mirror.android.os.storage;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class IStorageManager {
+ public static class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("android.os.storage.IStorageManager$Stub");
+
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/storage/StorageManager.java b/Bcore/black-fake/src/main/java/mirror/android/os/storage/StorageManager.java
new file mode 100644
index 00000000..aee64b8a
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/storage/StorageManager.java
@@ -0,0 +1,19 @@
+package mirror.android.os.storage;
+
+import android.os.storage.StorageVolume;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 4/10/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class StorageManager {
+ public static final MirrorReflection REF = MirrorReflection.on("android.os.storage.StorageManager");
+
+ public static MirrorReflection.StaticMethodWrapper getVolumeList = REF.staticMethod("getVolumeList", int.class, int.class);
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/os/storage/StorageVolume.java b/Bcore/black-fake/src/main/java/mirror/android/os/storage/StorageVolume.java
new file mode 100644
index 00000000..3adf15c6
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/os/storage/StorageVolume.java
@@ -0,0 +1,20 @@
+package mirror.android.os.storage;
+
+import java.io.File;
+
+import mirror.MirrorReflection;
+
+/**
+ * Created by Milk on 4/10/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class StorageVolume {
+ public static final MirrorReflection REF = MirrorReflection.on("android.os.storage.StorageVolume");
+
+ public static MirrorReflection.FieldWrapper mPath = REF.field("mPath");
+ public static MirrorReflection.FieldWrapper mInternalPath = REF.field("mInternalPath");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/android/util/Singleton.java b/Bcore/black-fake/src/main/java/mirror/android/util/Singleton.java
new file mode 100644
index 00000000..f61f2c74
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/android/util/Singleton.java
@@ -0,0 +1,10 @@
+package mirror.android.util;
+
+
+import mirror.MirrorReflection;
+
+public class Singleton {
+ public static final MirrorReflection REF = MirrorReflection.on("android.util.Singleton");
+ public static MirrorReflection.MethodWrapper get = REF.method("get");
+ public static MirrorReflection.FieldWrapper mInstance = REF.field("mInstance");
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/com/android/internal/app/IAppOpsService.java b/Bcore/black-fake/src/main/java/mirror/com/android/internal/app/IAppOpsService.java
new file mode 100644
index 00000000..8e0c5b12
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/com/android/internal/app/IAppOpsService.java
@@ -0,0 +1,15 @@
+package mirror.com.android.internal.app;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+
+public class IAppOpsService {
+ public static class Stub {
+ public static final String NAME = "com.android.internal.app.IAppOpsService$Stub";
+ private static final MirrorReflection REF = MirrorReflection.on(NAME);
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
\ No newline at end of file
diff --git a/Bcore/black-fake/src/main/java/mirror/com/android/internal/telephony/ITelephony.java b/Bcore/black-fake/src/main/java/mirror/com/android/internal/telephony/ITelephony.java
new file mode 100644
index 00000000..58b0edcb
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/com/android/internal/telephony/ITelephony.java
@@ -0,0 +1,14 @@
+package mirror.com.android.internal.telephony;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class ITelephony {
+ public static class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("com.android.internal.telephony.ITelephony$Stub");
+
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/com/android/internal/telephony/ITelephonyRegistry.java b/Bcore/black-fake/src/main/java/mirror/com/android/internal/telephony/ITelephonyRegistry.java
new file mode 100644
index 00000000..a1209111
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/com/android/internal/telephony/ITelephonyRegistry.java
@@ -0,0 +1,14 @@
+package mirror.com.android.internal.telephony;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+import mirror.MirrorReflection;
+
+public class ITelephonyRegistry {
+
+ public static class Stub {
+ public static final MirrorReflection REF = MirrorReflection.on("com.android.internal.telephony.ITelephonyRegistry$Stub");
+ public static MirrorReflection.StaticMethodWrapper asInterface = REF.staticMethod("asInterface", IBinder.class);
+ }
+}
diff --git a/Bcore/black-fake/src/main/java/mirror/libcore/io/Libcore.java b/Bcore/black-fake/src/main/java/mirror/libcore/io/Libcore.java
new file mode 100644
index 00000000..8b230059
--- /dev/null
+++ b/Bcore/black-fake/src/main/java/mirror/libcore/io/Libcore.java
@@ -0,0 +1,10 @@
+package mirror.libcore.io;
+
+import mirror.MirrorReflection;
+
+public class Libcore {
+ public static final String NAME = "libcore.io.Libcore";
+ public static final MirrorReflection REF = MirrorReflection.on(NAME);
+
+ public static MirrorReflection.FieldWrapper os = REF.field("os");
+}
diff --git a/Bcore/black-hook/.gitignore b/Bcore/black-hook/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/Bcore/black-hook/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/Bcore/black-hook/build.gradle b/Bcore/black-hook/build.gradle
new file mode 100644
index 00000000..50d2c8bf
--- /dev/null
+++ b/Bcore/black-hook/build.gradle
@@ -0,0 +1,62 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.3"
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ dexOptions {
+ preDexLibraries false
+ maxProcessCount 8
+ javaMaxHeapSize "4g"
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ aaptOptions {
+ cruncherEnabled = false
+ useNewCruncher = false
+ }
+ testOptions {
+ unitTests.returnDefaultValues = true
+ }
+ lintOptions {
+ checkReleaseBuilds false
+ abortOnError false
+ warningsAsErrors false
+ disable "UnusedResources", 'RestrictedApi'
+ textOutput "stdout"
+ textReport false
+ check 'NewApi', 'InlinedApi'
+ }
+}
+
+
+tasks.withType(Javadoc) {
+ options.addStringOption('Xdoclint:none', '-quiet')
+ options.addStringOption('encoding', 'UTF-8')
+ options.addStringOption('charSet', 'UTF-8')
+}
+
+dependencies {
+
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'com.google.android.material:material:1.3.0'
+}
\ No newline at end of file
diff --git a/Bcore/black-hook/consumer-rules.pro b/Bcore/black-hook/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/Bcore/black-hook/proguard-rules.pro b/Bcore/black-hook/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/Bcore/black-hook/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/Bcore/black-hook/src/main/AndroidManifest.xml b/Bcore/black-hook/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..df9d7518
--- /dev/null
+++ b/Bcore/black-hook/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/MethodUtils.java b/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/MethodUtils.java
new file mode 100644
index 00000000..b8ba47c5
--- /dev/null
+++ b/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/MethodUtils.java
@@ -0,0 +1,93 @@
+package top.niunaijun.jnihook;
+
+/**
+ * Created by Milk on 3/8/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+
+import androidx.annotation.Keep;
+
+import java.lang.reflect.Method;
+
+@Keep
+public class MethodUtils {
+
+ // native call
+ public static String getDeclaringClass(final Method method) {
+ return method.getDeclaringClass().getName().replace(".", "/");
+ }
+
+ // native call
+ public static String getMethodName(final Method method) {
+ return method.getName();
+ }
+
+ // native call
+ public static String getDesc(final Method method) {
+ final StringBuffer buf = new StringBuffer();
+ buf.append("(");
+ final Class>[] types = method.getParameterTypes();
+ for (int i = 0; i < types.length; ++i) {
+ buf.append(getDesc(types[i]));
+ }
+ buf.append(")");
+ buf.append(getDesc(method.getReturnType()));
+ return buf.toString();
+ }
+
+ private static String getDesc(final Class> returnType) {
+ if (returnType.isPrimitive()) {
+ return getPrimitiveLetter(returnType);
+ }
+ if (returnType.isArray()) {
+ return "[" + getDesc(returnType.getComponentType());
+ }
+ return "L" + getType(returnType) + ";";
+ }
+
+ private static String getType(final Class> parameterType) {
+ if (parameterType.isArray()) {
+ return "[" + getDesc(parameterType.getComponentType());
+ }
+ if (!parameterType.isPrimitive()) {
+ final String clsName = parameterType.getName();
+ return clsName.replaceAll("\\.", "/");
+ }
+ return getPrimitiveLetter(parameterType);
+ }
+
+ private static String getPrimitiveLetter(final Class> type) {
+ if (Integer.TYPE.equals(type)) {
+ return "I";
+ }
+ if (Void.TYPE.equals(type)) {
+ return "V";
+ }
+ if (Boolean.TYPE.equals(type)) {
+ return "Z";
+ }
+ if (Character.TYPE.equals(type)) {
+ return "C";
+ }
+ if (Byte.TYPE.equals(type)) {
+ return "B";
+ }
+ if (Short.TYPE.equals(type)) {
+ return "S";
+ }
+ if (Float.TYPE.equals(type)) {
+ return "F";
+ }
+ if (Long.TYPE.equals(type)) {
+ return "J";
+ }
+ if (Double.TYPE.equals(type)) {
+ return "D";
+ }
+ throw new IllegalStateException("Type: " + type.getCanonicalName() + " is not a primitive type");
+ }
+}
\ No newline at end of file
diff --git a/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/ReflectCore.java b/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/ReflectCore.java
new file mode 100644
index 00000000..4057630d
--- /dev/null
+++ b/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/ReflectCore.java
@@ -0,0 +1,37 @@
+package top.niunaijun.jnihook;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import top.niunaijun.jnihook.jni.JniHook;
+
+/**
+ * Created by Milk on 2021/5/7.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ReflectCore {
+
+ public static void set(Class> clazz) {
+ try {
+ Field accessFlags = Class.class.getDeclaredField("accessFlags");
+ accessFlags.setAccessible(true);
+ int o = (int) accessFlags.get(clazz);
+ accessFlags.set(clazz, o | 0x0001);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ for (Method declaredMethod : clazz.getDeclaredMethods()) {
+ JniHook.setAccessible(clazz, declaredMethod);
+ }
+ for (Field declaredField : clazz.getDeclaredFields()) {
+ JniHook.setAccessible(clazz, declaredField);
+ }
+ for (Class> declaredClass : clazz.getDeclaredClasses()) {
+ set(declaredClass);
+ }
+ }
+}
diff --git a/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/jni/JniHook.java b/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/jni/JniHook.java
new file mode 100644
index 00000000..0b4eba07
--- /dev/null
+++ b/Bcore/black-hook/src/main/java/top/niunaijun/jnihook/jni/JniHook.java
@@ -0,0 +1,26 @@
+package top.niunaijun.jnihook.jni;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Created by Milk on 3/7/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public final class JniHook {
+ public static final int NATIVE_OFFSET = 0;
+
+ public static final int NATIVE_OFFSET_2 = 0;
+
+ public static final native void nativeOffset();
+
+ public static final native void nativeOffset2();
+
+ public static native void setAccessible(Class> clazz, Method method);
+
+ public static native void setAccessible(Class> clazz, Field field);
+}
diff --git a/Bcore/build.gradle b/Bcore/build.gradle
new file mode 100644
index 00000000..837a011f
--- /dev/null
+++ b/Bcore/build.gradle
@@ -0,0 +1,74 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 28
+ buildToolsVersion "28.0.2"
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+
+ consumerProguardFiles "consumer-rules.pro"
+ ndk {
+ // 设置支持的SO库架构
+ abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ ndkBuild {
+ path file('src/main/jni/Android.mk')
+ }
+ }
+ dexOptions {
+ preDexLibraries false
+ maxProcessCount 8
+ javaMaxHeapSize "4g"
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ aaptOptions {
+ cruncherEnabled = false
+ useNewCruncher = false
+ }
+ testOptions {
+ unitTests.returnDefaultValues = true
+ }
+ lintOptions {
+ checkReleaseBuilds false
+ abortOnError false
+ warningsAsErrors false
+ disable "UnusedResources", 'RestrictedApi'
+ textOutput "stdout"
+ textReport false
+ check 'NewApi', 'InlinedApi'
+ }
+}
+
+
+tasks.withType(Javadoc) {
+ options.addStringOption('Xdoclint:none', '-quiet')
+ options.addStringOption('encoding', 'UTF-8')
+ options.addStringOption('charSet', 'UTF-8')
+}
+
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+
+ implementation 'me.weishu:free_reflection:3.0.1'
+ implementation project(':Bcore:black-hook')
+ implementation project(':Bcore:black-fake')
+ implementation 'com.swift.sandhook:hooklib:4.2.0'
+}
\ No newline at end of file
diff --git a/Bcore/consumer-rules.pro b/Bcore/consumer-rules.pro
new file mode 100644
index 00000000..de119130
--- /dev/null
+++ b/Bcore/consumer-rules.pro
@@ -0,0 +1,27 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+-keep class top.niunaijun.blackbox.** {*; }
+-keep class top.niunaijun.jnihook.** {*; }
+-keep class mirror.** {*; }
+-keep class android.** {*; }
+-keep class com.android.** {*; }
diff --git a/Bcore/proguard-rules.pro b/Bcore/proguard-rules.pro
new file mode 100644
index 00000000..de119130
--- /dev/null
+++ b/Bcore/proguard-rules.pro
@@ -0,0 +1,27 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+-keep class top.niunaijun.blackbox.** {*; }
+-keep class top.niunaijun.jnihook.** {*; }
+-keep class mirror.** {*; }
+-keep class android.** {*; }
+-keep class com.android.** {*; }
diff --git a/Bcore/src/main/AndroidManifest.xml b/Bcore/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..71450130
--- /dev/null
+++ b/Bcore/src/main/AndroidManifest.xml
@@ -0,0 +1,2558 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/android/accounts/IAccountAuthenticator.aidl b/Bcore/src/main/aidl/android/accounts/IAccountAuthenticator.aidl
new file mode 100644
index 00000000..fe5c9eaf
--- /dev/null
+++ b/Bcore/src/main/aidl/android/accounts/IAccountAuthenticator.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+import android.accounts.IAccountAuthenticatorResponse;
+import android.accounts.Account;
+import android.os.Bundle;
+
+/**
+ * Service that allows the interaction with an authentication server.
+ * @hide
+ */
+interface IAccountAuthenticator {
+ /**
+ * prompts the user for account information and adds the result to the IAccountManager
+ */
+ void addAccount(in IAccountAuthenticatorResponse response, String accountType,
+ String authTokenType, in String[] requiredFeatures, in Bundle options);
+
+ /**
+ * prompts the user for the credentials of the account
+ */
+ void confirmCredentials(in IAccountAuthenticatorResponse response, in Account account,
+ in Bundle options);
+
+ /**
+ * gets the password by either prompting the user or querying the IAccountManager
+ */
+ void getAuthToken(in IAccountAuthenticatorResponse response, in Account account,
+ String authTokenType, in Bundle options);
+
+ /**
+ * Gets the user-visible label of the given authtoken type.
+ */
+ void getAuthTokenLabel(in IAccountAuthenticatorResponse response, String authTokenType);
+
+ /**
+ * prompts the user for a new password and writes it to the IAccountManager
+ */
+ void updateCredentials(in IAccountAuthenticatorResponse response, in Account account,
+ String authTokenType, in Bundle options);
+
+ /**
+ * launches an activity that lets the user edit and set the properties for an authenticator
+ */
+ void editProperties(in IAccountAuthenticatorResponse response, String accountType);
+
+ /**
+ * returns a Bundle where the boolean value BOOLEAN_RESULT_KEY is set if the account has the
+ * specified features
+ */
+ void hasFeatures(in IAccountAuthenticatorResponse response, in Account account,
+ in String[] features);
+
+ /**
+ * Gets whether or not the account is allowed to be removed.
+ */
+ void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);
+
+ /**
+ * Returns a Bundle containing the required credentials to copy the account across users.
+ */
+ void getAccountCredentialsForCloning(in IAccountAuthenticatorResponse response,
+ in Account account);
+
+ /**
+ * Uses the Bundle containing credentials from another instance of the authenticator to create
+ * a copy of the account on this user.
+ */
+ void addAccountFromCredentials(in IAccountAuthenticatorResponse response, in Account account,
+ in Bundle accountCredentials);
+}
diff --git a/Bcore/src/main/aidl/android/accounts/IAccountAuthenticatorResponse.aidl b/Bcore/src/main/aidl/android/accounts/IAccountAuthenticatorResponse.aidl
new file mode 100644
index 00000000..5218bd74
--- /dev/null
+++ b/Bcore/src/main/aidl/android/accounts/IAccountAuthenticatorResponse.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+import android.os.Bundle;
+
+/**
+ * The interface used to return responses from an {@link IAccountAuthenticator}
+ */
+interface IAccountAuthenticatorResponse {
+ void onResult(in Bundle value);
+ void onRequestContinued();
+ void onError(int errorCode, String errorMessage);
+}
diff --git a/Bcore/src/main/aidl/android/accounts/IAccountManagerResponse.aidl b/Bcore/src/main/aidl/android/accounts/IAccountManagerResponse.aidl
new file mode 100644
index 00000000..ed33d905
--- /dev/null
+++ b/Bcore/src/main/aidl/android/accounts/IAccountManagerResponse.aidl
@@ -0,0 +1,11 @@
+package android.accounts;
+
+import android.os.Bundle;
+
+/**
+ * The interface used to return responses for asynchronous calls to the {@link IAccountManager}
+ */
+interface IAccountManagerResponse {
+ void onResult(in Bundle value);
+ void onError(int errorCode, String errorMessage);
+}
diff --git a/Bcore/src/main/aidl/android/app/IActivityManager/ContentProviderHolder.aidl b/Bcore/src/main/aidl/android/app/IActivityManager/ContentProviderHolder.aidl
new file mode 100644
index 00000000..8643b692
--- /dev/null
+++ b/Bcore/src/main/aidl/android/app/IActivityManager/ContentProviderHolder.aidl
@@ -0,0 +1,4 @@
+// ContentProviderHolder.aidl
+package android.app.IActivityManager;
+
+parcelable ContentProviderHolder;
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/android/app/IServiceConnection.aidl b/Bcore/src/main/aidl/android/app/IServiceConnection.aidl
new file mode 100644
index 00000000..e312ecb4
--- /dev/null
+++ b/Bcore/src/main/aidl/android/app/IServiceConnection.aidl
@@ -0,0 +1,26 @@
+/* //device/java/android/android/app/IServiceConnection.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.app;
+
+import android.content.ComponentName;
+
+/** @hide */
+interface IServiceConnection {
+ void connected(in ComponentName name, IBinder service);
+}
+
diff --git a/Bcore/src/main/aidl/android/app/IStopUserCallback.aidl b/Bcore/src/main/aidl/android/app/IStopUserCallback.aidl
new file mode 100644
index 00000000..19ac1d5d
--- /dev/null
+++ b/Bcore/src/main/aidl/android/app/IStopUserCallback.aidl
@@ -0,0 +1,27 @@
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.app;
+
+/**
+ * Callback to find out when we have finished stopping a user.
+ * {@hide}
+ */
+interface IStopUserCallback
+{
+ void userStopped(int userId);
+ void userStopAborted(int userId);
+}
diff --git a/Bcore/src/main/aidl/android/app/IWallpaperManagerCallback.aidl b/Bcore/src/main/aidl/android/app/IWallpaperManagerCallback.aidl
new file mode 100644
index 00000000..9bc19435
--- /dev/null
+++ b/Bcore/src/main/aidl/android/app/IWallpaperManagerCallback.aidl
@@ -0,0 +1,24 @@
+/* //device/java/android/android/app/IServiceConnection.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.app;
+
+/** @hide */
+interface IWallpaperManagerCallback {
+ void onWallpaperChanged();
+}
+
diff --git a/Bcore/src/main/aidl/android/app/job/IJobCallback.aidl b/Bcore/src/main/aidl/android/app/job/IJobCallback.aidl
new file mode 100644
index 00000000..e567268b
--- /dev/null
+++ b/Bcore/src/main/aidl/android/app/job/IJobCallback.aidl
@@ -0,0 +1,62 @@
+/**
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.job;
+
+import android.app.job.JobWorkItem;
+
+/**
+ * The server side of the JobScheduler IPC protocols. The app-side implementation
+ * invokes on this interface to indicate completion of the (asynchronous) instructions
+ * issued by the server.
+ *
+ * In all cases, the 'who' parameter is the caller's service binder, used to track
+ * which Job Service instance is reporting.
+ *
+ */
+interface IJobCallback {
+ /**
+ * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
+ *
+ * @param jobId Unique integer used to identify this job.
+ * @param ongoing True to indicate that the client is processing the job. False if the job is
+ * complete
+ */
+ void acknowledgeStartMessage(int jobId, boolean ongoing);
+ /**
+ * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
+ *
+ * @param jobId Unique integer used to identify this job.
+ * @param reschedule Whether or not to reschedule this job.
+ */
+ void acknowledgeStopMessage(int jobId, boolean reschedule);
+ /*
+ * Called to deqeue next work item for the job.
+ */
+ JobWorkItem dequeueWork(int jobId);
+ /*
+ * Called to report that job has completed processing a work item.
+ */
+ boolean completeWork(int jobId, int workId);
+ /*
+ * Tell the job manager that the client is done with its execution, so that it can go on to
+ * the next one and stop attributing wakelock time to us etc.
+ *
+ * @param jobId Unique integer used to identify this job.
+ * @param reschedule Whether or not to reschedule this job.
+ */
+ void jobFinished(int jobId, boolean reschedule);
+}
diff --git a/Bcore/src/main/aidl/android/app/job/IJobService.aidl b/Bcore/src/main/aidl/android/app/job/IJobService.aidl
new file mode 100644
index 00000000..7992da31
--- /dev/null
+++ b/Bcore/src/main/aidl/android/app/job/IJobService.aidl
@@ -0,0 +1,15 @@
+package android.app.job;
+
+import android.app.job.JobParameters;
+
+/**
+ * Interface that the framework uses to communicate with application code that implements a
+ * JobService. End user code does not implement this interface directly; instead, the app's
+ * service implementation will extend android.app.job.JobService.
+ */
+interface IJobService {
+ /** Begin execution of application's job. */
+ void startJob(in JobParameters jobParams);
+ /** Stop execution of application's job. */
+ void stopJob(in JobParameters jobParams);
+}
diff --git a/Bcore/src/main/aidl/android/app/job/JobWorkItem.aidl b/Bcore/src/main/aidl/android/app/job/JobWorkItem.aidl
new file mode 100644
index 00000000..4634ec2d
--- /dev/null
+++ b/Bcore/src/main/aidl/android/app/job/JobWorkItem.aidl
@@ -0,0 +1,4 @@
+// JobWorkItem.aidl
+package android.app.job;
+
+parcelable JobWorkItem;
diff --git a/Bcore/src/main/aidl/android/content/IIntentReceiver.aidl b/Bcore/src/main/aidl/android/content/IIntentReceiver.aidl
new file mode 100644
index 00000000..40d9303e
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/IIntentReceiver.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * System private API for dispatching intent broadcasts. This is given to the
+ * activity manager as part of registering for an intent broadcasts, and is
+ * called when it receives intents.
+ *
+ */
+interface IIntentReceiver {
+ void performReceive(in Intent intent, int resultCode, String data,
+ in Bundle extras, boolean ordered, boolean sticky, int sendingUser);
+}
+
diff --git a/Bcore/src/main/aidl/android/content/ISyncAdapter.aidl b/Bcore/src/main/aidl/android/content/ISyncAdapter.aidl
new file mode 100644
index 00000000..2325fffe
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/ISyncAdapter.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.content.ISyncContext;
+
+/**
+ * Interface used to control the sync activity on a SyncAdapter
+ */
+interface ISyncAdapter {
+ /**
+ * Initiate a sync for this account. SyncAdapter-specific parameters may
+ * be specified in extras, which is guaranteed to not be null.
+ *
+ * @param syncContext the ISyncContext used to indicate the progress of the sync. When
+ * the sync is finished (successfully or not) ISyncContext.onFinished() must be called.
+ * @param authority the authority that should be synced
+ * @param account the account that should be synced
+ * @param extras SyncAdapter-specific parameters
+ */
+ void startSync(ISyncContext syncContext, String authority,
+ in Account account, in Bundle extras);
+
+ /**
+ * Cancel the most recently initiated sync. Due to race conditions, this may arrive
+ * after the ISyncContext.onFinished() for that sync was called.
+ * @param syncContext the ISyncContext that was passed to {@link #startSync}
+ */
+ void cancelSync(ISyncContext syncContext);
+
+ /**
+ * Initialize the SyncAdapter for this account and authority.
+ *
+ * @param account the account that should be synced
+ * @param authority the authority that should be synced
+ */
+ void initialize(in Account account, String authority);
+}
diff --git a/Bcore/src/main/aidl/android/content/ISyncContext.aidl b/Bcore/src/main/aidl/android/content/ISyncContext.aidl
new file mode 100644
index 00000000..6d18a1ce
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/ISyncContext.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.content.SyncResult;
+
+/**
+ * Interface used by the SyncAdapter to indicate its progress.
+ * @hide
+ */
+interface ISyncContext {
+ /**
+ * Call to indicate that the SyncAdapter is making progress. E.g., if this SyncAdapter
+ * downloads or sends records to/from the server, this may be called after each record
+ * is downloaded or uploaded.
+ */
+ void sendHeartbeat();
+
+ /**
+ * Signal that the corresponding sync session is completed.
+ * @param result information about this sync session
+ */
+ void onFinished(in SyncResult result);
+}
diff --git a/Bcore/src/main/aidl/android/content/ISyncStatusObserver.aidl b/Bcore/src/main/aidl/android/content/ISyncStatusObserver.aidl
new file mode 100644
index 00000000..88ea23a0
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/ISyncStatusObserver.aidl
@@ -0,0 +1,6 @@
+package android.content;
+
+
+interface ISyncStatusObserver {
+ void onStatusChanged(int which);
+}
diff --git a/Bcore/src/main/aidl/android/content/SyncStatusInfo.aidl b/Bcore/src/main/aidl/android/content/SyncStatusInfo.aidl
new file mode 100644
index 00000000..fe0293c9
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/SyncStatusInfo.aidl
@@ -0,0 +1,3 @@
+package android.content;
+
+parcelable SyncStatusInfo;
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/android/content/pm/IPackageDataObserver.aidl b/Bcore/src/main/aidl/android/content/pm/IPackageDataObserver.aidl
new file mode 100644
index 00000000..118ba5a0
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/pm/IPackageDataObserver.aidl
@@ -0,0 +1,10 @@
+package android.content.pm;
+
+/**
+ * API for package data change related callbacks from the Package Manager.
+ * Some usage scenarios include deletion of cache directory, generate
+ * statistics related to code, data, cache usage(TODO)
+ */
+interface IPackageDataObserver {
+ void onRemoveCompleted(in String packageName, boolean succeeded);
+}
diff --git a/Bcore/src/main/aidl/android/content/pm/IPackageDeleteObserver2.aidl b/Bcore/src/main/aidl/android/content/pm/IPackageDeleteObserver2.aidl
new file mode 100644
index 00000000..8ab0c5cd
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/pm/IPackageDeleteObserver2.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.Intent;
+
+interface IPackageDeleteObserver2 {
+ void onUserActionRequired(in Intent intent);
+ void onPackageDeleted(String packageName, int returnCode, String msg);
+}
diff --git a/Bcore/src/main/aidl/android/content/pm/IPackageInstallObserver.aidl b/Bcore/src/main/aidl/android/content/pm/IPackageInstallObserver.aidl
new file mode 100644
index 00000000..4ec7d4bf
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/pm/IPackageInstallObserver.aidl
@@ -0,0 +1,9 @@
+package android.content.pm;
+
+/**
+ * API for installation callbacks from the Package Manager.
+ */
+interface IPackageInstallObserver {
+ void packageInstalled(in String packageName, int returnCode);
+}
+
diff --git a/Bcore/src/main/aidl/android/content/pm/IPackageInstallObserver2.aidl b/Bcore/src/main/aidl/android/content/pm/IPackageInstallObserver2.aidl
new file mode 100644
index 00000000..6894622b
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/pm/IPackageInstallObserver2.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * API for installation callbacks from the Package Manager. In certain result cases
+ * additional information will be provided.
+ */
+interface IPackageInstallObserver2 {
+ void onUserActionRequired(in Intent intent);
+
+ /**
+ * The install operation has completed. {@code returnCode} holds a numeric code
+ * indicating success or failure. In certain cases the {@code extras} Bundle will
+ * contain additional details:
+ *
+ *
+ *
+ * INSTALL_FAILED_DUPLICATE_PERMISSION
+ * Two strings are provided in the extras bundle: EXTRA_EXISTING_PERMISSION
+ * is the name of the permission that the app is attempting to define, and
+ * EXTRA_EXISTING_PACKAGE is the package name of the app which has already
+ * defined the permission.
+ *
+ *
+ */
+ void onPackageInstalled(String basePackageName, int returnCode, String msg, in Bundle extras);
+}
diff --git a/Bcore/src/main/aidl/android/content/pm/IPackageInstallerCallback.aidl b/Bcore/src/main/aidl/android/content/pm/IPackageInstallerCallback.aidl
new file mode 100644
index 00000000..14b0d36b
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/pm/IPackageInstallerCallback.aidl
@@ -0,0 +1,9 @@
+package android.content.pm;
+
+interface IPackageInstallerCallback {
+ void onSessionCreated(int sessionId);
+ void onSessionBadgingChanged(int sessionId);
+ void onSessionActiveChanged(int sessionId, boolean active);
+ void onSessionProgressChanged(int sessionId, float progress);
+ void onSessionFinished(int sessionId, boolean success);
+}
diff --git a/Bcore/src/main/aidl/android/content/pm/IPackageInstallerSession.aidl b/Bcore/src/main/aidl/android/content/pm/IPackageInstallerSession.aidl
new file mode 100644
index 00000000..c2c70fe7
--- /dev/null
+++ b/Bcore/src/main/aidl/android/content/pm/IPackageInstallerSession.aidl
@@ -0,0 +1,20 @@
+package android.content.pm;
+
+import android.content.pm.IPackageInstallObserver2;
+import android.content.IntentSender;
+import android.os.ParcelFileDescriptor;
+
+interface IPackageInstallerSession {
+ void setClientProgress(float progress);
+ void addClientProgress(float progress);
+
+ String[] getNames();
+ ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
+ ParcelFileDescriptor openRead(String name);
+
+ void removeSplit(String splitName);
+
+ void close();
+ void commit(in IntentSender statusReceiver);
+ void abandon();
+}
diff --git a/Bcore/src/main/aidl/android/database/IContentObserver.aidl b/Bcore/src/main/aidl/android/database/IContentObserver.aidl
new file mode 100644
index 00000000..e395dc75
--- /dev/null
+++ b/Bcore/src/main/aidl/android/database/IContentObserver.aidl
@@ -0,0 +1,13 @@
+package android.database;
+
+import android.net.Uri;
+
+interface IContentObserver
+{
+ /**
+ * This method is called when an update occurs to the cursor that is being
+ * observed. selfUpdate is true if the update was caused by a call to
+ * commit on the cursor that is being observed.
+ */
+ void onChange(boolean selfUpdate, in Uri uri, int userId);
+}
diff --git a/Bcore/src/main/aidl/android/location/ILocationListener.aidl b/Bcore/src/main/aidl/android/location/ILocationListener.aidl
new file mode 100644
index 00000000..1571ae26
--- /dev/null
+++ b/Bcore/src/main/aidl/android/location/ILocationListener.aidl
@@ -0,0 +1,13 @@
+// ILocationListener.aidl
+package android.location;
+
+import android.location.Location;
+import android.os.Bundle;
+
+interface ILocationListener
+{
+ void onLocationChanged(in Location location);
+ void onStatusChanged(String provider, int status, in Bundle extras);
+ void onProviderEnabled(String provider);
+ void onProviderDisabled(String provider);
+}
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/android/net/IConnectivityManager.aidl b/Bcore/src/main/aidl/android/net/IConnectivityManager.aidl
new file mode 100644
index 00000000..c26314e5
--- /dev/null
+++ b/Bcore/src/main/aidl/android/net/IConnectivityManager.aidl
@@ -0,0 +1,18 @@
+package android.net;
+
+import android.net.NetworkInfo;
+import android.net.LinkProperties;
+
+interface IConnectivityManager {
+
+ NetworkInfo getActiveNetworkInfo();
+ NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked);
+
+ NetworkInfo getNetworkInfo(int networkType);
+ NetworkInfo[] getAllNetworkInfo();
+ boolean isActiveNetworkMetered();
+ boolean requestRouteToHostAddress(int networkType, int address);
+ LinkProperties getActiveLinkProperties();
+ LinkProperties getLinkProperties(int networkType);
+
+}
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/android/net/wifi/IWifiScanner.aidl b/Bcore/src/main/aidl/android/net/wifi/IWifiScanner.aidl
new file mode 100644
index 00000000..3e71a5f8
--- /dev/null
+++ b/Bcore/src/main/aidl/android/net/wifi/IWifiScanner.aidl
@@ -0,0 +1,11 @@
+package android.net.wifi;
+
+import android.os.Messenger;
+import android.os.Bundle;
+
+interface IWifiScanner
+{
+ Messenger getMessenger();
+
+ Bundle getAvailableChannels(int band);
+}
diff --git a/Bcore/src/main/aidl/android/os/ISystemUpdateManager.aidl b/Bcore/src/main/aidl/android/os/ISystemUpdateManager.aidl
new file mode 100644
index 00000000..cfce2106
--- /dev/null
+++ b/Bcore/src/main/aidl/android/os/ISystemUpdateManager.aidl
@@ -0,0 +1,9 @@
+package android.os;
+
+import android.os.Bundle;
+import android.os.PersistableBundle;
+
+interface ISystemUpdateManager {
+ Bundle retrieveSystemUpdateInfo();
+ void updateSystemUpdateInfo(in PersistableBundle data);
+}
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/com/android/internal/widget/ILockSettings.aidl b/Bcore/src/main/aidl/com/android/internal/widget/ILockSettings.aidl
new file mode 100644
index 00000000..7c725f89
--- /dev/null
+++ b/Bcore/src/main/aidl/com/android/internal/widget/ILockSettings.aidl
@@ -0,0 +1,6 @@
+package com.android.internal.widget;
+
+interface ILockSettings {
+ void setRecoverySecretTypes(in int[] secretTypes);
+ int[] getRecoverySecretTypes();
+}
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/IBActivityThread.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/IBActivityThread.aidl
new file mode 100644
index 00000000..bc379998
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/IBActivityThread.aidl
@@ -0,0 +1,15 @@
+// IBActivityThread.aidl
+package top.niunaijun.blackbox.core;
+
+// Declare any non-default types here with import statements
+
+import android.os.IBinder;
+import android.content.ComponentName;
+import android.content.Intent;
+import java.util.List;
+import android.content.pm.ResolveInfo;
+
+interface IBActivityThread {
+ IBinder getActivityThread();
+ void bindApplication();
+}
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/am/IBActivityManagerService.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/am/IBActivityManagerService.aidl
new file mode 100644
index 00000000..19502048
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/am/IBActivityManagerService.aidl
@@ -0,0 +1,39 @@
+// IBActivityManagerService.aidl
+package top.niunaijun.blackbox.core.system.am;
+
+import android.content.Intent;
+import android.content.ComponentName;
+import android.content.pm.ServiceInfo;
+import android.content.pm.ProviderInfo;
+import android.os.IBinder;
+import java.lang.String;
+import android.app.IServiceConnection;
+import top.niunaijun.blackbox.entity.AppConfig;
+import android.os.Bundle;
+
+// Declare any non-default types here with import statements
+
+interface IBActivityManagerService {
+ AppConfig initProcess(String packageName, String processName, int userId);
+ void restartProcess(String packageName, String processName, int userId);
+
+ void startActivity(in Intent intent, int userId);
+ int startActivityAms(int userId, in Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, in Bundle options);
+ int startActivities(int userId, in Intent[] intent, in String[] resolvedType, IBinder resultTo, in Bundle options);
+
+ ComponentName startService(in Intent intent, String resolvedType, int userId);
+ int stopService(in Intent intent,in String resolvedType, int userId);
+
+ Intent bindService(in Intent service, in IBinder binder, String resolvedType, int userId);
+ void unbindService(in IBinder binder, int userId);
+
+ void onStartCommand(in Intent proxyIntent, int userId);
+ void onServiceDestroy(in Intent proxyIntent, int userId);
+
+ Intent sendBroadcast(in Intent intent, String resolvedType, int userId);
+
+ void onActivityCreated(int taskId, IBinder token, IBinder activityRecord);
+ void onActivityResumed(IBinder token);
+ void onActivityDestroyed(IBinder token);
+ void onFinishActivity(IBinder token);
+}
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/os/IBStorageManagerService.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/os/IBStorageManagerService.aidl
new file mode 100644
index 00000000..275c20ee
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/os/IBStorageManagerService.aidl
@@ -0,0 +1,12 @@
+// IBStorageManagerService.aidl
+package top.niunaijun.blackbox.core.system.os;
+
+import android.os.storage.StorageVolume;
+import java.lang.String;
+import android.net.Uri;
+
+// Declare any non-default types here with import statements
+
+interface IBStorageManagerService {
+ StorageVolume[] getVolumeList(int uid, String packageName, int flags, int userId);
+}
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/BPackageSettings.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/BPackageSettings.aidl
new file mode 100644
index 00000000..fd330248
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/BPackageSettings.aidl
@@ -0,0 +1,6 @@
+// BPackageSettings.aidl
+package top.niunaijun.blackbox.core.system.pm;
+
+// Declare any non-default types here with import statements
+
+parcelable BPackageSettings;
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/IBPackageInstallerService.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/IBPackageInstallerService.aidl
new file mode 100644
index 00000000..cc4e3336
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/IBPackageInstallerService.aidl
@@ -0,0 +1,13 @@
+// IBPackageInstallerService.aidl
+package top.niunaijun.blackbox.core.system.pm;
+
+import top.niunaijun.blackbox.core.system.pm.BPackageSettings;
+import top.niunaijun.blackbox.entity.pm.InstallOption;
+
+// Declare any non-default types here with import statements
+
+interface IBPackageInstallerService {
+ int installPackageAsUser(in BPackageSettings file, int userId);
+ int uninstallPackageAsUser(in BPackageSettings file, boolean removeApp, int userId);
+ int updatePackage(in BPackageSettings file);
+}
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/IBPackageManagerService.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/IBPackageManagerService.aidl
new file mode 100644
index 00000000..1ad735a0
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/pm/IBPackageManagerService.aidl
@@ -0,0 +1,45 @@
+// IBPackageManagerService.aidl
+package top.niunaijun.blackbox.core.system.pm;
+
+// Declare any non-default types here with import statements
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ProviderInfo;
+import android.content.Intent;
+import android.content.ComponentName;
+import java.util.List;
+import top.niunaijun.blackbox.entity.pm.InstallResult;
+import top.niunaijun.blackbox.entity.pm.InstallOption;
+import top.niunaijun.blackbox.entity.pm.InstalledPackage;
+
+
+interface IBPackageManagerService {
+ ResolveInfo resolveService(in Intent intent, int flags, String resolvedType, int userId);
+ ResolveInfo resolveActivity(in Intent intent, int flags, String resolvedType, int userId);
+ ProviderInfo resolveContentProvider(String authority, int flag, int userId);
+ ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
+
+ ApplicationInfo getApplicationInfo(String packageName, int flags, int userId);
+ PackageInfo getPackageInfo(String packageName, int flags, int userId);
+ ServiceInfo getServiceInfo(in ComponentName component, int flags, int userId);
+ ActivityInfo getReceiverInfo(in ComponentName componentName, int flags, int userId);
+ ActivityInfo getActivityInfo(in ComponentName component, int flags, int userId);
+ ProviderInfo getProviderInfo(in ComponentName component, int flags, int userId);
+ List getInstalledApplications(int flags, int userId);
+ List getInstalledPackages(int flags, int userId);
+
+ List queryIntentActivities(in Intent intent, int flags, String resolvedType, int userId);
+ List queryBroadcastReceivers(in Intent intent, int flags, String resolvedType, int userId);
+ List queryContentProviders(String processName, int uid, int flags, int userId);
+
+ InstallResult installPackageAsUser(String file, in InstallOption option, int userId);
+ void uninstallPackageAsUser(String packageName, int userId);
+ void uninstallPackage(String packageName);
+ void deleteUser(int userId);
+
+ boolean isInstalled(String packageName, int userId);
+ List getInstalledPackagesAsUser(int userId);
+}
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/user/BUserInfo.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/user/BUserInfo.aidl
new file mode 100644
index 00000000..573c98d3
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/user/BUserInfo.aidl
@@ -0,0 +1,5 @@
+// BUserInfo.aidl
+package top.niunaijun.blackbox.core.system.user;
+
+// Declare any non-default types here with import statements
+parcelable BUserInfo;
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/user/IBUserManagerService.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/user/IBUserManagerService.aidl
new file mode 100644
index 00000000..896e8658
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/core/system/user/IBUserManagerService.aidl
@@ -0,0 +1,15 @@
+// IBUserManagerService.aidl
+package top.niunaijun.blackbox.core.system.user;
+
+// Declare any non-default types here with import statements
+import top.niunaijun.blackbox.core.system.user.BUserInfo;
+import java.util.List;
+
+
+interface IBUserManagerService {
+ BUserInfo getUserInfo(int userId);
+ boolean exists(int userId);
+ BUserInfo createUser(int userId);
+ List getUsers();
+ void deleteUser(int userId);
+}
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/AppConfig.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/AppConfig.aidl
new file mode 100644
index 00000000..aac73d99
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/AppConfig.aidl
@@ -0,0 +1,6 @@
+// AppConfig.aidl
+package top.niunaijun.blackbox.entity;
+
+// Declare any non-default types here with import statements
+
+parcelable AppConfig;
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstallOption.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstallOption.aidl
new file mode 100644
index 00000000..ab8cacb1
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstallOption.aidl
@@ -0,0 +1,3 @@
+package top.niunaijun.blackbox.entity.pm;
+
+parcelable InstallOption;
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstallResult.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstallResult.aidl
new file mode 100644
index 00000000..bb15a61e
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstallResult.aidl
@@ -0,0 +1,3 @@
+package top.niunaijun.blackbox.entity.pm;
+
+parcelable InstallResult;
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstalledModule.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstalledModule.aidl
new file mode 100644
index 00000000..1fd84cb4
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstalledModule.aidl
@@ -0,0 +1,3 @@
+package top.niunaijun.blackbox.entity.pm;
+
+parcelable InstalledModule;
\ No newline at end of file
diff --git a/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstalledPackage.aidl b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstalledPackage.aidl
new file mode 100644
index 00000000..b66321fb
--- /dev/null
+++ b/Bcore/src/main/aidl/top/niunaijun/blackbox/entity/pm/InstalledPackage.aidl
@@ -0,0 +1,3 @@
+package top.niunaijun.blackbox.entity.pm;
+
+parcelable InstalledPackage;
\ No newline at end of file
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java
new file mode 100644
index 00000000..c5347128
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java
@@ -0,0 +1,276 @@
+package top.niunaijun.blackbox;
+
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.Process;
+
+import top.niunaijun.blackbox.app.configuration.ClientConfiguration;
+import top.niunaijun.blackbox.proxy.ProxyManifest;
+import top.niunaijun.blackbox.app.configuration.AppLifecycleCallback;
+import top.niunaijun.blackbox.fake.hook.HookManager;
+import top.niunaijun.blackbox.entity.pm.InstallOption;
+import top.niunaijun.blackbox.entity.pm.InstallResult;
+import top.niunaijun.blackbox.core.system.DaemonService;
+import top.niunaijun.blackbox.utils.FileUtils;
+import top.niunaijun.blackbox.utils.ShellUtils;
+import top.niunaijun.blackbox.utils.compat.BuildCompat;
+import top.niunaijun.blackbox.utils.compat.BundleCompat;
+import top.niunaijun.blackbox.utils.provider.ProviderCall;
+import top.niunaijun.blackbox.fake.frameworks.BActivityManager;
+import top.niunaijun.blackbox.fake.frameworks.BPackageManager;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import me.weishu.reflection.Reflection;
+import mirror.android.app.ActivityThread;
+import top.niunaijun.blackbox.fake.frameworks.BStorageManager;
+import top.niunaijun.blackbox.core.system.ServiceManager;
+
+/**
+ * Created by Milk on 3/30/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+@SuppressLint("StaticFieldLeak")
+public class BlackBoxCore extends ClientConfiguration {
+ public static final String TAG = "BlackBoxCore";
+ private static final int USER_ID = 0;
+
+ private static final BlackBoxCore sBlackBoxCore = new BlackBoxCore();
+ private static Context sContext;
+ private ProcessType mProcessType;
+ private final Map mServices = new HashMap<>();
+ private ClientConfiguration mClientConfiguration;
+ private AppLifecycleCallback mAppLifecycleCallback = AppLifecycleCallback.EMPTY;
+
+ public static BlackBoxCore get() {
+ return sBlackBoxCore;
+ }
+
+ public static PackageManager getPackageManager() {
+ return sContext.getPackageManager();
+ }
+
+ public static String getHostPkg() {
+ return get().getHostPackageName();
+ }
+
+ public static Context getContext() {
+ return sContext;
+ }
+
+ public void doAttachBaseContext(Context context, ClientConfiguration clientConfiguration) {
+ if (clientConfiguration == null) {
+ throw new IllegalArgumentException("ClientConfiguration is null!");
+ }
+ Reflection.unseal(context);
+ sContext = context;
+ mClientConfiguration = clientConfiguration;
+ mClientConfiguration.init();
+ String processName = getProcessName(getContext());
+ if (processName.equals(BlackBoxCore.getHostPkg())) {
+ mProcessType = ProcessType.Main;
+ startLogcat();
+ } else if (processName.endsWith(getContext().getString(R.string.black_box_service_name))) {
+ mProcessType = ProcessType.Server;
+ } else {
+ mProcessType = ProcessType.BAppClient;
+ }
+ if (BlackBoxCore.get().isVirtualProcess()) {
+ if (processName.endsWith("p0")) {
+// android.os.Debug.waitForDebugger();
+ }
+// android.os.Debug.waitForDebugger();
+ }
+ if (isServerProcess()) {
+ Intent intent = new Intent();
+ intent.setClass(getContext(), DaemonService.class);
+ if (BuildCompat.isOreo()) {
+ getContext().startForegroundService(intent);
+ } else {
+ getContext().startService(intent);
+ }
+ }
+ HookManager.get().init();
+ }
+
+ public void doCreate() {
+ // fix contentProvider
+ if (isVirtualProcess()) {
+ }
+ if (!isServerProcess()) {
+ initService();
+ }
+ }
+
+ private void initService() {
+ get().getService(ServiceManager.ACTIVITY_MANAGER);
+ get().getService(ServiceManager.PACKAGE_MANAGER);
+ get().getService(ServiceManager.STORAGE_MANAGER);
+ }
+
+ public static Object mainThread() {
+ return ActivityThread.currentActivityThread.call();
+ }
+
+ public void startActivity(Intent intent, int userId) {
+ getBActivityManager().startActivity(intent, userId);
+ }
+
+ public static BPackageManager getBPackageManager() {
+ return BPackageManager.get();
+ }
+
+ public static BActivityManager getBActivityManager() {
+ return BActivityManager.get();
+ }
+
+ public static BStorageManager getBStorageManager() {
+ return BStorageManager.get();
+ }
+
+ public boolean launchApk(String packageName) {
+ Intent launchIntentForPackage = getBPackageManager().getLaunchIntentForPackage(packageName, USER_ID);
+ if (launchIntentForPackage == null) {
+ return false;
+ }
+ startActivity(launchIntentForPackage, USER_ID);
+ return true;
+ }
+
+ public boolean isInstalled(String packageName) {
+ return getBPackageManager().isInstalled(packageName, USER_ID);
+ }
+
+ public void uninstallPackage(String packageName) {
+ getBPackageManager().uninstallPackageAsUser(packageName, USER_ID);
+ }
+
+ public InstallResult installPackage(String packageName) {
+ try {
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(packageName, 0);
+ return getBPackageManager().installPackageAsUser(packageInfo.applicationInfo.sourceDir, InstallOption.installBySystem(), USER_ID);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return new InstallResult().installError(e.getMessage());
+ }
+ }
+
+ public InstallResult installPackage(File apk) {
+ return getBPackageManager().installPackageAsUser(apk.getAbsolutePath(), InstallOption.installByStorage(), USER_ID);
+ }
+
+ public InstallResult installPackage(Uri apk) {
+ return getBPackageManager().installPackageAsUser(apk.toString(), InstallOption.installByStorage().makeUriFile(), USER_ID);
+ }
+
+ public AppLifecycleCallback getAppLifecycleCallback() {
+ return mAppLifecycleCallback;
+ }
+
+ public void setAppLifecycleCallback(AppLifecycleCallback appLifecycleCallback) {
+ if (appLifecycleCallback == null) {
+ throw new IllegalArgumentException("AppLifecycleCallback is null!");
+ }
+ mAppLifecycleCallback = appLifecycleCallback;
+ }
+
+ public IBinder getService(String name) {
+ IBinder binder = mServices.get(name);
+ if (binder != null && binder.isBinderAlive()) {
+ return binder;
+ }
+ Bundle bundle = new Bundle();
+ bundle.putString("_VM_|_server_name_", name);
+ Bundle vm = ProviderCall.callSafely(ProxyManifest.getBindProvider(), "VM", null, bundle);
+ assert vm != null;
+ binder = BundleCompat.getBinder(vm, "_VM_|_server_");
+ mServices.put(name, binder);
+ return binder;
+ }
+
+ /**
+ * Process type
+ */
+ private enum ProcessType {
+ /**
+ * Server process
+ */
+ Server,
+ /**
+ * Virtual app process
+ */
+ BAppClient,
+ /**
+ * Main process
+ */
+ Main,
+ }
+
+ public boolean isVirtualProcess() {
+ return mProcessType == ProcessType.BAppClient;
+ }
+
+ public boolean isMainProcess() {
+ return mProcessType == ProcessType.Main;
+ }
+
+ public boolean isServerProcess() {
+ return mProcessType == ProcessType.Server;
+ }
+
+ @Override
+ public String getHostPackageName() {
+ return mClientConfiguration.getHostPackageName();
+ }
+
+ @Override
+ public String getDexDumpDir() {
+ return mClientConfiguration.getDexDumpDir();
+ }
+
+ private void startLogcat() {
+ File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), getContext().getPackageName() + "_logcat.txt");
+ FileUtils.deleteDir(file);
+ ShellUtils.execCommand("logcat -c", false);
+ ShellUtils.execCommand("logcat >> " + file.getAbsolutePath() + " &", false);
+ }
+
+ private static String getProcessName(Context context) {
+ int pid = Process.myPid();
+ String processName = null;
+ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ for (ActivityManager.RunningAppProcessInfo info : am.getRunningAppProcesses()) {
+ if (info.pid == pid) {
+ processName = info.processName;
+ break;
+ }
+ }
+ if (processName == null) {
+ throw new RuntimeException("processName = null");
+ }
+ return processName;
+ }
+
+ public static boolean is64Bit() {
+ if (BuildCompat.isM()) {
+ return Process.is64Bit();
+ } else {
+ return Build.CPU_ABI.equals("arm64-v8a");
+ }
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
new file mode 100644
index 00000000..3b459215
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
@@ -0,0 +1,222 @@
+package top.niunaijun.blackbox.app;
+
+import android.app.Application;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.os.Build;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+import mirror.android.app.ActivityThread;
+import mirror.android.app.ContextImpl;
+import mirror.android.app.LoadedApk;
+import top.niunaijun.blackbox.core.IBActivityThread;
+import top.niunaijun.blackbox.core.VMCore;
+import top.niunaijun.blackbox.entity.AppConfig;
+import top.niunaijun.blackbox.core.IOCore;
+import top.niunaijun.blackbox.utils.compat.ContextCompat;
+import top.niunaijun.blackbox.BlackBoxCore;
+
+/**
+ * Created by Milk on 3/31/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class BActivityThread extends IBActivityThread.Stub {
+ public static final String TAG = "BActivityThread";
+
+ private static BActivityThread sBActivityThread;
+ private AppBindData mBoundApplication;
+ private Application mInitialApplication;
+ private AppConfig mAppConfig;
+ private final List mProviders = new ArrayList<>();
+
+ public static BActivityThread currentActivityThread() {
+ if (sBActivityThread == null) {
+ synchronized (BActivityThread.class) {
+ if (sBActivityThread == null) {
+ sBActivityThread = new BActivityThread();
+ }
+ }
+ }
+ return sBActivityThread;
+ }
+
+ public static synchronized AppConfig getAppConfig() {
+ return currentActivityThread().mAppConfig;
+ }
+
+ public static List getProviders() {
+ return currentActivityThread().mProviders;
+ }
+
+ public static String getAppProcessName() {
+ if (getAppConfig() != null) {
+ return getAppConfig().processName;
+ } else if (currentActivityThread().mBoundApplication != null) {
+ return currentActivityThread().mBoundApplication.processName;
+ } else {
+ return null;
+ }
+ }
+
+ public static String getAppPackageName() {
+ if (getAppConfig() != null) {
+ return getAppConfig().packageName;
+ } else if (currentActivityThread().mInitialApplication != null) {
+ return currentActivityThread().mInitialApplication.getPackageName();
+ } else {
+ return null;
+ }
+ }
+
+ public static Application getApplication() {
+ return currentActivityThread().mInitialApplication;
+ }
+
+ public static int getAppPid() {
+ return getAppConfig() == null ? -1 : getAppConfig().bpid;
+ }
+
+ public static int getAppUid() {
+ return getAppConfig() == null ? 10000 : getAppConfig().buid;
+ }
+
+ public static int getBaseAppUid() {
+ return getAppConfig() == null ? 10000 : getAppConfig().baseBUid;
+ }
+
+ public static int getUid() {
+ return getAppConfig() == null ? -1 : getAppConfig().uid;
+ }
+
+ public static int getUserId() {
+ return getAppConfig() == null ? 0 : getAppConfig().userId;
+ }
+
+ public void initProcess(AppConfig appConfig) {
+ if (this.mAppConfig != null) {
+ throw new RuntimeException("reject init process: " + appConfig.processName + ", this process is : " + this.mAppConfig.processName);
+ }
+ this.mAppConfig = appConfig;
+ }
+
+ public boolean isInit() {
+ return mBoundApplication != null;
+ }
+
+ public void bindApplication(final String packageName, final String processName) {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ final ConditionVariable conditionVariable = new ConditionVariable();
+ new Handler(Looper.getMainLooper()).post(() -> {
+ handleBindApplication(packageName, processName);
+ conditionVariable.open();
+ });
+ conditionVariable.block();
+ } else {
+ handleBindApplication(packageName, processName);
+ }
+ }
+
+ public synchronized void handleBindApplication(String packageName, String processName) {
+ PackageInfo packageInfo = BlackBoxCore.getBPackageManager().getPackageInfo(packageName, PackageManager.GET_PROVIDERS, BActivityThread.getUserId());
+ if (packageInfo == null)
+ return;
+ ApplicationInfo applicationInfo = packageInfo.applicationInfo;
+ if (packageInfo.providers == null) {
+ packageInfo.providers = new ProviderInfo[]{};
+ }
+ mProviders.addAll(Arrays.asList(packageInfo.providers));
+
+ Object boundApplication = ActivityThread.mBoundApplication.get(BlackBoxCore.mainThread());
+
+ Context packageContext = createPackageContext(applicationInfo);
+ Object loadedApk = ContextImpl.mPackageInfo.get(packageContext);
+ LoadedApk.mSecurityViolation.set(loadedApk, false);
+ // fix applicationInfo
+ LoadedApk.mApplicationInfo.set(loadedApk, applicationInfo);
+
+ VMCore.init(Build.VERSION.SDK_INT);
+ assert packageContext != null;
+ IOCore.get().enableRedirect(packageContext);
+
+ AppBindData bindData = new AppBindData();
+ bindData.appInfo = applicationInfo;
+ bindData.processName = processName;
+ bindData.info = loadedApk;
+ bindData.providers = mProviders;
+
+ ActivityThread.AppBindData.instrumentationName.set(boundApplication,
+ new ComponentName(bindData.appInfo.packageName, Instrumentation.class.getName()));
+ ActivityThread.AppBindData.appInfo.set(boundApplication, bindData.appInfo);
+ ActivityThread.AppBindData.info.set(boundApplication, bindData.info);
+ ActivityThread.AppBindData.processName.set(boundApplication, bindData.processName);
+ ActivityThread.AppBindData.providers.set(boundApplication, bindData.providers);
+
+ mBoundApplication = bindData;
+
+ Application application;
+ BlackBoxCore.get().getAppLifecycleCallback().beforeCreateApplication(packageName, processName, packageContext);
+ try {
+ application = LoadedApk.makeApplication.call(loadedApk, false, null);
+
+ mInitialApplication = application;
+ ActivityThread.mInitialApplication.set(BlackBoxCore.mainThread(), mInitialApplication);
+ ContextCompat.fix((Context) ActivityThread.getSystemContext.call(BlackBoxCore.mainThread()));
+ ContextCompat.fix(mInitialApplication);
+
+ if (Objects.equals(packageName, processName)) {
+ VMCore.dumpDex(mInitialApplication.getClassLoader(), processName);
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ throw new RuntimeException("Unable to makeApplication", e);
+ } finally {
+ BlackBoxCore.get().uninstallPackage(packageName);
+ }
+ }
+
+ private Context createPackageContext(ApplicationInfo info) {
+ try {
+ return BlackBoxCore.getContext().createPackageContext(info.packageName,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public IBinder getActivityThread() {
+ return ActivityThread.getApplicationThread.call(BlackBoxCore.mainThread());
+ }
+
+ @Override
+ public void bindApplication() {
+ if (!isInit()) {
+ bindApplication(getAppPackageName(), getAppProcessName());
+ }
+ }
+
+ public static class AppBindData {
+ String processName;
+ ApplicationInfo appInfo;
+ List providers;
+ Object info;
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/AppLifecycleCallback.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/AppLifecycleCallback.java
new file mode 100644
index 00000000..ebd5a3de
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/AppLifecycleCallback.java
@@ -0,0 +1,30 @@
+package top.niunaijun.blackbox.app.configuration;
+
+import android.app.Application;
+import android.content.Context;
+
+/**
+ * Created by Milk on 5/5/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class AppLifecycleCallback {
+ public static AppLifecycleCallback EMPTY = new AppLifecycleCallback() {
+
+ };
+
+ public void beforeCreateApplication(String packageName, String processName, Context context) {
+
+ }
+
+ public void beforeApplicationOnCreate(String packageName, String processName, Application application) {
+
+ }
+
+ public void afterApplicationOnCreate(String packageName, String processName, Application application) {
+
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/ClientConfiguration.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/ClientConfiguration.java
new file mode 100644
index 00000000..36c2185e
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/ClientConfiguration.java
@@ -0,0 +1,32 @@
+package top.niunaijun.blackbox.app.configuration;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import top.niunaijun.blackbox.BlackBoxCore;
+import top.niunaijun.blackbox.utils.FileUtils;
+
+/**
+ * Created by Milk on 5/4/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public abstract class ClientConfiguration {
+ private File mExternalFilesDir;
+
+ public final void init() {
+ mExternalFilesDir = BlackBoxCore.getContext().getExternalCacheDir().getParentFile();
+ }
+
+ public abstract String getHostPackageName();
+
+ public String getDexDumpDir() {
+ File dump = new File(mExternalFilesDir, "dump");
+ FileUtils.mkdirs(dump);
+ return dump.getAbsolutePath();
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/IOCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/IOCore.java
new file mode 100644
index 00000000..d52ae305
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/IOCore.java
@@ -0,0 +1,140 @@
+package top.niunaijun.blackbox.core;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.text.TextUtils;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import top.niunaijun.blackbox.BlackBoxCore;
+import top.niunaijun.blackbox.app.BActivityThread;
+import top.niunaijun.blackbox.utils.FileUtils;
+
+/**
+ * Created by Milk on 4/9/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+@SuppressLint("SdCardPath")
+public class IOCore {
+ private static final IOCore sIOCore = new IOCore();
+ private final Map mRedirectMap = new LinkedHashMap<>();
+
+ private static final Map> sCachePackageRedirect = new HashMap<>();
+
+ public static IOCore get() {
+ return sIOCore;
+ }
+
+ // /data/data/com.google/ -----> /data/data/com.virtual/data/com.google/
+ public void addRedirect(String origPath, String redirectPath) {
+ if (TextUtils.isEmpty(origPath) || TextUtils.isEmpty(redirectPath) || mRedirectMap.get(origPath) != null)
+ return;
+ mRedirectMap.put(origPath, redirectPath);
+ File redirectFile = new File(redirectPath);
+ if (!redirectFile.exists()) {
+ FileUtils.mkdirs(redirectPath);
+ }
+ VMCore.addIORule(origPath, redirectPath);
+ }
+
+ public String redirectPath(String path) {
+ if (TextUtils.isEmpty(path))
+ return path;
+ for (String orig : mRedirectMap.keySet()) {
+ if (path.startsWith(orig)) {
+ path = path.replace(orig, Objects.requireNonNull(mRedirectMap.get(orig)));
+ break;
+ }
+ }
+ return path;
+ }
+
+ public File redirectPath(File path) {
+ if (path == null)
+ return null;
+ String pathStr = path.getAbsolutePath();
+ return new File(redirectPath(pathStr));
+ }
+
+ public String redirectPath(String path, Map rule) {
+ if (TextUtils.isEmpty(path))
+ return path;
+ for (String orig : rule.keySet()) {
+ if (path.startsWith(orig)) {
+ path = path.replace(orig, Objects.requireNonNull(rule.get(orig)));
+ break;
+ }
+ }
+ return path;
+ }
+
+ public File redirectPath(File path, Map rule) {
+ if (path == null)
+ return null;
+ String pathStr = path.getAbsolutePath();
+ return new File(redirectPath(pathStr, rule));
+ }
+
+ // 由于正常情况Application已完成重定向,以下重定向是怕代码写死。
+ public void enableRedirect(Context context) {
+ Map rule = new LinkedHashMap<>();
+ String packageName = context.getPackageName();
+
+ try {
+ ApplicationInfo packageInfo = BlackBoxCore.getBPackageManager().getApplicationInfo(packageName, PackageManager.GET_META_DATA, BActivityThread.getUserId());
+ rule.put("/data/data/" + packageName + "/lib", packageInfo.nativeLibraryDir);
+ rule.put("/data/user/0/" + packageName + "/lib", packageInfo.nativeLibraryDir);
+
+ rule.put("/data/data/" + packageName, packageInfo.dataDir);
+ rule.put("/data/user/0/" + packageName, packageInfo.dataDir);
+
+ if (BlackBoxCore.getContext().getExternalCacheDir() != null && context.getExternalCacheDir() != null) {
+ File external = context.getExternalCacheDir().getParentFile();
+
+ // sdcard
+ rule.put("/sdcard/Android/data/" + packageName,
+ external.getAbsolutePath());
+ rule.put("/sdcard/android/data/" + packageName, external.getAbsolutePath());
+
+ rule.put("/storage/emulated/0/android/data/" + packageName,
+ external.getAbsolutePath());
+ rule.put("/storage/emulated/0/Android/data/" + packageName,
+ external.getAbsolutePath());
+
+ rule.put("/storage/emulated/0/Android/data/" + packageName + "/files",
+ new File(external.getAbsolutePath(), "files").getAbsolutePath());
+ rule.put("/storage/emulated/0/Android/data/" + packageName + "/cache",
+ new File(external.getAbsolutePath(), "cache").getAbsolutePath());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ for (String key : rule.keySet()) {
+ get().addRedirect(key, rule.get(key));
+ }
+ VMCore.enableIO();
+ }
+
+ private void hideRoot(Map rule) {
+ rule.put("/system/app/Superuser.apk", "/system/app/Superuser.apk-fake");
+ rule.put("/sbin/su", "/sbin/su-fake");
+ rule.put("/system/bin/su", "/system/bin/su-fake");
+ rule.put("/system/xbin/su", "/system/xbin/su-fake");
+ rule.put("/data/local/xbin/su", "/data/local/xbin/su-fake");
+ rule.put("/data/local/bin/su", "/data/local/bin/su-fake");
+ rule.put("/system/sd/xbin/su", "/system/sd/xbin/su-fake");
+ rule.put("/system/bin/failsafe/su", "/system/bin/failsafe/su-fake");
+ rule.put("/data/local/su", "/data/local/su-fake");
+ rule.put("/su/bin/su", "/su/bin/su-fake");
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/VMCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/VMCore.java
new file mode 100644
index 00000000..bb980b40
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/VMCore.java
@@ -0,0 +1,101 @@
+package top.niunaijun.blackbox.core;
+
+
+import androidx.annotation.Keep;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import dalvik.system.DexFile;
+import top.niunaijun.blackbox.BlackBoxCore;
+import top.niunaijun.blackbox.utils.FileUtils;
+import top.niunaijun.blackbox.utils.Reflector;
+import top.niunaijun.blackbox.utils.compat.DexFileCompat;
+
+import static top.niunaijun.blackbox.core.env.BEnvironment.EMPTY_JAR;
+
+/**
+ * Created by Milk on 4/9/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class VMCore {
+ public static final String TAG = "VMCoreJava";
+
+ static {
+ new File("");
+ if (BlackBoxCore.is64Bit()) {
+ try {
+ System.loadLibrary("vm64");
+ } catch (Throwable e) {
+ System.loadLibrary("vm");
+ }
+ } else {
+ System.loadLibrary("vm");
+ }
+ }
+
+ public static native void init(int apiLevel);
+
+ public static native void enableIO();
+
+ public static native void addIORule(String targetPath, String relocatePath);
+
+ public static native void hideXposed();
+
+ private static native void dumpDex(long cookie, String dir);
+
+ public static void dumpDex(ClassLoader classLoader, String packageName) {
+ List cookies = DexFileCompat.getCookies(classLoader);
+ for (Long cookie : cookies) {
+ if (cookie == 0)
+ continue;
+ File file = new File(BlackBoxCore.get().getDexDumpDir(), packageName);
+ FileUtils.mkdirs(file);
+ dumpDex(cookie, file.getAbsolutePath());
+ }
+ }
+
+ @Keep
+ public static int getCallingUid(int origCallingUid) {
+// if (origCallingUid > 0 && origCallingUid < Process.FIRST_APPLICATION_UID)
+// return origCallingUid;
+// // 非用户应用
+// if (origCallingUid > Process.LAST_APPLICATION_UID)
+// return origCallingUid;
+//
+// Log.d(TAG, "origCallingUid: " + origCallingUid + " => " + BClient.getBaseVUid());
+// return BClient.getBaseVUid();
+ return origCallingUid;
+ }
+
+ @Keep
+ public static String redirectPath(String path) {
+ return IOCore.get().redirectPath(path);
+ }
+
+ @Keep
+ public static File redirectPath(File path) {
+ return IOCore.get().redirectPath(path);
+ }
+
+ @Keep
+ public static long[] loadEmptyDex() {
+ try {
+ DexFile dexFile = new DexFile(EMPTY_JAR);
+ List cookies = DexFileCompat.getCookies(dexFile);
+ long[] longs = new long[cookies.size()];
+ for (int i = 0; i < cookies.size(); i++) {
+ longs[i] = cookies.get(i);
+ }
+ return longs;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return new long[]{};
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/env/AppSystemEnv.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/env/AppSystemEnv.java
new file mode 100644
index 00000000..d7962af6
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/env/AppSystemEnv.java
@@ -0,0 +1,68 @@
+package top.niunaijun.blackbox.core.env;
+
+import android.content.ComponentName;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import top.niunaijun.blackbox.BlackBoxCore;
+
+/**
+ * Created by Milk on 4/21/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class AppSystemEnv {
+ private static final List sSystemPackages = new ArrayList<>();
+ private static final List sSuPackages = new ArrayList<>();
+ private static final List sXposedPackages = new ArrayList<>();
+ private static final List sPreInstallPackages = new ArrayList<>();
+
+ static {
+ sSystemPackages.add("android");
+ sSystemPackages.add("com.google.android.webview");
+ sSystemPackages.add("com.google.android.webview.dev");
+ sSystemPackages.add("com.google.android.webview.beta");
+ sSystemPackages.add("com.google.android.webview.canary");
+ sSystemPackages.add("com.android.webview");
+ sSystemPackages.add("com.android.camera");
+ sSystemPackages.add(BlackBoxCore.getHostPkg());
+
+ // 华为
+ sSystemPackages.add("com.huawei.webview");
+
+ // oppo
+ sSystemPackages.add("com.coloros.safecenter");
+
+ // su
+ sSuPackages.add("com.noshufou.android.su");
+ sSuPackages.add("com.noshufou.android.su.elite");
+ sSuPackages.add("eu.chainfire.supersu");
+ sSuPackages.add("com.koushikdutta.superuser");
+ sSuPackages.add("com.thirdparty.superuser");
+ sSuPackages.add("com.yellowes.su");
+
+ sXposedPackages.add("de.robv.android.xposed.installer");
+
+ sPreInstallPackages.add("com.huawei.hwid");
+ }
+
+ public static boolean isOpenPackage(String packageName) {
+ return sSystemPackages.contains(packageName);
+ }
+
+ public static boolean isOpenPackage(ComponentName componentName) {
+ return componentName != null && isOpenPackage(componentName.getPackageName());
+ }
+
+ public static boolean isBlackPackage(String packageName) {
+ return false;
+ }
+
+ public static List getPreInstallPackages() {
+ return sPreInstallPackages;
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/env/BEnvironment.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/env/BEnvironment.java
new file mode 100644
index 00000000..f7dc913e
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/env/BEnvironment.java
@@ -0,0 +1,123 @@
+package top.niunaijun.blackbox.core.env;
+
+import java.io.File;
+import java.util.Locale;
+
+import top.niunaijun.blackbox.BlackBoxCore;
+import top.niunaijun.blackbox.utils.FileUtils;
+
+/**
+ * Created by Milk on 4/22/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class BEnvironment {
+ private static final File sVirtualRoot = new File(BlackBoxCore.getContext().getCacheDir().getParent(), "virtual");
+ private static final File sExternalVirtualRoot = BlackBoxCore.getContext().getExternalFilesDir("virtual");
+
+ public static File JUNIT_JAR = new File(getCacheDir(), "junit.jar");
+ public static File EMPTY_JAR = new File(getCacheDir(), "empty.jar");
+
+ public static void load() {
+ FileUtils.mkdirs(sVirtualRoot);
+ FileUtils.mkdirs(sExternalVirtualRoot);
+ FileUtils.mkdirs(getSystemDir());
+ FileUtils.mkdirs(getCacheDir());
+ }
+
+ public static File getVirtualRoot() {
+ return sVirtualRoot;
+ }
+
+ public static File getExternalVirtualRoot() {
+ return sExternalVirtualRoot;
+ }
+
+ public static File getSystemDir() {
+ return new File(sVirtualRoot, "system");
+ }
+
+ public static File getCacheDir() {
+ return new File(sVirtualRoot, "cache");
+ }
+
+ public static File getUserInfoConf() {
+ return new File(getSystemDir(), "user.conf");
+ }
+
+ public static File getUidConf() {
+ return new File(getSystemDir(), "uid.conf");
+ }
+
+ public static File getXPModuleConf() {
+ return new File(getSystemDir(), "xposed-module.conf");
+ }
+
+ public static File getPackageConf(String packageName) {
+ return new File(getAppDir(packageName), "package.conf");
+ }
+
+ public static File getExternalUserDir(int userId) {
+ return new File(sExternalVirtualRoot, String.format(Locale.CHINA, "storage/emulated/%d/", userId));
+ }
+
+ public static File getUserDir(int userId) {
+ return new File(sVirtualRoot, String.format(Locale.CHINA, "data/user/%d", userId));
+ }
+
+ public static File getDeDataDir(String packageName, int userId) {
+ return new File(sVirtualRoot, String.format(Locale.CHINA, "data/user_de/%d/%s", userId, packageName));
+ }
+
+ public static File getExternalDataDir(String packageName, int userId) {
+ return new File(getExternalUserDir(userId), String.format(Locale.CHINA, "Android/data/%s", packageName));
+ }
+
+
+ public static File getDataDir(String packageName, int userId) {
+ return new File(sVirtualRoot, String.format(Locale.CHINA, "data/user/%d/%s", userId, packageName));
+ }
+
+ public static File getExternalDataFilesDir(String packageName, int userId) {
+ return new File(getExternalDataDir(packageName, userId), "files");
+ }
+
+ public static File getDataFilesDir(String packageName, int userId) {
+ return new File(getDataDir(packageName, userId), "files");
+ }
+
+ public static File getExternalDataCacheDir(String packageName, int userId) {
+ return new File(getExternalDataDir(packageName, userId), "cache");
+ }
+
+ public static File getDataCacheDir(String packageName, int userId) {
+ return new File(getDataDir(packageName, userId), "cache");
+ }
+
+ public static File getDataLibDir(String packageName, int userId) {
+ return new File(getDataDir(packageName, userId), "lib");
+ }
+
+ public static File getDataDatabasesDir(String packageName, int userId) {
+ return new File(getDataDir(packageName, userId), "databases");
+ }
+
+ public static File getAppRootDir() {
+ return getAppDir("");
+ }
+
+ public static File getAppDir(String packageName) {
+ return new File(sVirtualRoot, "data/app/" + packageName);
+ }
+
+ public static File getBaseApkDir(String packageName) {
+ return new File(sVirtualRoot, "data/app/" + packageName + "/base.apk");
+ }
+
+ public static File getAppLibDir(String packageName) {
+ return new File(getAppDir(packageName), "lib");
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BProcessManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BProcessManager.java
new file mode 100644
index 00000000..2229f5fd
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BProcessManager.java
@@ -0,0 +1,293 @@
+package top.niunaijun.blackbox.core.system;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import top.niunaijun.blackbox.BlackBoxCore;
+import top.niunaijun.blackbox.entity.AppConfig;
+import top.niunaijun.blackbox.proxy.ProxyManifest;
+import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
+import top.niunaijun.blackbox.core.system.user.BUserHandle;
+import top.niunaijun.blackbox.utils.Slog;
+import top.niunaijun.blackbox.utils.compat.ApplicationThreadCompat;
+import top.niunaijun.blackbox.utils.compat.BundleCompat;
+import top.niunaijun.blackbox.utils.provider.ProviderCall;
+import top.niunaijun.blackbox.core.IBActivityThread;
+
+/**
+ * Created by Milk on 4/2/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class BProcessManager {
+ public static final String TAG = "BProcessManager";
+
+ public static BProcessManager sVProcessManager = new BProcessManager();
+ private final Map> mProcessMap = new HashMap<>();
+ private final List mPidsSelfLocked = new ArrayList<>();
+ private final Object mProcessLock = new Object();
+
+ public static BProcessManager get() {
+ return sVProcessManager;
+ }
+
+ public ProcessRecord startProcessLocked(String packageName, String processName, int userId, int bpid, int callingUid, int callingPid) {
+ ApplicationInfo info = BPackageManagerService.get().getApplicationInfo(packageName, 0, userId);
+ if (info == null)
+ return null;
+ ProcessRecord app;
+ int buid = BUserHandle.getUid(userId, BPackageManagerService.get().getAppId(packageName));
+ Map vProcess = mProcessMap.get(buid);
+
+ if (vProcess == null) {
+ vProcess = new HashMap<>();
+ }
+ synchronized (mProcessLock) {
+ if (bpid == -1) {
+ app = vProcess.get(processName);
+ if (app != null) {
+ if (app.initLock != null) {
+ app.initLock.block();
+ }
+ if (app.bActivityThread != null) {
+ return app;
+ }
+ }
+ bpid = getUsingBPidL();
+ Slog.d(TAG, "init bUid = " + buid + ", bPid = " + bpid);
+ }
+ if (bpid == -1) {
+ throw new RuntimeException("No processes available");
+ }
+ app = new ProcessRecord(info, processName, 0, bpid, callingUid);
+ app.uid = buid;
+ app.buid = buid;
+ app.userId = userId;
+ app.baseBUid = BUserHandle.getAppId(info.uid);
+
+ vProcess.put(processName, app);
+ mPidsSelfLocked.add(app);
+
+ mProcessMap.put(app.buid, vProcess);
+ if (!initAppProcessL(app)) {
+ //init process fail
+ vProcess.remove(processName);
+ mPidsSelfLocked.remove(app);
+ app = null;
+ } else {
+ app.pid = getPid(BlackBoxCore.getContext(), ProxyManifest.getProcessName(app.bpid));
+ }
+ }
+ return app;
+ }
+
+ private int getUsingBPidL() {
+ ActivityManager manager = (ActivityManager) BlackBoxCore.getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ List runningAppProcesses = manager.getRunningAppProcesses();
+ for (int i = 0; i < ProxyManifest.FREE_COUNT; i++) {
+ boolean using = false;
+ for (ProcessRecord processRecord : mPidsSelfLocked) {
+ if (processRecord.bpid == i) {
+ using = true;
+ break;
+ }
+ }
+ if (using)
+ continue;
+ return i;
+ }
+ return -1;
+ }
+
+ public void restartAppProcess(String packageName, String processName, int userId) {
+ synchronized (mProcessLock) {
+ int callingUid = Binder.getCallingUid();
+ int callingPid = Binder.getCallingPid();
+ ProcessRecord app;
+ synchronized (mProcessLock) {
+ app = findProcessByPid(callingPid);
+ }
+ if (app == null) {
+ String stubProcessName = getProcessName(BlackBoxCore.getContext(), callingPid);
+ int bpid = parseBPid(stubProcessName);
+ startProcessLocked(packageName, processName, userId, bpid, callingUid, callingPid);
+ }
+ }
+ }
+
+ private int parseBPid(String stubProcessName) {
+ String prefix;
+ if (stubProcessName == null) {
+ return -1;
+ } else {
+ prefix = BlackBoxCore.getHostPkg() + ":p";
+ }
+ if (stubProcessName.startsWith(prefix)) {
+ try {
+ return Integer.parseInt(stubProcessName.substring(prefix.length()));
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ }
+ return -1;
+ }
+
+ private boolean initAppProcessL(ProcessRecord record) {
+ Log.d(TAG, "initProcess: " + record.processName);
+ AppConfig appConfig = record.getClientConfig();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(AppConfig.KEY, appConfig);
+ Bundle init = ProviderCall.callSafely(record.getProviderAuthority(), "_Black_|_init_process_", null, bundle);
+ IBinder appThread = BundleCompat.getBinder(init, "_Black_|_client_");
+ if (appThread == null || !appThread.isBinderAlive()) {
+ return false;
+ }
+ attachClientL(record, appThread);
+ return true;
+ }
+
+ private void attachClientL(final ProcessRecord app, final IBinder appThread) {
+ IBActivityThread activityThread = IBActivityThread.Stub.asInterface(appThread);
+ if (activityThread == null) {
+ app.kill();
+ return;
+ }
+ try {
+ appThread.linkToDeath(new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.d(TAG, "App Died: " + app.processName);
+ appThread.unlinkToDeath(this, 0);
+ onProcessDie(app);
+ }
+ }, 0);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ app.bActivityThread = activityThread;
+ try {
+ app.appThread = ApplicationThreadCompat.asInterface(activityThread.getActivityThread());
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ app.initLock.open();
+ }
+
+ public void onProcessDie(ProcessRecord record) {
+ synchronized (mProcessLock) {
+ record.kill();
+ Map remove = mProcessMap.remove(record.buid);
+ if (remove != null)
+ remove.remove(record.processName);
+ mPidsSelfLocked.remove(record);
+ }
+ }
+
+ public ProcessRecord findProcessRecord(String packageName, String processName, int userId) {
+ synchronized (mProcessLock) {
+ int appId = BPackageManagerService.get().getAppId(packageName);
+ int buid = BUserHandle.getUid(userId, appId);
+ Map processRecordMap = mProcessMap.get(buid);
+ if (processRecordMap == null)
+ return null;
+ return processRecordMap.get(processName);
+ }
+ }
+
+ public void killAllByPackageName(String packageName) {
+ synchronized (mProcessLock) {
+ synchronized (mPidsSelfLocked) {
+ List tmp = new ArrayList<>(mPidsSelfLocked);
+ int appId = BPackageManagerService.get().getAppId(packageName);
+ for (ProcessRecord processRecord : mPidsSelfLocked) {
+ int appId1 = BUserHandle.getAppId(processRecord.buid);
+ if (appId == appId1) {
+ mProcessMap.remove(processRecord.buid);
+ tmp.remove(processRecord);
+ processRecord.kill();
+ }
+ }
+ mPidsSelfLocked.clear();
+ mPidsSelfLocked.addAll(tmp);
+ }
+ }
+ }
+
+ public void killPackageAsUser(String packageName, int userId) {
+ synchronized (mProcessLock) {
+ int buid = BUserHandle.getUid(userId, BPackageManagerService.get().getAppId(packageName));
+ Map process = mProcessMap.get(buid);
+ if (process == null)
+ return;
+ for (ProcessRecord value : process.values()) {
+ value.kill();
+ }
+ mProcessMap.remove(buid);
+ }
+ }
+
+
+ public int getUserIdByCallingPid(int callingPid) {
+ synchronized (mProcessLock) {
+ ProcessRecord callingProcess = BProcessManager.get().findProcessByPid(callingPid);
+ if (callingProcess == null) {
+ return 0;
+ }
+ return callingProcess.userId;
+ }
+ }
+
+ public ProcessRecord findProcessByPid(int pid) {
+ synchronized (mPidsSelfLocked) {
+ for (ProcessRecord processRecord : mPidsSelfLocked) {
+ if (processRecord.pid == pid)
+ return processRecord;
+ }
+ return null;
+ }
+ }
+
+ private static String getProcessName(Context context, int pid) {
+ String processName = null;
+ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ for (ActivityManager.RunningAppProcessInfo info : am.getRunningAppProcesses()) {
+ if (info.pid == pid) {
+ processName = info.processName;
+ break;
+ }
+ }
+ if (processName == null) {
+ throw new RuntimeException("processName = null");
+ }
+ return processName;
+ }
+
+ public static int getPid(Context context, String processName) {
+ try {
+ ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ List runningAppProcesses = manager.getRunningAppProcesses();
+ for (ActivityManager.RunningAppProcessInfo runningAppProcess : runningAppProcesses) {
+ if (runningAppProcess.processName.equals(processName)) {
+ return runningAppProcess.pid;
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return -1;
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BlackBoxSystem.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BlackBoxSystem.java
new file mode 100644
index 00000000..0046105b
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BlackBoxSystem.java
@@ -0,0 +1,80 @@
+package top.niunaijun.blackbox.core.system;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import top.niunaijun.blackbox.core.env.BEnvironment;
+import top.niunaijun.blackbox.BlackBoxCore;
+import top.niunaijun.blackbox.core.env.AppSystemEnv;
+import top.niunaijun.blackbox.entity.pm.InstallOption;
+import top.niunaijun.blackbox.core.system.am.BActivityManagerService;
+import top.niunaijun.blackbox.core.system.os.BStorageManagerService;
+import top.niunaijun.blackbox.core.system.pm.BPackageInstallerService;
+import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
+import top.niunaijun.blackbox.core.system.user.BUserHandle;
+import top.niunaijun.blackbox.core.system.user.BUserManagerService;
+import top.niunaijun.blackbox.utils.FileUtils;
+
+import static top.niunaijun.blackbox.core.env.BEnvironment.EMPTY_JAR;
+import static top.niunaijun.blackbox.core.env.BEnvironment.JUNIT_JAR;
+
+/**
+ * Created by Milk on 4/22/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class BlackBoxSystem {
+ private static BlackBoxSystem sBlackBoxSystem;
+
+ public static BlackBoxSystem getSystem() {
+ if (sBlackBoxSystem == null) {
+ synchronized (BlackBoxSystem.class) {
+ if (sBlackBoxSystem == null) {
+ sBlackBoxSystem = new BlackBoxSystem();
+ }
+ }
+ }
+ return sBlackBoxSystem;
+ }
+
+ public void startup() {
+ BEnvironment.load();
+
+ BPackageManagerService.get().systemReady();
+ BUserManagerService.get().systemReady();
+ BActivityManagerService.get().systemReady();
+ BStorageManagerService.get().systemReady();
+ BPackageInstallerService.get().systemReady();
+
+ List preInstallPackages = AppSystemEnv.getPreInstallPackages();
+ for (String preInstallPackage : preInstallPackages) {
+ try {
+ if (!BPackageManagerService.get().isInstalled(preInstallPackage, BUserHandle.USER_ALL)) {
+ PackageInfo packageInfo = BlackBoxCore.getPackageManager().getPackageInfo(preInstallPackage, 0);
+ BPackageManagerService.get().installPackageAsUser(packageInfo.applicationInfo.sourceDir, InstallOption.installBySystem(), BUserHandle.USER_ALL);
+ }
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
+ }
+ initJarEnv();
+ }
+
+ private void initJarEnv() {
+ try {
+ InputStream junit = BlackBoxCore.getContext().getAssets().open("junit.jar");
+ FileUtils.copyFile(junit, JUNIT_JAR);
+
+ InputStream empty = BlackBoxCore.getContext().getAssets().open("empty.jar");
+ FileUtils.copyFile(empty, EMPTY_JAR);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/DaemonService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/DaemonService.java
new file mode 100644
index 00000000..9fceb06c
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/DaemonService.java
@@ -0,0 +1,106 @@
+package top.niunaijun.blackbox.core.system;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.core.app.NotificationCompat;
+
+import top.niunaijun.blackbox.R;
+import top.niunaijun.blackbox.utils.compat.BuildCompat;
+
+
+/**
+ * Created by Milk on 3/2/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class DaemonService extends Service {
+ public static final String TAG = "DaemonService";
+ private static final int NOTIFY_ID = (int) (System.currentTimeMillis() / 1000);
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ initNotificationManager();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Intent innerIntent = new Intent(this, DaemonInnerService.class);
+ startService(innerIntent);
+ if (BuildCompat.isOreo()) {
+ showNotification();
+ }
+ return START_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d(TAG, "onDestroy");
+ }
+
+ private void showNotification() {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), getPackageName() + ".blackbox")
+ .setPriority(NotificationCompat.PRIORITY_MAX);
+ startForeground(NOTIFY_ID, builder.build());
+ }
+
+ private void initNotificationManager() {
+ NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ String CHANNEL_ONE_ID = getPackageName() + ".blackbox";
+ String CHANNEL_ONE_NAME = "blackbox";
+ if (BuildCompat.isOreo()) {
+ NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
+ CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_HIGH);
+ notificationChannel.enableLights(true);
+ notificationChannel.setLightColor(Color.RED);
+ notificationChannel.setShowBadge(true);
+ notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
+ nm.createNotificationChannel(notificationChannel);
+ }
+ }
+
+ public static class DaemonInnerService extends Service {
+ @Override
+ public void onCreate() {
+ Log.i(TAG, "DaemonInnerService -> onCreate");
+ super.onCreate();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.i(TAG, "DaemonInnerService -> onStartCommand");
+ NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ nm.cancel(NOTIFY_ID);
+ stopSelf();
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.i(TAG, "DaemonInnerService -> onDestroy");
+ super.onDestroy();
+ }
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ISystemService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ISystemService.java
new file mode 100644
index 00000000..7149f555
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ISystemService.java
@@ -0,0 +1,13 @@
+package top.niunaijun.blackbox.core.system;
+
+/**
+ * Created by Milk on 4/22/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public interface ISystemService {
+ void systemReady();
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ProcessRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ProcessRecord.java
new file mode 100644
index 00000000..5d9a1d74
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ProcessRecord.java
@@ -0,0 +1,138 @@
+package top.niunaijun.blackbox.core.system;
+
+import android.content.pm.ApplicationInfo;
+import android.os.Binder;
+import android.os.ConditionVariable;
+
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Process;
+import android.text.TextUtils;
+
+import java.util.Arrays;
+
+import top.niunaijun.blackbox.entity.AppConfig;
+import top.niunaijun.blackbox.core.IBActivityThread;
+import top.niunaijun.blackbox.proxy.ProxyManifest;
+
+public class ProcessRecord extends Binder implements Parcelable {
+ public final ApplicationInfo info;
+ final public String processName;
+ public IBActivityThread bActivityThread;
+ public IInterface appThread;
+ public int pid;
+ public int uid;
+ public int buid;
+ public int bpid;
+ public int callingVUid;
+ public int userId;
+ public int baseBUid;
+
+ public ConditionVariable initLock = new ConditionVariable();
+
+ public ProcessRecord(ApplicationInfo info, String processName, int buid, int bpid, int callingVUid) {
+ this.info = info;
+ this.buid = buid;
+ this.bpid = bpid;
+ this.userId = 0;
+ this.callingVUid = callingVUid;
+ this.processName = processName;
+ }
+
+ public int getCallingBUid() {
+ return callingVUid;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ProcessRecord that = (ProcessRecord) o;
+ return pid == that.pid &&
+ buid == that.buid &&
+ bpid == that.bpid &&
+ uid == that.uid &&
+ userId == that.userId &&
+ baseBUid == that.baseBUid &&
+ TextUtils.equals(processName, that.processName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(new Object[]{processName, pid, buid, bpid, uid, pid, userId});
+ }
+
+ public String getProviderAuthority() {
+ return ProxyManifest.getProxyAuthorities(bpid);
+ }
+
+ public AppConfig getClientConfig() {
+ AppConfig config = new AppConfig();
+ config.packageName = info.packageName;
+ config.processName = processName;
+ config.bpid = bpid;
+ config.buid = buid;
+ config.uid = uid;
+ config.userId = userId;
+ config.token = this;
+ config.baseBUid = baseBUid;
+ return config;
+ }
+
+ public void kill() {
+ if (pid > 0) {
+ try {
+ Process.killProcess(pid);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public String getPackageName() {
+ return info.packageName;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(this.info, flags);
+ dest.writeString(this.processName);
+ dest.writeInt(this.pid);
+ dest.writeInt(this.buid);
+ dest.writeInt(this.bpid);
+ dest.writeInt(this.uid);
+ dest.writeInt(this.callingVUid);
+ dest.writeInt(this.userId);
+ dest.writeInt(this.baseBUid);
+ }
+
+ protected ProcessRecord(Parcel in) {
+ this.info = in.readParcelable(ApplicationInfo.class.getClassLoader());
+ this.processName = in.readString();
+ this.pid = in.readInt();
+ this.buid = in.readInt();
+ this.bpid = in.readInt();
+ this.uid = in.readInt();
+ this.callingVUid = in.readInt();
+ this.userId = in.readInt();
+ this.baseBUid = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public ProcessRecord createFromParcel(Parcel source) {
+ return new ProcessRecord(source);
+ }
+
+ @Override
+ public ProcessRecord[] newArray(int size) {
+ return new ProcessRecord[size];
+ }
+ };
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ServiceManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ServiceManager.java
new file mode 100644
index 00000000..5b7c50bc
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ServiceManager.java
@@ -0,0 +1,56 @@
+package top.niunaijun.blackbox.core.system;
+
+import android.os.IBinder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import top.niunaijun.blackbox.core.system.am.BActivityManagerService;
+import top.niunaijun.blackbox.core.system.os.BStorageManagerService;
+import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
+import top.niunaijun.blackbox.core.system.user.BUserManagerService;
+
+/**
+ * Created by Milk on 3/31/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ServiceManager {
+ private static ServiceManager sServiceManager = null;
+ public static final String ACTIVITY_MANAGER = "activity_manager";
+ public static final String PACKAGE_MANAGER = "package_manager";
+ public static final String STORAGE_MANAGER = "storage_manager";
+ public static final String USER_MANAGER = "user_manager";
+ public static final String Xposed_MANAGER = "Xposed_manager";
+
+ private final Map mCaches = new HashMap<>();
+
+ public static ServiceManager get() {
+ if (sServiceManager == null) {
+ synchronized (ServiceManager.class) {
+ if (sServiceManager == null) {
+ sServiceManager = new ServiceManager();
+ }
+ }
+ }
+ return sServiceManager;
+ }
+
+ public static IBinder getService(String name) {
+ return get().getServiceInternal(name);
+ }
+
+ private ServiceManager() {
+ mCaches.put(ACTIVITY_MANAGER, BActivityManagerService.get());
+ mCaches.put(PACKAGE_MANAGER, BPackageManagerService.get());
+ mCaches.put(STORAGE_MANAGER, BStorageManagerService.get());
+ mCaches.put(USER_MANAGER, BUserManagerService.get());
+ }
+
+ public IBinder getServiceInternal(String name) {
+ return mCaches.get(name);
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/SystemCallProvider.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/SystemCallProvider.java
new file mode 100644
index 00000000..54859f06
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/SystemCallProvider.java
@@ -0,0 +1,74 @@
+package top.niunaijun.blackbox.core.system;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import top.niunaijun.blackbox.utils.compat.BundleCompat;
+
+/**
+ * Created by Milk on 3/31/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class SystemCallProvider extends ContentProvider {
+ @Override
+ public boolean onCreate() {
+ return initSystem();
+ }
+
+ private boolean initSystem() {
+ BlackBoxSystem.getSystem().startup();
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
+ if (method.equals("VM")) {
+ Bundle bundle = new Bundle();
+ if (extras != null) {
+ String name = extras.getString("_VM_|_server_name_");
+ BundleCompat.putBinder(bundle, "_VM_|_server_", ServiceManager.getService(name));
+ }
+ return bundle;
+ }
+ return super.call(method, arg, extras);
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActiveServices.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActiveServices.java
new file mode 100644
index 00000000..dc1bf5ee
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActiveServices.java
@@ -0,0 +1,114 @@
+package top.niunaijun.blackbox.core.system.am;
+
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
+
+/**
+ * Created by Milk on 4/7/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ActiveServices {
+ public static final String TAG = "ActiveServices";
+
+ private final Map mRunningServiceRecords = new HashMap<>();
+ private final Map mConnectedServices = new HashMap<>();
+
+ public void startService(Intent intent, String resolvedType, int userId) {
+
+ }
+
+ public int stopService(Intent intent, String resolvedType, int userId) {
+// ResolveInfo resolveInfo = resolveService(intent, resolvedType, userId);
+ synchronized (mRunningServiceRecords) {
+ RunningServiceRecord runningServiceRecord = findRunningServiceRecord(intent);
+ if (runningServiceRecord == null) {
+ return 0;
+ }
+ if (runningServiceRecord.mBindCount.get() > 0) {
+ Log.d(TAG, "There are also connections");
+ return 0;
+ }
+
+ runningServiceRecord.mStartId.set(0);
+ }
+ return 0;
+ }
+
+ public void unbindService(IBinder binder, int userId) {
+ ConnectedServiceRecord connectedService = mConnectedServices.get(binder);
+ if (connectedService == null) {
+ return;
+ }
+ RunningServiceRecord runningServiceRecord = getOrCreateRunningServiceRecord(connectedService.mIntent);
+ runningServiceRecord.mConnectedServiceRecord = null;
+ runningServiceRecord.mBindCount.decrementAndGet();
+ mConnectedServices.remove(binder);
+ }
+
+ public void onStartCommand(Intent proxyIntent, int userId) {
+ }
+
+ public void onServiceDestroy(Intent proxyIntent, int userId) {
+ }
+
+ private RunningServiceRecord getOrCreateRunningServiceRecord(Intent intent) {
+ RunningServiceRecord runningServiceRecord = findRunningServiceRecord(intent);
+ if (runningServiceRecord == null) {
+ runningServiceRecord = new RunningServiceRecord();
+ mRunningServiceRecords.put(new Intent.FilterComparison(intent), runningServiceRecord);
+ }
+ return runningServiceRecord;
+ }
+
+ private RunningServiceRecord findRunningServiceRecord(Intent intent) {
+ return mRunningServiceRecords.get(new Intent.FilterComparison(intent));
+ }
+
+ private ResolveInfo resolveService(Intent intent, String resolvedType, int userId) {
+ return BPackageManagerService.get().resolveService(intent, 0, resolvedType, userId);
+ }
+
+ private ConnectedServiceRecord findConnectedServiceRecord(Intent intent) {
+ RunningServiceRecord runningServiceRecord = mRunningServiceRecords.get(intent);
+ if (runningServiceRecord == null)
+ return null;
+ return runningServiceRecord.mConnectedServiceRecord;
+ }
+
+ public static class RunningServiceRecord {
+ // onStartCommand startId
+ private AtomicInteger mStartId = new AtomicInteger(1);
+ private AtomicInteger mBindCount = new AtomicInteger(0);
+ // 正在连接的服务
+ private ConnectedServiceRecord mConnectedServiceRecord;
+
+ public int getAndIncrementStartId() {
+ return mStartId.getAndIncrement();
+ }
+
+ public int decrementBindCountAndGet() {
+ return mBindCount.decrementAndGet();
+ }
+
+ public int incrementBindCountAndGet() {
+ return mBindCount.incrementAndGet();
+ }
+ }
+
+ public static class ConnectedServiceRecord {
+ private IBinder mIBinder;
+ private Intent mIntent;
+ }
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActivityRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActivityRecord.java
new file mode 100644
index 00000000..7d3e880d
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActivityRecord.java
@@ -0,0 +1,42 @@
+package top.niunaijun.blackbox.core.system.am;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.Binder;
+import android.os.IBinder;
+
+import top.niunaijun.blackbox.core.system.ProcessRecord;
+
+
+/**
+ * Created by Milk on 4/9/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ActivityRecord extends Binder {
+ public TaskRecord task;
+ public IBinder token;
+ public IBinder resultTo;
+ public ActivityInfo info;
+ public ComponentName component;
+ public Intent intent;
+ public int userId;
+ public boolean finished;
+ public ProcessRecord processRecord;
+
+ public static ActivityRecord create(Intent intent, ActivityInfo info, IBinder resultTo, int userId) {
+ ActivityRecord record = new ActivityRecord();
+ record.intent = intent;
+ record.info = info;
+ record.component = new ComponentName(info.packageName, info.name);
+ record.resultTo = resultTo;
+ record.userId = userId;
+ return record;
+ }
+
+
+}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActivityStack.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActivityStack.java
new file mode 100644
index 00000000..5b1cd825
--- /dev/null
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/ActivityStack.java
@@ -0,0 +1,468 @@
+package top.niunaijun.blackbox.core.system.am;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Process;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import mirror.android.app.ActivityManagerNative;
+import mirror.android.app.IActivityManager;
+import top.niunaijun.blackbox.BlackBoxCore;
+import top.niunaijun.blackbox.proxy.ProxyManifest;
+import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
+import top.niunaijun.blackbox.utils.ComponentUtils;
+import top.niunaijun.blackbox.proxy.record.ProxyActivityRecord;
+import top.niunaijun.blackbox.core.system.ProcessRecord;
+import top.niunaijun.blackbox.core.system.BProcessManager;
+
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
+
+/**
+ * Created by Milk on 4/5/21.
+ * * ∧_∧
+ * (`・ω・∥
+ * 丶 つ0
+ * しーJ
+ * 此处无Bug
+ */
+public class ActivityStack {
+ private ActivityManager mAms;
+ private final Map mTasks = new LinkedHashMap<>();
+ private final Set mLaunchingActivities = new HashSet<>();
+
+ public ActivityStack() {
+ mAms = (ActivityManager) BlackBoxCore.getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ }
+
+ public boolean containsFlag(Intent intent, int flag) {
+ return (intent.getFlags() & flag) != 0;
+ }
+
+ public int startActivitiesLocked(int userId, Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle options) {
+ if (intents == null) {
+ throw new NullPointerException("intents is null");
+ }
+ if (resolvedTypes == null) {
+ throw new NullPointerException("resolvedTypes is null");
+ }
+ if (intents.length != resolvedTypes.length) {
+ throw new IllegalArgumentException("intents are length different than resolvedTypes");
+ }
+ for (int i = 0; i < intents.length; i++) {
+ startActivityLocked(userId, intents[i], resolvedTypes[i], resultTo, null, -1, 0, options);
+ }
+ return 0;
+ }
+
+ public int startActivityLocked(int userId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, Bundle options) {
+ synchronized (mTasks) {
+ synchronizeTasks();
+ }
+
+ ResolveInfo resolveInfo = BPackageManagerService.get().resolveActivity(intent, GET_ACTIVITIES, resolvedType, userId);
+ if (resolveInfo == null || resolveInfo.activityInfo == null) {
+ return 0;
+ }
+ Log.d("TestActivity", "startActivityLocked : " + intent.getComponent().toString());
+ ActivityInfo activityInfo = resolveInfo.activityInfo;
+
+ ActivityRecord sourceRecord = findActivityRecordByToken(userId, resultTo);
+ if (sourceRecord == null) {
+ resultTo = null;
+ }
+ TaskRecord sourceTask = null;
+ if (sourceRecord != null) {
+ sourceTask = sourceRecord.task;
+ }
+
+ String taskAffinity = ComponentUtils.getTaskAffinity(activityInfo);
+
+ int launchModeFlags = 0;
+ boolean singleTop = containsFlag(intent, Intent.FLAG_ACTIVITY_SINGLE_TOP) || activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
+ boolean newTask = containsFlag(intent, Intent.FLAG_ACTIVITY_NEW_TASK);
+ boolean clearTop = containsFlag(intent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ boolean clearTask = containsFlag(intent, Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ TaskRecord taskRecord = null;
+ switch (activityInfo.launchMode) {
+ case ActivityInfo.LAUNCH_SINGLE_TOP:
+ case ActivityInfo.LAUNCH_MULTIPLE:
+ case ActivityInfo.LAUNCH_SINGLE_TASK:
+ taskRecord = findTaskRecordByTaskAffinityLocked(userId, taskAffinity);
+ if (taskRecord == null && !newTask) {
+ taskRecord = sourceTask;
+ }
+ break;
+ case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
+ taskRecord = findTaskRecordByTaskAffinityLocked(userId, taskAffinity);
+ break;
+ }
+
+ // 如果还没有task则新启动一个task
+ if (taskRecord == null || taskRecord.needNewTask()) {
+ return startActivityInNewTaskLocked(userId, intent, activityInfo, resultTo, launchModeFlags);
+ }
+ // 移至前台
+ mAms.moveTaskToFront(taskRecord.id, 0);
+
+ boolean notStartToFront = false;
+ if (clearTop || singleTop || clearTask) {
+ notStartToFront = true;
+ }
+
+ boolean startTaskToFront = !notStartToFront
+ && ComponentUtils.intentFilterEquals(taskRecord.rootIntent, intent)
+ && taskRecord.rootIntent.getFlags() == intent.getFlags();
+
+ if (startTaskToFront)
+ return 0;
+
+ ActivityRecord topActivityRecord = taskRecord.getTopActivityRecord();
+ ActivityRecord targetActivityRecord = findActivityRecordByComponentName(userId, ComponentUtils.toComponentName(activityInfo));
+ ActivityRecord newIntentRecord = null;
+ boolean ignore = false;
+
+ if (clearTop) {
+ if (targetActivityRecord != null) {
+ // 目标栈上面所有activity出栈
+ synchronized (targetActivityRecord.task.activities) {
+ for (int i = targetActivityRecord.task.activities.size() - 1; i >= 0; i--) {
+ ActivityRecord next = targetActivityRecord.task.activities.get(i);
+ if (next != targetActivityRecord) {
+ next.finished = true;
+ Log.d("TestActivity", "makerFinish: " + next.component.toString());
+ } else {
+ if (singleTop) {
+ newIntentRecord = targetActivityRecord;
+ } else {
+ // clearTop并且不是singleTop,目标也finish,重建。
+ targetActivityRecord.finished = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (singleTop && !clearTop) {
+ if (ComponentUtils.intentFilterEquals(topActivityRecord.intent, intent)) {
+ newIntentRecord = topActivityRecord;
+ } else {
+ synchronized (mLaunchingActivities) {
+ for (ActivityRecord launchingActivity : mLaunchingActivities) {
+ if (!launchingActivity.finished && launchingActivity.component.equals(intent.getComponent())) {
+ // todo update onNewIntent from intent
+ ignore = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK && !clearTop) {
+ if (ComponentUtils.intentFilterEquals(topActivityRecord.intent, intent)) {
+ newIntentRecord = topActivityRecord;
+ } else {
+ ActivityRecord record = findActivityRecordByComponentName(userId, ComponentUtils.toComponentName(activityInfo));
+ if (record != null) {
+ // 需要调用目标onNewIntent
+ newIntentRecord = record;
+ // 目标栈上面所有activity出栈
+ synchronized (taskRecord.activities) {
+ for (int i = taskRecord.activities.size() - 1; i >= 0; i--) {
+ ActivityRecord next = taskRecord.activities.get(i);
+ if (next != record) {
+ next.finished = true;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
+ newIntentRecord = topActivityRecord;
+ }
+
+ // clearTask finish All
+ if (clearTask && newTask) {
+ for (ActivityRecord activity : taskRecord.activities) {
+ activity.finished = true;
+ }
+ }
+
+ finishAllActivity(userId);
+
+ if (newIntentRecord != null) {
+ // 通知onNewIntent
+ deliverNewIntentLocked(newIntentRecord, intent);
+ return 0;
+ } else if (ignore) {
+ return 0;
+ }
+
+ if (resultTo == null) {
+ ActivityRecord top = taskRecord.getTopActivityRecord();
+ if (top != null) {
+ resultTo = top.token;
+ }
+ } else if (sourceTask != null) {
+ ActivityRecord top = sourceTask.getTopActivityRecord();
+ if (top != null) {
+ resultTo = top.token;
+ }
+ }
+ return startActivityInSourceTask(intent,
+ resolvedType, resultTo, resultWho, requestCode, flags, options, userId, topActivityRecord, activityInfo, launchModeFlags);
+ }
+
+ private void deliverNewIntentLocked(ActivityRecord activityRecord, Intent intent) {
+
+ }
+
+ private Intent startActivityProcess(int userId, Intent intent, ActivityInfo
+ info, ActivityRecord record, int callingUid) {
+ ProxyActivityRecord stubRecord = new ProxyActivityRecord(userId, info, intent, record);
+ ProcessRecord targetApp = BProcessManager.get().startProcessLocked(info.packageName, info.processName, userId, -1, Binder.getCallingUid(), Binder.getCallingPid());
+ if (targetApp == null) {
+ throw new RuntimeException("Unable to create process, name:" + info.name);
+ }
+ return getStartStubActivityIntentInner(intent, targetApp.bpid, userId, stubRecord, info);
+ }
+
+ private int startActivityInNewTaskLocked(int userId, Intent intent, ActivityInfo
+ activityInfo, IBinder resultTo, int launchMode) {
+ ActivityRecord record = newActivityRecord(intent, activityInfo, resultTo, userId);
+ Intent shadow = startActivityProcess(userId, intent, activityInfo, record, Process.myUid());
+
+ shadow.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ shadow.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ shadow.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ shadow.addFlags(launchMode);
+
+ BlackBoxCore.getContext().startActivity(shadow);
+ return 0;
+ }
+
+ private int startActivityInSourceTask(Intent intent, String resolvedType,
+ IBinder resultTo, String resultWho, int requestCode, int flags,
+ Bundle options,
+ int userId, ActivityRecord sourceRecord, ActivityInfo activityInfo, int launchMode) {
+ ActivityRecord selfRecord = newActivityRecord(intent, activityInfo, resultTo, userId);
+ Intent shadow = startActivityProcess(userId, intent, activityInfo, selfRecord, Process.myUid());
+ shadow.addFlags(launchMode);
+ return realStartActivityLocked(sourceRecord.processRecord.appThread, shadow, resolvedType, resultTo, resultWho, requestCode, flags, options);
+ }
+
+ private int realStartActivityLocked(IInterface appThread, Intent intent, String
+ resolvedType,
+ IBinder resultTo, String resultWho, int requestCode, int flags,
+ Bundle options) {
+ Class>[] classes = IActivityManager.startActivity.unwrap().getParameterTypes();
+ Object[] args = new Object[classes.length];
+
+ int index = 0;
+ args[index++] = appThread;
+ args[index++] = BlackBoxCore.getHostPkg();
+ args[index++] = intent;
+ args[index++] = resolvedType;
+ args[index++] = resultTo;
+ args[index++] = resultWho;
+ args[index++] = requestCode;
+ args[index++] = flags;
+ args[index++] = null;
+ args[index++] = options;
+
+ try {
+ IActivityManager.startActivity.call(ActivityManagerNative.getDefault.call(), args);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return 0;
+ }
+
+ private ActivityRecord getTopActivityRecord() {
+ synchronized (mTasks) {
+ synchronizeTasks();
+ }
+ List