periodicSyncTimes;
private static final String TAG = "Sync";
@@ -129,8 +129,8 @@ public class SyncStatusInfo implements Parcelable {
}
public void setPeriodicSyncTime(int index, long when) {
- // The list is initialized lazily when scheduling occurs so we need to make sure
- // we initialize elements < index to zero (zero is ignore for scheduling purposes)
+
+
ensurePeriodicSyncTimeSize(index);
periodicSyncTimes.set(index, when);
}
diff --git a/Bcore/src/main/java/android/content/pm/ManifestDigest.java b/Bcore/src/main/java/android/content/pm/ManifestDigest.java
index 92c6a4b..1a71dcc 100644
--- a/Bcore/src/main/java/android/content/pm/ManifestDigest.java
+++ b/Bcore/src/main/java/android/content/pm/ManifestDigest.java
@@ -5,14 +5,7 @@ import android.os.Parcelable;
import java.util.jar.Attributes;
-/**
- * updated by alex5402 on 2021/5/7.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ManifestDigest implements Parcelable {
ManifestDigest(final byte[] digest) {
diff --git a/Bcore/src/main/java/android/content/pm/PackageParser.java b/Bcore/src/main/java/android/content/pm/PackageParser.java
index 271f272..340dace 100644
--- a/Bcore/src/main/java/android/content/pm/PackageParser.java
+++ b/Bcore/src/main/java/android/content/pm/PackageParser.java
@@ -90,24 +90,20 @@ public class PackageParser {
public final int installLocation;
public final VerifierInfo[] verifiers;
- /** Names of any split APKs, ordered by parsed splitName */
+
public final String[] splitNames;
- /**
- * 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 final String codePath;
- /** Path of base APK */
+
public final String baseCodePath;
- /** Paths of any split APKs, ordered by parsed splitName */
+
public final String[] splitCodePaths;
- /** Revision code of base APK */
+
public final int baseRevisionCode;
- /** Revision codes of any split APKs, ordered by parsed splitName */
+
public final int[] splitRevisionCodes;
public final boolean coreApp;
@@ -141,9 +137,7 @@ public class PackageParser {
}
}
- /**
- * For Android 5.0+
- */
+
public PackageParser() {
throw new RuntimeException("Stub!");
}
@@ -180,49 +174,17 @@ public class PackageParser {
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!");
}
@@ -235,63 +197,45 @@ public class PackageParser {
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 ApplicationInfo applicationInfo = new ApplicationInfo();
public final ArrayList permissions = new ArrayList(0);
@@ -317,92 +261,80 @@ public class PackageParser {
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) {
@@ -413,10 +345,7 @@ public class PackageParser {
throw new RuntimeException("Stub!");
}
- /**
- * Filtered set of {@link #getAllCodePaths()} that excludes
- * resource-only APKs.
- */
+
public List getAllCodePathsExcludingResourceOnly() {
throw new RuntimeException("Stub!");
}
diff --git a/Bcore/src/main/java/android/content/pm/PackageUserState.java b/Bcore/src/main/java/android/content/pm/PackageUserState.java
index 31938ef..8aa6520 100644
--- a/Bcore/src/main/java/android/content/pm/PackageUserState.java
+++ b/Bcore/src/main/java/android/content/pm/PackageUserState.java
@@ -2,20 +2,13 @@ package android.content.pm;
import android.util.ArraySet;
-/**
- * updated by alex5402 on 2021/5/7.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class PackageUserState {
public boolean stopped;
public boolean notLaunched;
public boolean installed;
- public boolean hidden; // Is the app restricted by owner / admin
+ public boolean hidden;
public int enabled;
public boolean blockUninstall;
diff --git a/Bcore/src/main/java/android/content/pm/VerifierInfo.java b/Bcore/src/main/java/android/content/pm/VerifierInfo.java
index 8df305b..192b090 100644
--- a/Bcore/src/main/java/android/content/pm/VerifierInfo.java
+++ b/Bcore/src/main/java/android/content/pm/VerifierInfo.java
@@ -5,14 +5,7 @@ import android.os.Parcelable;
import java.security.PublicKey;
-/**
- * updated by alex5402 on 2021/5/7.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class VerifierInfo implements Parcelable {
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
diff --git a/Bcore/src/main/java/android/os/ParcelableException.java b/Bcore/src/main/java/android/os/ParcelableException.java
index 52830cb..416a078 100644
--- a/Bcore/src/main/java/android/os/ParcelableException.java
+++ b/Bcore/src/main/java/android/os/ParcelableException.java
@@ -4,20 +4,7 @@ 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) {
diff --git a/Bcore/src/main/java/black/android/app/ActivityClient.java b/Bcore/src/main/java/black/android/app/ActivityClient.java
index 8de3b4d..4c3af67 100644
--- a/Bcore/src/main/java/black/android/app/ActivityClient.java
+++ b/Bcore/src/main/java/black/android/app/ActivityClient.java
@@ -6,9 +6,7 @@ import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
-/**
- * Created by BlackBox on 2022/2/22.
- */
+
@BClassName("android.app.ActivityClient")
public interface ActivityClient {
@BField
diff --git a/Bcore/src/main/java/black/android/content/AttributionSource.java b/Bcore/src/main/java/black/android/content/AttributionSource.java
index 9dd7311..13f3096 100644
--- a/Bcore/src/main/java/black/android/content/AttributionSource.java
+++ b/Bcore/src/main/java/black/android/content/AttributionSource.java
@@ -4,9 +4,7 @@ import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
import top.niunaijun.blackreflection.annotation.BMethod;
-/**
- * Created by BlackBox on 2022/2/20.
- */
+
@BClassName("android.content.AttributionSource")
public interface AttributionSource {
@BField
diff --git a/Bcore/src/main/java/black/android/content/AttributionSourceState.java b/Bcore/src/main/java/black/android/content/AttributionSourceState.java
index 8aad81e..fcf2b22 100644
--- a/Bcore/src/main/java/black/android/content/AttributionSourceState.java
+++ b/Bcore/src/main/java/black/android/content/AttributionSourceState.java
@@ -3,9 +3,7 @@ package black.android.content;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
-/**
- * Created by BlackBox on 2022/2/20.
- */
+
@BClassName("android.content.AttributionSourceState")
public interface AttributionSourceState {
@BField
diff --git a/Bcore/src/main/java/black/android/content/pm/PackageParser.java b/Bcore/src/main/java/black/android/content/pm/PackageParser.java
index d7f079d..777e888 100644
--- a/Bcore/src/main/java/black/android/content/pm/PackageParser.java
+++ b/Bcore/src/main/java/black/android/content/pm/PackageParser.java
@@ -23,20 +23,20 @@ public interface PackageParser {
@BConstructor
android.content.pm.PackageParser _new(String String0);
-// @BStaticMethod
-// ActivityInfo generateActivityInfo();
-//
-// @BStaticMethod
-// ApplicationInfo generateApplicationInfo();
-//
-// @BStaticMethod
-// PackageInfo generatePackageInfo();
-//
-// @BStaticMethod
-// ProviderInfo generateProviderInfo();
-//
-// @BStaticMethod
-// ServiceInfo generateServiceInfo();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@BMethod
void collectCertificates(android.content.pm.PackageParser.Package p, int flags);
diff --git a/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop.java b/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop.java
index ca5283f..b1586e5 100644
--- a/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop.java
+++ b/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop.java
@@ -13,20 +13,20 @@ public interface PackageParserLollipop {
@BConstructor
android.content.pm.PackageParser _new();
-// @BStaticMethod
-// ActivityInfo generateActivityInfo(PackageParser.Activity service, int flag, PackageUserState state, int userId);
-//
-// @BStaticMethod
-// ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state);
-//
-// @BStaticMethod
-// PackageInfo generatePackageInfo(Package p, int[] ints, int int1, long long1, long );
-//
-// @BStaticMethod
-// ProviderInfo generateProviderInfo(PackageParser.Provider service, int flag, PackageUserState state, int userId);
-//
-// @BStaticMethod
-// ServiceInfo generateServiceInfo(PackageParser.Service service, int flag, PackageUserState state, int userId);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@BMethod
void collectCertificates(Package p, int flags);
diff --git a/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop22.java b/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop22.java
index 83cf1aa..898bc7b 100644
--- a/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop22.java
+++ b/Bcore/src/main/java/black/android/content/pm/PackageParserLollipop22.java
@@ -13,20 +13,20 @@ public interface PackageParserLollipop22 {
@BConstructor
android.content.pm.PackageParser _new();
-// @BStaticMethod
-// ActivityInfo generateActivityInfo();
-//
-// @BStaticMethod
-// ApplicationInfo generateApplicationInfo();
-//
-// @BStaticMethod
-// PackageInfo generatePackageInfo();
-//
-// @BStaticMethod
-// ProviderInfo generateProviderInfo();
-//
-// @BStaticMethod
-// ServiceInfo generateServiceInfo();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@BMethod
void collectCertificates(Package p, int flags);
diff --git a/Bcore/src/main/java/black/android/content/pm/PackageParserMarshmallow.java b/Bcore/src/main/java/black/android/content/pm/PackageParserMarshmallow.java
index a0933e5..b0233d5 100644
--- a/Bcore/src/main/java/black/android/content/pm/PackageParserMarshmallow.java
+++ b/Bcore/src/main/java/black/android/content/pm/PackageParserMarshmallow.java
@@ -14,20 +14,20 @@ public interface PackageParserMarshmallow {
@BConstructor
PackageParser _new();
-// @BStaticMethod
-// ActivityInfo generateActivityInfo();
-//
-// @BStaticMethod
-// ApplicationInfo generateApplicationInfo();
-//
-// @BStaticMethod
-// PackageInfo generatePackageInfo();
-//
-// @BStaticMethod
-// ProviderInfo generateProviderInfo();
-//
-// @BStaticMethod
-// ServiceInfo generateServiceInfo();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@BMethod
void collectCertificates(Package p, int flags);
diff --git a/Bcore/src/main/java/black/android/graphics/Compatibility.java b/Bcore/src/main/java/black/android/graphics/Compatibility.java
index abff7be..ba089c0 100644
--- a/Bcore/src/main/java/black/android/graphics/Compatibility.java
+++ b/Bcore/src/main/java/black/android/graphics/Compatibility.java
@@ -3,9 +3,7 @@ package black.android.graphics;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
-/**
- * Created by BlackBox on 2022/2/24.
- */
+
@BClassName("android.graphics.Compatibility")
public interface Compatibility {
@BStaticMethod
diff --git a/Bcore/src/main/java/black/android/hardware/location/IContextHubService.java b/Bcore/src/main/java/black/android/hardware/location/IContextHubService.java
index a11ec15..878f732 100644
--- a/Bcore/src/main/java/black/android/hardware/location/IContextHubService.java
+++ b/Bcore/src/main/java/black/android/hardware/location/IContextHubService.java
@@ -6,9 +6,7 @@ import android.os.IInterface;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
-/**
- * Created by BlackBox on 2022/3/2.
- */
+
@BClassName("android.hardware.location.IContextHubService")
public interface IContextHubService {
diff --git a/Bcore/src/main/java/black/android/location/LocationManager.java b/Bcore/src/main/java/black/android/location/LocationManager.java
index 367b339..7a1d3ca 100644
--- a/Bcore/src/main/java/black/android/location/LocationManager.java
+++ b/Bcore/src/main/java/black/android/location/LocationManager.java
@@ -63,14 +63,14 @@ public interface LocationManager {
@BClassName("android.location.LocationManager$GpsStatusListenerTransport")
interface GpsStatusListenerTransportSumsungS5 {
-// @BMethod
-// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, int int5, int int6, int int7, [I int[]8);
+
+
}
@BClassName("android.location.LocationManager$GpsStatusListenerTransport")
interface GpsStatusListenerTransportOPPO_R815T {
-// @BMethod
-// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, [I int[]5, [I int[]6, [I int[]7, int int8);
+
+
}
@BClassName("android.location.LocationManager$GpsStatusListenerTransport")
@@ -93,14 +93,14 @@ public interface LocationManager {
@BMethod
void onNmeaReceived(long long0, String String1);
-// @BMethod
-// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, int int5, int int6, int int7);
+
+
}
@BClassName("android.location.LocationManager$GnssStatusListenerTransport")
interface GnssStatusListenerTransportO {
-// @BMethod
-// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4, [F float[]5);
+
+
}
@BClassName("android.location.LocationManager$GnssStatusListenerTransport")
@@ -123,7 +123,7 @@ public interface LocationManager {
@BMethod
void onNmeaReceived(long long0, String String1);
-// @BMethod
-// void onSvStatusChanged(int int0, [I int[]1, [F float[]2, [F float[]3, [F float[]4);
+
+
}
}
diff --git a/Bcore/src/main/java/black/android/net/IVpnManager.java b/Bcore/src/main/java/black/android/net/IVpnManager.java
index 9caff62..1a4ca1e 100644
--- a/Bcore/src/main/java/black/android/net/IVpnManager.java
+++ b/Bcore/src/main/java/black/android/net/IVpnManager.java
@@ -6,9 +6,7 @@ import android.os.IInterface;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
-/**
- * Created by BlackBox on 2022/2/26.
- */
+
@BClassName("android.net.IVpnManager")
public interface IVpnManager {
diff --git a/Bcore/src/main/java/black/android/os/IVibratorManagerService.java b/Bcore/src/main/java/black/android/os/IVibratorManagerService.java
index 4bd7a2e..27e880d 100644
--- a/Bcore/src/main/java/black/android/os/IVibratorManagerService.java
+++ b/Bcore/src/main/java/black/android/os/IVibratorManagerService.java
@@ -6,9 +6,7 @@ import android.os.IInterface;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
-/**
- * Created by BlackBox on 2022/3/19.
- */
+
@BClassName("android.os.IVibratorManagerService")
public interface IVibratorManagerService {
diff --git a/Bcore/src/main/java/black/android/telephony/TelephonyManager.java b/Bcore/src/main/java/black/android/telephony/TelephonyManager.java
index e971697..9c43941 100644
--- a/Bcore/src/main/java/black/android/telephony/TelephonyManager.java
+++ b/Bcore/src/main/java/black/android/telephony/TelephonyManager.java
@@ -6,9 +6,7 @@ import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BStaticField;
import top.niunaijun.blackreflection.annotation.BStaticMethod;
-/**
- * Created by BlackBox on 2022/2/26.
- */
+
@BClassName("android.telephony.TelephonyManager")
public interface TelephonyManager {
diff --git a/Bcore/src/main/java/black/com/android/internal/net/VpnConfig.java b/Bcore/src/main/java/black/com/android/internal/net/VpnConfig.java
index 1d99cce..a812711 100644
--- a/Bcore/src/main/java/black/com/android/internal/net/VpnConfig.java
+++ b/Bcore/src/main/java/black/com/android/internal/net/VpnConfig.java
@@ -5,9 +5,7 @@ import java.util.List;
import top.niunaijun.blackreflection.annotation.BClassName;
import top.niunaijun.blackreflection.annotation.BField;
-/**
- * Created by BlackBox on 2022/2/25.
- */
+
@BClassName("com.android.internal.net.VpnConfig")
public interface VpnConfig {
@BField
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java
index 79af7c9..766bfae 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/BlackBoxCore.java
@@ -72,15 +72,8 @@ import top.niunaijun.blackbox.utils.CrashMonitor;
import top.niunaijun.blackbox.utils.StoragePermissionHelper;
import top.niunaijun.blackbox.utils.LogSender;
-// just use it guys and i know you forgot to give credits so have it what ever 🤧
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
+
@SuppressLint({"StaticFieldLeak", "NewApi"})
@SuppressWarnings({"unchecked", "deprecation"})
public class BlackBoxCore extends ClientConfiguration {
@@ -89,25 +82,25 @@ public class BlackBoxCore extends ClientConfiguration {
private static final BlackBoxCore sBlackBoxCore = new BlackBoxCore();
private static Context sContext;
- // Static initializer to install the simple fix at class loading time
+
static {
try {
- // Install Pine anti-detection hooks as early as possible
+
SimpleCrashFix.installSimpleFix();
Slog.d(TAG, "Simple crash fix installed at class loading time");
- // Install stack trace filter for anti-detection
+
StackTraceFilter.install();
Slog.d(TAG, "Stack trace filter installed at class loading time");
- // Install social media app crash prevention
+
SocialMediaAppCrashPrevention.initialize();
Slog.d(TAG, "Social media app crash prevention initialized at class loading time");
- // Install DEX crash prevention
+
DexCrashPrevention.initialize();
Slog.d(TAG, "DEX crash prevention initialized at class loading time");
- // Install native crash prevention
+
NativeCrashPrevention.initialize();
Slog.d(TAG, "Native crash prevention initialized at class loading time");
- // Install comprehensive crash monitoring
+
CrashMonitor.initialize();
Slog.d(TAG, "Comprehensive crash monitoring initialized at class loading time");
} catch (Exception e) {
@@ -125,13 +118,13 @@ public class BlackBoxCore extends ClientConfiguration {
private boolean mServicesInitialized = false;
private long mLastServiceInitAttempt = 0;
- private static final long SERVICE_INIT_TIMEOUT_MS = 10000; // 10 seconds
+ private static final long SERVICE_INIT_TIMEOUT_MS = 10000;
+
- // Add callback mechanism for service availability
private final List mServiceAvailableCallbacks = new ArrayList<>();
private final Object mServiceCallbackLock = new Object();
- // Enhanced UID management for sandboxed environments
+
private int mCurrentAppUid = -1;
private String mCurrentAppPackage = null;
private boolean mIsSandboxedEnvironment = false;
@@ -172,12 +165,12 @@ public class BlackBoxCore extends ClientConfiguration {
mExceptionHandler = exceptionHandler;
}
- // Enhanced UID management methods
+
public void setCurrentAppUid(int uid, String packageName) {
mCurrentAppUid = uid;
mCurrentAppPackage = packageName;
- // Detect sandboxed environment
+
if (uid != mHostUid && uid > Process.FIRST_APPLICATION_UID && uid < Process.LAST_APPLICATION_UID) {
mIsSandboxedEnvironment = true;
Slog.d("BlackBoxCore", "Detected sandboxed environment for " + packageName + " with UID: " + uid);
@@ -196,26 +189,26 @@ public class BlackBoxCore extends ClientConfiguration {
return mIsSandboxedEnvironment;
}
- // Enhanced UID resolution for security-sensitive operations
+
public int resolveUidForOperation(int originalUid, String operation) {
try {
- // System UIDs should remain unchanged
+
if (originalUid > 0 && originalUid < Process.FIRST_APPLICATION_UID) {
return originalUid;
}
- // Non-user app UIDs should remain unchanged
+
if (originalUid > Process.LAST_APPLICATION_UID) {
return originalUid;
}
- // If we're in a sandboxed environment, use the current app UID
+
if (mIsSandboxedEnvironment && mCurrentAppUid > 0) {
Slog.d("BlackBoxCore", "Resolving UID for " + operation + ": " + originalUid + " -> " + mCurrentAppUid);
return mCurrentAppUid;
}
- // Default behavior for non-sandboxed environments
+
return originalUid;
} catch (Exception e) {
Slog.e("BlackBoxCore", "Error resolving UID for " + operation + ": " + e.getMessage());
@@ -229,12 +222,12 @@ public class BlackBoxCore extends ClientConfiguration {
}
try {
- // First, try to check if the black process is running
+
if (isMainProcess() && !isBlackProcessRunning()) {
Slog.w(TAG, "Black process not running, starting it and using fallback services...");
startBlackProcess();
- // Initialize services with fallbacks
+
String[] serviceNames = {
ServiceManager.ACTIVITY_MANAGER,
ServiceManager.PACKAGE_MANAGER,
@@ -260,12 +253,12 @@ public class BlackBoxCore extends ClientConfiguration {
mServicesInitialized = true;
Slog.d(TAG, "Services initialized with fallbacks");
- // Notify callbacks that services are available
+
notifyServiceAvailableCallbacks();
return true;
}
- // Try to initialize services normally
+
String[] serviceNames = {
ServiceManager.ACTIVITY_MANAGER,
ServiceManager.PACKAGE_MANAGER,
@@ -283,7 +276,7 @@ public class BlackBoxCore extends ClientConfiguration {
getServiceInternal(serviceName);
} catch (Exception e) {
Slog.w(TAG, "Failed to initialize service: " + serviceName + ", trying fallback", e);
- // Try fallback if normal initialization fails
+
IBinder fallbackService = createFallbackService(serviceName);
if (fallbackService != null) {
mServices.put(serviceName, fallbackService);
@@ -293,11 +286,11 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.d(TAG, "Services initialized successfully");
mServicesInitialized = true;
- // Notify callbacks that services are available
+
notifyServiceAvailableCallbacks();
} catch (Exception e) {
Slog.e(TAG, "Failed to initialize services, using fallbacks: " + e.getMessage());
- // Even if initialization fails, try to create fallback services
+
try {
String[] serviceNames = {
ServiceManager.ACTIVITY_MANAGER,
@@ -324,7 +317,7 @@ public class BlackBoxCore extends ClientConfiguration {
mServicesInitialized = true;
Slog.d(TAG, "Services initialized with fallbacks after error");
- // Notify callbacks that services are available
+
notifyServiceAvailableCallbacks();
return true;
} catch (Exception fallbackEx) {
@@ -351,12 +344,12 @@ public class BlackBoxCore extends ClientConfiguration {
return binder;
}
- // Check if we're in the main process and trying to access services
- // If so, we need to ensure the black process is running first
+
+
if (isMainProcess() && !isBlackProcessRunning()) {
Slog.w(TAG, "Main process trying to access service " + name + " but black process not running, starting it...");
startBlackProcess();
- // Wait a bit for the process to start, but with timeout
+
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
@@ -364,20 +357,20 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- // Add timeout for provider calls to prevent hanging
+
long startTime = System.currentTimeMillis();
- long timeout = 3000; // 3 seconds timeout
+ long timeout = 3000;
try {
Bundle bundle = new Bundle();
bundle.putString("_B_|_server_name_", name);
- // Try to call the provider with timeout
+
Bundle vm = null;
try {
vm = ProviderCall.callSafely(ProxyManifest.getBindProvider(), "VM", null, bundle);
} catch (Exception e) {
- // If provider call fails, check if we've exceeded timeout
+
if (System.currentTimeMillis() - startTime > timeout) {
Slog.w(TAG, "Provider call timeout for service: " + name + ", using fallback");
return createFallbackService(name);
@@ -387,7 +380,7 @@ public class BlackBoxCore extends ClientConfiguration {
if (vm == null) {
Slog.w(TAG, "Provider call returned null for service: " + name);
- // Try to create a fallback service if possible
+
return createFallbackService(name);
}
@@ -397,7 +390,7 @@ public class BlackBoxCore extends ClientConfiguration {
mServices.put(name, binder);
} else {
Slog.w(TAG, "Failed to get binder for service: " + name);
- // Try to create a fallback service
+
return createFallbackService(name);
}
return binder;
@@ -407,13 +400,11 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Create a fallback service when the main service is not available
- */
+
private IBinder createFallbackService(String name) {
try {
- // Don't call ServiceManager.getService here to avoid circular dependency
- // Instead, just return null and let the caller handle it
+
+
Slog.w(TAG, "No fallback available for service: " + name + " (avoiding circular dependency)");
return null;
} catch (Exception e) {
@@ -424,16 +415,14 @@ public class BlackBoxCore extends ClientConfiguration {
- /**
- * Check if the black process is running
- */
+
private boolean isBlackProcessRunning() {
try {
- // Try to access the SystemCallProvider to see if it's available
+
Bundle testBundle = new Bundle();
testBundle.putString("_B_|_server_name_", "test");
- // Use a more robust provider check with better error handling
+
try {
Bundle result = ProviderCall.callSafely(ProxyManifest.getBindProvider(), "VM", null, testBundle);
if (result != null) {
@@ -444,23 +433,23 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.w(TAG, "Provider call failed: " + e.getMessage());
}
- // Fallback: Check if the provider authority exists
+
try {
String authority = ProxyManifest.getBindProvider();
if (authority != null && !authority.isEmpty()) {
- // Try to resolve the provider
+
android.content.pm.ProviderInfo providerInfo = getContext().getPackageManager()
.resolveContentProvider(authority, 0);
if (providerInfo != null) {
Slog.d(TAG, "Provider exists but call failed - black process may be starting");
- return false; // Provider exists but not accessible yet
+ return false;
}
}
} catch (Exception e) {
Slog.w(TAG, "Provider resolution failed: " + e.getMessage());
}
- // Additional fallback: Check if DaemonService is running
+
try {
android.app.ActivityManager am = (android.app.ActivityManager) getContext()
.getSystemService(Context.ACTIVITY_SERVICE);
@@ -485,26 +474,24 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Start the black process if it's not running
- */
+
private void startBlackProcess() {
try {
Slog.d(TAG, "Starting black process...");
- // Check if we're in a valid state to start services
+
if (!isValidProcessState()) {
Slog.w(TAG, "Process state is invalid, delaying service start");
- // Schedule a delayed retry
+
scheduleDelayedServiceStart();
return;
}
- // Start the DaemonService which should be in the black process
+
Intent intent = new Intent();
intent.setClass(getContext(), DaemonService.class);
- // Add flags to help with process startup
+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
boolean serviceStarted = false;
@@ -514,12 +501,12 @@ public class BlackBoxCore extends ClientConfiguration {
try {
if (retry > 0) {
Slog.d(TAG, "Retry attempt " + (retry + 1) + " for starting DaemonService");
- // Use non-blocking delay instead of Thread.sleep
+
if (retry == 1) {
- // For first retry, just continue immediately
+
Slog.d(TAG, "First retry - continuing immediately");
} else {
- // For subsequent retries, schedule delayed execution
+
scheduleDelayedRetry(intent, retry);
return;
}
@@ -561,40 +548,38 @@ public class BlackBoxCore extends ClientConfiguration {
if (!serviceStarted) {
Slog.e(TAG, "Failed to start DaemonService after " + maxRetries + " attempts");
- // Try alternative startup methods
+
tryAlternativeStartupMethods();
return;
}
- // Schedule provider check asynchronously instead of blocking
+
scheduleProviderCheck();
Slog.d(TAG, "Started DaemonService to initialize black process");
} catch (Exception e) {
Slog.e(TAG, "Failed to start black process", e);
- // Schedule a delayed retry
+
scheduleDelayedServiceStart();
}
}
- /**
- * Check if the current process state is valid for starting services
- */
+
private boolean isValidProcessState() {
try {
- // Check if the context is valid
+
if (getContext() == null) {
Slog.w(TAG, "Context is null, process state invalid");
return false;
}
- // Check if we're in the main process
+
if (!isMainProcess()) {
Slog.w(TAG, "Not in main process, skipping service start");
return false;
}
- // Check if the process is in a good state
+
try {
getContext().getPackageName();
} catch (Exception e) {
@@ -609,9 +594,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Schedule a delayed retry for service startup
- */
+
private void scheduleDelayedRetry(Intent intent, int retry) {
try {
int delayMs = 1000 * retry;
@@ -631,7 +614,7 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.d(TAG, "Delayed retry successful");
} catch (Exception e) {
Slog.e(TAG, "Delayed retry failed: " + e.getMessage());
- // Try alternative methods
+
tryAlternativeStartupMethods();
}
}
@@ -639,14 +622,12 @@ public class BlackBoxCore extends ClientConfiguration {
} catch (Exception e) {
Slog.w(TAG, "Failed to schedule delayed retry: " + e.getMessage());
- // Fall back to alternative methods immediately
+
tryAlternativeStartupMethods();
}
}
- /**
- * Schedule provider check asynchronously
- */
+
private void scheduleProviderCheck() {
try {
android.os.Handler handler = new android.os.Handler(android.os.Looper.getMainLooper());
@@ -654,7 +635,7 @@ public class BlackBoxCore extends ClientConfiguration {
@Override
public void run() {
try {
- // Try to access the provider to ensure it's working
+
Bundle testBundle = new Bundle();
testBundle.putString("_B_|_server_name_", "test");
Bundle result = ProviderCall.callSafely(ProxyManifest.getBindProvider(), "VM", null, testBundle);
@@ -667,36 +648,32 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.w(TAG, "SystemCallProvider not accessible yet, will retry later: " + e.getMessage());
}
}
- }, 1000); // 1 second delay
+ }, 1000);
} catch (Exception e) {
Slog.w(TAG, "Failed to schedule provider check: " + e.getMessage());
}
}
- /**
- * Handle service startup failures with appropriate recovery actions
- */
+
private void handleServiceStartFailure(int retry, int maxRetries, Exception e) {
if (retry < maxRetries - 1) {
Slog.w(TAG, "Service start failed, will retry. Attempt " + (retry + 1) + " of " + maxRetries);
} else {
Slog.e(TAG, "Service start failed after " + maxRetries + " attempts: " + e.getMessage());
- // Try alternative startup methods
+
tryAlternativeStartupMethods();
}
}
- /**
- * Handle "process is bad" errors with recovery strategies
- */
+
private void handleProcessBadError(int retry, int maxRetries) {
if (retry < maxRetries - 1) {
Slog.w(TAG, "Process is bad, attempting recovery. Attempt " + (retry + 1) + " of " + maxRetries);
- // Try to recover the process state
+
try {
- // Schedule recovery instead of blocking
+
scheduleProcessRecovery(retry, maxRetries);
} catch (Exception e) {
@@ -704,17 +681,15 @@ public class BlackBoxCore extends ClientConfiguration {
}
} else {
Slog.e(TAG, "Process recovery failed after " + maxRetries + " attempts");
- // Try alternative startup methods
+
tryAlternativeStartupMethods();
}
}
- /**
- * Schedule process recovery asynchronously
- */
+
private void scheduleProcessRecovery(int retry, int maxRetries) {
try {
- int delayMs = 2000; // 2 second delay for process recovery
+ int delayMs = 2000;
Slog.d(TAG, "Scheduling process recovery in " + delayMs + "ms");
android.os.Handler handler = new android.os.Handler(android.os.Looper.getMainLooper());
@@ -723,10 +698,10 @@ public class BlackBoxCore extends ClientConfiguration {
public void run() {
try {
Slog.d(TAG, "Executing process recovery");
- // Try to refresh the context
+
refreshProcessContext();
- // Retry the service start
+
if (isMainProcess() && !isBlackProcessRunning()) {
startBlackProcess();
}
@@ -742,14 +717,12 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Try alternative methods to start the service
- */
+
private void tryAlternativeStartupMethods() {
Slog.w(TAG, "Trying alternative startup methods...");
try {
- // Method 1: Try using a different context
+
Context alternativeContext = getAlternativeContext();
if (alternativeContext != null) {
Intent intent = new Intent();
@@ -763,7 +736,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
try {
- // Method 2: Try using application context
+
Context appContext = getContext().getApplicationContext();
if (appContext != null && appContext != getContext()) {
Intent intent = new Intent();
@@ -779,12 +752,10 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.e(TAG, "All alternative startup methods failed");
}
- /**
- * Get an alternative context for service startup
- */
+
private Context getAlternativeContext() {
try {
- // Try to get the application context
+
Context appContext = getContext().getApplicationContext();
if (appContext != null) {
return appContext;
@@ -796,28 +767,24 @@ public class BlackBoxCore extends ClientConfiguration {
return null;
}
- /**
- * Refresh the process context to recover from bad state
- */
+
private void refreshProcessContext() {
try {
- // This is a placeholder for context refresh logic
- // In a real implementation, you might want to reinitialize certain components
+
+
Slog.d(TAG, "Attempting to refresh process context");
- // No blocking operations - just log and continue
+
} catch (Exception e) {
Slog.w(TAG, "Context refresh failed: " + e.getMessage());
}
}
- /**
- * Schedule a delayed service start for later
- */
+
private void scheduleDelayedServiceStart() {
try {
- // Schedule a delayed retry using a handler
+
android.os.Handler handler = new android.os.Handler(android.os.Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
@@ -827,7 +794,7 @@ public class BlackBoxCore extends ClientConfiguration {
startBlackProcess();
}
}
- }, 5000); // 5 second delay
+ }, 5000);
Slog.d(TAG, "Scheduled delayed service start in 5 seconds");
} catch (Exception e) {
@@ -835,15 +802,13 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Ensure the black process is properly initialized
- */
+
public void ensureBlackProcessInitialized() {
if (isMainProcess() && !isBlackProcessRunning()) {
Slog.w(TAG, "Ensuring black process is initialized...");
startBlackProcess();
- // Wait for the process to be ready
+
int maxRetries = 5;
int retryCount = 0;
while (retryCount < maxRetries && !isBlackProcessRunning()) {
@@ -867,15 +832,15 @@ public class BlackBoxCore extends ClientConfiguration {
public void doAttachBaseContext(Context context,
ClientConfiguration clientConfiguration) {
try {
- // Set essential properties for the context
+
setEssentialProperties(context, clientConfiguration);
- // Try to disable window leak warnings via reflection
+
try {
Class> windowManagerClass = Class.forName("android.view.WindowManager");
Field ignoreLeaksField = windowManagerClass.getDeclaredField("mIgnoreWindowLeaks");
ignoreLeaksField.setAccessible(true);
- // This might not work, but worth trying
+
} catch (Exception e) {
Slog.w(TAG, "Could not access WindowManager leak field: " + e.getMessage());
}
@@ -887,7 +852,7 @@ public class BlackBoxCore extends ClientConfiguration {
sContext = context;
mClientConfiguration = clientConfiguration;
- // Install system hooks to prevent crashes
+
installSystemHooks();
initNotificationManager();
@@ -904,17 +869,17 @@ public class BlackBoxCore extends ClientConfiguration {
if (BlackBoxCore.get().isBlackProcess()) {
BEnvironment.load();
if (processName.endsWith("p0")) {
-// android.os.Debug.waitForDebugger();
+
}
-// android.os.Debug.waitForDebugger();
+
}
if (isServerProcess()) {
if (clientConfiguration.isEnableDaemonService()) {
try {
- // Check if we're in a valid state to start services
+
if (!isValidProcessState()) {
Slog.w(TAG, "Server process state is invalid, delaying service start");
- // Schedule a delayed retry for server process
+
scheduleDelayedServerServiceStart();
return;
}
@@ -922,7 +887,7 @@ public class BlackBoxCore extends ClientConfiguration {
Intent intent = new Intent();
intent.setClass(getContext(), DaemonService.class);
- // Add flags to help with process startup
+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
boolean serviceStarted = false;
@@ -932,12 +897,12 @@ public class BlackBoxCore extends ClientConfiguration {
try {
if (retry > 0) {
Slog.d(TAG, "Retry attempt " + (retry + 1) + " for starting DaemonService in server process");
- // Use non-blocking delay instead of Thread.sleep
+
if (retry == 1) {
- // For first retry, just continue immediately
+
Slog.d(TAG, "First retry for server process - continuing immediately");
} else {
- // For subsequent retries, schedule delayed execution
+
scheduleDelayedServerRetry(intent, retry);
return;
}
@@ -979,56 +944,56 @@ public class BlackBoxCore extends ClientConfiguration {
if (!serviceStarted) {
Slog.e(TAG, "Failed to start DaemonService in server process after " + maxRetries + " attempts");
- // Try alternative startup methods for server process
+
tryAlternativeServerStartupMethods();
}
} catch (Exception e) {
Slog.e(TAG, "Unexpected error starting DaemonService in server process: " + e.getMessage(), e);
- // Schedule a delayed retry
+
scheduleDelayedServerServiceStart();
}
}
}
- // Initialize VPN service for internet access
+
initVpnService();
HookManager.get().init();
}
public void doCreate() {
- // Install system hooks to prevent crashes
+
installSystemHooks();
- // Set a timeout for the entire initialization process
+
long startTime = System.currentTimeMillis();
- long maxInitTime = 10000; // 10 seconds max
+ long maxInitTime = 10000;
try {
- // Ensure black process is initialized before proceeding
+
ensureBlackProcessInitialized();
- // Check if we've exceeded the timeout
+
if (System.currentTimeMillis() - startTime > maxInitTime) {
Slog.w(TAG, "Initialization timeout exceeded, proceeding with fallback services");
}
ensureProperInitialization();
- // fix contentProvider
+
if (isBlackProcess()) {
ContentProviderDelegate.init();
}
if (!isServerProcess()) {
- // Initialize the ServiceManager to ensure services are available
+
try {
ServiceManager.initBlackManager();
} catch (Exception e) {
Slog.w(TAG, "Failed to initialize ServiceManager, continuing with fallback: " + e.getMessage());
}
- // Reset transaction throttler on startup
+
getBPackageManager().resetTransactionThrottler();
}
@@ -1039,7 +1004,7 @@ public class BlackBoxCore extends ClientConfiguration {
long totalTime = System.currentTimeMillis() - startTime;
Slog.e(TAG, "BlackBox initialization failed after " + totalTime + "ms", e);
- // Try to continue with fallback services
+
try {
if (!isServerProcess()) {
ServiceManager.initBlackManager();
@@ -1078,84 +1043,50 @@ public class BlackBoxCore extends ClientConfiguration {
return BStorageManager.get();
}
- // ============== Storage Permission Methods (SDK 30+) ==============
- /**
- * Check if the host app has storage permission.
- * On Android 13+, this checks for granular media permissions.
- * On Android 11-12, this checks for READ_EXTERNAL_STORAGE or MANAGE_EXTERNAL_STORAGE.
- */
+
+
public boolean hasStoragePermission() {
return StoragePermissionHelper.hasStoragePermission(sContext);
}
- /**
- * Check if the host app has "All Files Access" (MANAGE_EXTERNAL_STORAGE) on Android 11+.
- * Returns true on older Android versions where this isn't required.
- */
+
public boolean hasAllFilesAccess() {
return StoragePermissionHelper.hasAllFilesAccess();
}
- /**
- * Check if the host app has full file access (both storage permission and all files access).
- */
+
public boolean hasFullFileAccess() {
return StoragePermissionHelper.hasFullFileAccess(sContext);
}
- /**
- * Request storage permission from the user.
- * On Android 13+, requests granular media permissions.
- * On older versions, requests READ/WRITE_EXTERNAL_STORAGE.
- *
- * @param activity The activity to use for requesting permission
- */
+
public void requestStoragePermission(android.app.Activity activity) {
StoragePermissionHelper.requestStoragePermission(activity);
}
- /**
- * Request "All Files Access" (MANAGE_EXTERNAL_STORAGE) on Android 11+.
- * This opens the system settings page for the user to grant permission.
- *
- * @param activity The activity to use for requesting permission
- */
+
public void requestAllFilesAccess(android.app.Activity activity) {
StoragePermissionHelper.requestAllFilesAccess(activity);
}
- /**
- * Request full file access (both storage permission and all files access).
- * Use this before launching apps that need file access.
- *
- * @param activity The activity to use for requesting permission
- */
+
public void requestFullFileAccess(android.app.Activity activity) {
StoragePermissionHelper.requestFullFileAccess(activity);
}
- /**
- * Handle permission result callback from Activity.onRequestPermissionsResult()
- * @return true if storage permission was granted
- */
+
public boolean handleStoragePermissionResult(android.app.Activity activity, int requestCode,
String[] permissions, int[] grantResults) {
return StoragePermissionHelper.handlePermissionResult(activity, requestCode, permissions, grantResults);
}
- /**
- * Handle result from All Files Access settings activity.
- * Call this from Activity.onActivityResult()
- * @return true if all files access was granted
- */
+
public boolean handleAllFilesAccessResult(int requestCode) {
return StoragePermissionHelper.handleAllFilesAccessResult(requestCode);
}
- /**
- * Get the request codes for permission handling.
- */
+
public static int getStoragePermissionRequestCode() {
return StoragePermissionHelper.REQUEST_CODE_STORAGE_PERMISSION;
}
@@ -1167,19 +1098,19 @@ public class BlackBoxCore extends ClientConfiguration {
public boolean launchApk(String packageName, int userId) {
onBeforeMainLaunchApk(packageName, userId);
- // Check storage permissions on Android 11+ (SDK 30+)
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!hasAllFilesAccess()) {
Slog.w(TAG, "All files access not granted for launching: " + packageName);
- // Notify the host app that permission is needed
+
for (AppLifecycleCallback callback : mAppLifecycleCallbacks) {
if (callback.onStoragePermissionNeeded(packageName, userId)) {
- // Host app will handle the permission request, cancel launch
+
Slog.d(TAG, "Launch cancelled - host app handling permission request");
return false;
}
}
- // Otherwise, continue but warn
+
Slog.w(TAG, "Launching without all files access - some file operations may fail");
}
}
@@ -1205,7 +1136,7 @@ public class BlackBoxCore extends ClientConfiguration {
public InstallResult installPackageAsUser(String packageName, int userId) {
try {
- // Prevent cloning BlackBox app from within BlackBox
+
if (packageName.equals(getHostPkg())) {
return new InstallResult().installError("Cannot clone BlackBox app from within BlackBox. This would create infinite recursion and is not allowed for security reasons.");
}
@@ -1219,7 +1150,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
public InstallResult installPackageAsUser(File apk, int userId) {
- // Check if this is a BlackBox-related APK
+
try {
PackageInfo packageInfo = getPackageManager().getPackageArchiveInfo(apk.getAbsolutePath(), 0);
if (packageInfo != null) {
@@ -1229,7 +1160,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
} catch (Exception e) {
- // If we can't check the package info, proceed but log a warning
+
Slog.w(TAG, "Could not verify package info for APK: " + apk.getAbsolutePath());
}
@@ -1237,7 +1168,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
public InstallResult installPackageAsUser(Uri apk, int userId) {
- // For URI installations, we can't easily check the package name, so we'll rely on the BPackageManagerService check
+
return getBPackageManager().installPackageAsUser(apk.toString(), InstallOption.installByStorage().makeUriFile(), userId);
}
@@ -1302,21 +1233,13 @@ public class BlackBoxCore extends ClientConfiguration {
return !GmsCore.isInstalledGoogleService(userId);
}
- /**
- * Process type
- */
+
private enum ProcessType {
- /**
- * Server process
- */
+
Server,
- /**
- * Black app process
- */
+
BAppClient,
- /**
- * Main process
- */
+
Main,
}
@@ -1337,6 +1260,11 @@ public class BlackBoxCore extends ClientConfiguration {
return mClientConfiguration.isHideRoot();
}
+ @Override
+ public boolean isDisableFlagSecure() {
+ return mClientConfiguration.isDisableFlagSecure();
+ }
+
@Override
@@ -1356,12 +1284,12 @@ public class BlackBoxCore extends ClientConfiguration {
String fileName = context.getPackageName() + "_logcat.txt";
boolean useMediaStore = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
- // Log comprehensive device information
+
logDeviceInfo();
try {
if (useMediaStore) {
- // Use MediaStore for Android 10+
+
android.content.ContentValues values = new android.content.ContentValues();
values.put(android.provider.MediaStore.Downloads.DISPLAY_NAME, fileName);
values.put(android.provider.MediaStore.Downloads.MIME_TYPE, "text/plain");
@@ -1369,7 +1297,7 @@ public class BlackBoxCore extends ClientConfiguration {
android.net.Uri uri = context.getContentResolver().insert(android.provider.MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
if (uri != null) {
try (java.io.OutputStream out = context.getContentResolver().openOutputStream(uri)) {
- // Clear logcat and dump to output stream
+
ShellUtils.execCommand("logcat -c", false);
java.lang.Process process = Runtime.getRuntime().exec("logcat");
try (java.io.InputStream in = process.getInputStream()) {
@@ -1382,7 +1310,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
} else {
- // Use app-private external files dir for Android 9 and below
+
File docuentsdir = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "logs");
if (!docuentsdir.exists()) {
docuentsdir.mkdirs();
@@ -1398,27 +1326,25 @@ public class BlackBoxCore extends ClientConfiguration {
}).start();
}
- /**
- * Log comprehensive device information for debugging purposes
- */
+
private void logDeviceInfo() {
try {
Slog.i(TAG, "╔══════════════════════════════════════════════════════════════╗");
Slog.i(TAG, "║ DEVICE INFORMATION ║");
Slog.i(TAG, "╠══════════════════════════════════════════════════════════════╣");
- // Android Version Info
+
Slog.i(TAG, "║ Android Version: " + Build.VERSION.RELEASE);
Slog.i(TAG, "║ SDK Level: " + Build.VERSION.SDK_INT);
Slog.i(TAG, "║ Build ID: " + Build.ID);
Slog.i(TAG, "║ Build Display: " + Build.DISPLAY);
- // Security Patch (API 23+)
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Slog.i(TAG, "║ Security Patch: " + Build.VERSION.SECURITY_PATCH);
}
- // Device Info
+
Slog.i(TAG, "╠══════════════════════════════════════════════════════════════╣");
Slog.i(TAG, "║ Manufacturer: " + Build.MANUFACTURER);
Slog.i(TAG, "║ Brand: " + Build.BRAND);
@@ -1428,7 +1354,7 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.i(TAG, "║ Board: " + Build.BOARD);
Slog.i(TAG, "║ Hardware: " + Build.HARDWARE);
- // CPU/ABI Info
+
Slog.i(TAG, "╠══════════════════════════════════════════════════════════════╣");
Slog.i(TAG, "║ Supported ABIs: " + String.join(", ", Build.SUPPORTED_ABIS));
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
@@ -1438,13 +1364,13 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.i(TAG, "║ 64-bit ABIs: " + String.join(", ", Build.SUPPORTED_64_BIT_ABIS));
}
- // Build Fingerprint
+
Slog.i(TAG, "╠══════════════════════════════════════════════════════════════╣");
Slog.i(TAG, "║ Fingerprint: " + Build.FINGERPRINT);
Slog.i(TAG, "║ Type: " + Build.TYPE);
Slog.i(TAG, "║ Tags: " + Build.TAGS);
- // Memory Info
+
try {
Runtime runtime = Runtime.getRuntime();
long maxMem = runtime.maxMemory() / (1024 * 1024);
@@ -1459,7 +1385,7 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.w(TAG, "║ Memory info unavailable: " + e.getMessage());
}
- // App Info
+
try {
Context context = getContext();
if (context != null) {
@@ -1478,7 +1404,7 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.w(TAG, "║ App info unavailable: " + e.getMessage());
}
- // Timestamp
+
Slog.i(TAG, "╠══════════════════════════════════════════════════════════════╣");
Slog.i(TAG, "║ Timestamp: " + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z",
java.util.Locale.getDefault()).format(new java.util.Date()));
@@ -1494,7 +1420,7 @@ public class BlackBoxCore extends ClientConfiguration {
int pid = Process.myPid();
String processName = null;
- // Try modern approach first (API 28+)
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -1512,7 +1438,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- // Fallback to deprecated method if modern approach fails
+
if (processName == null) {
try {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -1702,9 +1628,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Install system hooks to prevent crashes
- */
+
public static void installSystemHooks() {
try {
SimpleCrashFix.installSimpleFix();
@@ -1714,9 +1638,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Set essential properties for the context
- */
+
private void setEssentialProperties(Context context, ClientConfiguration clientConfiguration) {
if (clientConfiguration == null) {
throw new IllegalArgumentException("ClientConfiguration is null!");
@@ -1736,19 +1658,19 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.w(TAG, "Failed to call native resource disabling: " + e.getMessage());
}
- // Set only essential system properties that don't require system permissions
+
try {
- // Set properties to handle window management issues (these are usually allowed)
+
System.setProperty("android.view.WindowManager.IGNORE_WINDOW_LEAKS", "true");
System.setProperty("android.app.Activity.IGNORE_WINDOW_LEAKS", "true");
System.setProperty("android.view.WindowManager.SUPPRESS_WINDOW_LEAK_WARNINGS", "true");
- // Try to disable overlay loading via reflection (safer than system properties)
+
try {
Class> resourcesManagerClass = Class.forName("android.app.ResourcesManager");
Field disableOverlayField = resourcesManagerClass.getDeclaredField("mDisableOverlayLoading");
disableOverlayField.setAccessible(true);
- // This might not work, but worth trying
+
} catch (Exception e) {
Slog.w(TAG, "Could not access ResourcesManager overlay field: " + e.getMessage());
}
@@ -1757,23 +1679,21 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Initialize VPN service for internet access
- */
+
private void initVpnService() {
try {
- // Check if VPN mode is enabled in settings
+
if (mClientConfiguration == null || !mClientConfiguration.isUseVpnNetwork()) {
Slog.d(TAG, "VPN network mode disabled, using normal network");
return;
}
- // Start the VPN service asynchronously to prevent blocking main thread
+
new Thread(new Runnable() {
@Override
public void run() {
try {
- // Start the VPN service to ensure internet access works
+
Intent vpnIntent = new Intent(getContext(), top.niunaijun.blackbox.proxy.ProxyVpnService.class);
vpnIntent.setAction("android.net.VpnService");
@@ -1786,27 +1706,25 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.d(TAG, "VPN service started successfully for internet access");
} catch (Exception e) {
Slog.w(TAG, "Failed to start VPN service: " + e.getMessage());
- // Don't fail initialization if VPN service fails
- // The app can still work without VPN, just with limited network access
+
+
}
}
}, "VPNServiceInit").start();
} catch (Exception e) {
Slog.w(TAG, "Failed to initialize VPN service: " + e.getMessage());
- // Don't fail initialization if VPN service fails
+
}
}
- /**
- * Ensure proper initialization order for all components
- */
+
private static void ensureProperInitialization() {
try {
- // Initialize core components in the correct order
+
Slog.d(TAG, "Ensuring proper initialization order...");
- // 1. Initialize NativeCore first
+
try {
NativeCore.init(android.os.Build.VERSION.SDK_INT);
Slog.d(TAG, "NativeCore initialized successfully");
@@ -1814,7 +1732,7 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.w(TAG, "NativeCore initialization failed: " + e.getMessage());
}
- // 2. Initialize services
+
try {
ServiceManager.initBlackManager();
Slog.d(TAG, "ServiceManager initialized successfully");
@@ -1822,7 +1740,7 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.w(TAG, "ServiceManager initialization failed: " + e.getMessage());
}
- // 3. Initialize ActivityThread hooks
+
try {
BActivityThread.hookActivityThread();
Slog.d(TAG, "BActivityThread hooks initialized successfully");
@@ -1836,18 +1754,16 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Returns true if the application instance is already running for the given user, else false.
- */
+
public static boolean isRunningApplication(String packageName, int userId) {
- // Access the virtual task stack
+
try {
- // Get the ActivityManager from the context
+
android.app.ActivityManager am = (android.app.ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
if (am == null) return false;
- // Check all running tasks in the virtual stack
- // We need to check the virtual stack, not the real system stack
- // So we use the ActivityStack from BlackBox
+
+
+
ServiceManager.get();
top.niunaijun.blackbox.core.system.am.ActivityStack stack =
(top.niunaijun.blackbox.core.system.am.ActivityStack) ServiceManager.getService(ServiceManager.ACTIVITY_MANAGER);
@@ -1857,7 +1773,7 @@ public class BlackBoxCore extends ClientConfiguration {
if (tasks == null) return false;
for (top.niunaijun.blackbox.core.system.am.TaskRecord task : tasks.values()) {
if (task.userId == userId && task.taskAffinity != null && task.taskAffinity.contains(packageName)) {
- // Check if there is at least one non-finished activity in the task
+
for (top.niunaijun.blackbox.core.system.am.ActivityRecord activity : task.activities) {
if (!activity.finished) {
return true;
@@ -1871,13 +1787,11 @@ public class BlackBoxCore extends ClientConfiguration {
return false;
}
- /**
- * Register a callback to be notified when services become available
- */
+
public void addServiceAvailableCallback(Runnable callback) {
synchronized (mServiceCallbackLock) {
if (mServicesInitialized) {
- // Services are already available, run callback immediately
+
callback.run();
} else {
mServiceAvailableCallbacks.add(callback);
@@ -1885,18 +1799,14 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Remove a service available callback
- */
+
public void removeServiceAvailableCallback(Runnable callback) {
synchronized (mServiceCallbackLock) {
mServiceAvailableCallbacks.remove(callback);
}
}
- /**
- * Notify all registered callbacks that services are available
- */
+
private void notifyServiceAvailableCallbacks() {
synchronized (mServiceCallbackLock) {
if (!mServiceAvailableCallbacks.isEmpty()) {
@@ -1913,11 +1823,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Wait for services to become available with a timeout
- * @param timeoutMs Timeout in milliseconds
- * @return true if services became available, false if timeout
- */
+
public boolean waitForServicesAvailable(long timeoutMs) {
if (mServicesInitialized) {
return true;
@@ -1936,18 +1842,12 @@ public class BlackBoxCore extends ClientConfiguration {
return mServicesInitialized;
}
- /**
- * Check if services are currently available
- */
+
public boolean isServicesAvailable() {
return mServicesInitialized;
}
- /**
- * Check if an APK file is the BlackBox app itself
- * @param apkFile The APK file to check
- * @return true if it's the BlackBox app, false otherwise
- */
+
public boolean isBlackBoxApp(File apkFile) {
try {
if (apkFile == null || !apkFile.exists()) {
@@ -1965,11 +1865,7 @@ public class BlackBoxCore extends ClientConfiguration {
return false;
}
- /**
- * Check if a package name is the BlackBox app
- * @param packageName The package name to check
- * @return true if it's the BlackBox app, false otherwise
- */
+
public boolean isBlackBoxApp(String packageName) {
if (packageName == null || packageName.isEmpty()) {
return false;
@@ -1977,29 +1873,25 @@ public class BlackBoxCore extends ClientConfiguration {
return packageName.equals(getHostPkg());
}
- /**
- * Handle server service startup failures with appropriate recovery actions
- */
+
private void handleServerServiceStartFailure(int retry, int maxRetries, Exception e) {
if (retry < maxRetries - 1) {
Slog.w(TAG, "Server service start failed, will retry. Attempt " + (retry + 1) + " of " + maxRetries);
} else {
Slog.e(TAG, "Server service start failed after " + maxRetries + " attempts: " + e.getMessage());
- // Try alternative startup methods for server process
+
tryAlternativeServerStartupMethods();
}
}
- /**
- * Handle "process is bad" errors for server process with recovery strategies
- */
+
private void handleServerProcessBadError(int retry, int maxRetries) {
if (retry < maxRetries - 1) {
Slog.w(TAG, "Server process is bad, attempting recovery. Attempt " + (retry + 1) + " of " + maxRetries);
- // Try to recover the server process state
+
try {
- // Schedule recovery instead of blocking
+
scheduleServerProcessRecovery(retry, maxRetries);
} catch (Exception e) {
@@ -2007,17 +1899,15 @@ public class BlackBoxCore extends ClientConfiguration {
}
} else {
Slog.e(TAG, "Server process recovery failed after " + maxRetries + " attempts");
- // Try alternative startup methods for server process
+
tryAlternativeServerStartupMethods();
}
}
- /**
- * Schedule server process recovery asynchronously
- */
+
private void scheduleServerProcessRecovery(int retry, int maxRetries) {
try {
- int delayMs = 2000; // 2 second delay for process recovery
+ int delayMs = 2000;
Slog.d(TAG, "Scheduling server process recovery in " + delayMs + "ms");
android.os.Handler handler = new android.os.Handler(android.os.Looper.getMainLooper());
@@ -2026,10 +1916,10 @@ public class BlackBoxCore extends ClientConfiguration {
public void run() {
try {
Slog.d(TAG, "Executing server process recovery");
- // Try to refresh the server process context
+
refreshServerProcessContext();
- // Retry the service start
+
if (isServerProcess() && mClientConfiguration.isEnableDaemonService()) {
Intent intent = new Intent();
intent.setClass(getContext(), DaemonService.class);
@@ -2053,14 +1943,12 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Try alternative methods to start the service in server process
- */
+
private void tryAlternativeServerStartupMethods() {
Slog.w(TAG, "Trying alternative startup methods for server process...");
try {
- // Method 1: Try using a different context
+
Context alternativeContext = getAlternativeContext();
if (alternativeContext != null) {
Intent intent = new Intent();
@@ -2074,7 +1962,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
try {
- // Method 2: Try using application context
+
Context appContext = getContext().getApplicationContext();
if (appContext != null && appContext != getContext()) {
Intent intent = new Intent();
@@ -2090,35 +1978,31 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.e(TAG, "All alternative startup methods failed for server process");
}
- /**
- * Refresh the server process context to recover from bad state
- */
+
private void refreshServerProcessContext() {
try {
- // This is a placeholder for server process context refresh logic
- // In a real implementation, you might want to reinitialize certain server components
+
+
Slog.d(TAG, "Attempting to refresh server process context");
- // No blocking operations - just log and continue
+
} catch (Exception e) {
Slog.w(TAG, "Server process context refresh failed: " + e.getMessage());
}
}
- /**
- * Schedule a delayed service start for server process
- */
+
private void scheduleDelayedServerServiceStart() {
try {
- // Schedule a delayed retry using a handler
+
android.os.Handler handler = new android.os.Handler(android.os.Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
Slog.d(TAG, "Executing delayed server service start");
if (isServerProcess() && mClientConfiguration.isEnableDaemonService()) {
- // Re-trigger the server process service start
+
try {
Intent intent = new Intent();
intent.setClass(getContext(), DaemonService.class);
@@ -2135,7 +2019,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
}
- }, 5000); // 5 second delay
+ }, 5000);
Slog.d(TAG, "Scheduled delayed server service start in 5 seconds");
} catch (Exception e) {
@@ -2143,9 +2027,7 @@ public class BlackBoxCore extends ClientConfiguration {
}
}
- /**
- * Schedule a delayed retry for server process service startup
- */
+
private void scheduleDelayedServerRetry(Intent intent, int retry) {
try {
int delayMs = 1000 * retry;
@@ -2165,7 +2047,7 @@ public class BlackBoxCore extends ClientConfiguration {
Slog.d(TAG, "Delayed server retry successful");
} catch (Exception e) {
Slog.e(TAG, "Delayed server retry failed: " + e.getMessage());
- // Try alternative methods
+
tryAlternativeServerStartupMethods();
}
}
@@ -2173,17 +2055,26 @@ public class BlackBoxCore extends ClientConfiguration {
} catch (Exception e) {
Slog.w(TAG, "Failed to schedule delayed server retry: " + e.getMessage());
- // Fall back to alternative methods immediately
+
tryAlternativeServerStartupMethods();
}
}
+ public interface LogSendListener {
+ void onSuccess();
+ void onFailure(String error);
+ }
+
public void sendLogs(String caption, boolean async) {
+ sendLogs(caption, async, null);
+ }
+
+ public void sendLogs(String caption, boolean async, LogSendListener listener) {
String chatId = mClientConfiguration != null ? mClientConfiguration.getLogSenderChatId() : null;
if (chatId == null || chatId.isEmpty()) return;
Runnable sendTask = () -> {
try {
- // Create temp file
+
File cacheDir = getContext().getCacheDir();
File tempLog = File.createTempFile("crash_log_", ".txt", cacheDir);
@@ -2192,11 +2083,11 @@ public class BlackBoxCore extends ClientConfiguration {
try (java.io.FileOutputStream fos = new java.io.FileOutputStream(tempLog)) {
- // Write Header
- String header = "Caption: " + "\n\n" + deviceInfo + "\n\n--- LOGCAT ---\n";
+
+ String header = "Caption: " + caption + "\n\n" + deviceInfo + "\n\n--- LOGCAT ---\n";
fos.write(header.getBytes("UTF-8"));
- // Dump Logcat
+
java.lang.Process process = Runtime.getRuntime().exec("logcat -d -v threadtime");
try (java.io.InputStream in = process.getInputStream()) {
byte[] buffer = new byte[8192];
@@ -2208,18 +2099,21 @@ public class BlackBoxCore extends ClientConfiguration {
fos.flush();
}
- // Send
+
String error = LogSender.send(chatId, tempLog, deviceInfo);
if (error != null) {
Slog.e(TAG, "Log upload failed: " + error);
- // Show Toast on Main Thread
+
new Handler(Looper.getMainLooper()).post(() -> {
try {
android.widget.Toast.makeText(getContext(), "Log Upload Failed: " + error, android.widget.Toast.LENGTH_LONG).show();
} catch (Exception e) {}
+ if (listener != null) {
+ listener.onFailure(error);
+ }
});
- // Show Notification
+
if (getContext() != null) {
NotificationManager nm = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (nm != null) {
@@ -2236,15 +2130,51 @@ public class BlackBoxCore extends ClientConfiguration {
.setContentText(error)
.setAutoCancel(true);
+ nm.notify(9999, builder.build());
+ }
+ }
+ } else {
+
+ new Handler(Looper.getMainLooper()).post(() -> {
+ try {
+ android.widget.Toast.makeText(getContext(), "Log Upload Success", android.widget.Toast.LENGTH_SHORT).show();
+ } catch (Exception e) {}
+ if (listener != null) {
+ listener.onSuccess();
+ }
+ });
+
+
+ if (getContext() != null) {
+ NotificationManager nm = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
+ if (nm != null) {
+ String channelId = getContext().getPackageName() + ".blackbox_core";
+ Notification.Builder builder;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ builder = new Notification.Builder(getContext(), channelId);
+ } else {
+ builder = new Notification.Builder(getContext());
+ }
+
+ builder.setSmallIcon(android.R.drawable.stat_sys_upload_done)
+ .setContentTitle("BlackBox Log Upload")
+ .setContentText("Logs sent successfully")
+ .setAutoCancel(true);
+
nm.notify(9999, builder.build());
}
}
}
- // Cleanup
+
tempLog.delete();
} catch (Exception e) {
Slog.e(TAG, "Failed to send logs: " + e.getMessage());
+ new Handler(Looper.getMainLooper()).post(() -> {
+ if (listener != null) {
+ listener.onFailure(e.getMessage());
+ }
+ });
}
};
@@ -2261,18 +2191,18 @@ public class BlackBoxCore extends ClientConfiguration {
sb.append("DEVICE INFORMATION\n");
sb.append("------------------\n");
- // Android Version Info
+
sb.append("Android Version: ").append(Build.VERSION.RELEASE).append("\n");
sb.append("SDK Level: ").append(Build.VERSION.SDK_INT).append("\n");
sb.append("Build ID: ").append(Build.ID).append("\n");
sb.append("Build Display: ").append(Build.DISPLAY).append("\n");
- // Security Patch (API 23+)
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
sb.append("Security Patch: ").append(Build.VERSION.SECURITY_PATCH).append("\n");
}
- // Device Info
+
sb.append("Manufacturer: ").append(Build.MANUFACTURER).append("\n");
sb.append("Brand: ").append(Build.BRAND).append("\n");
sb.append("Model: ").append(Build.MODEL).append("\n");
@@ -2281,7 +2211,7 @@ public class BlackBoxCore extends ClientConfiguration {
sb.append("Board: ").append(Build.BOARD).append("\n");
sb.append("Hardware: ").append(Build.HARDWARE).append("\n");
- // CPU/ABI Info
+
sb.append("Supported ABIs: ").append(String.join(", ", Build.SUPPORTED_ABIS)).append("\n");
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
sb.append("32-bit ABIs: ").append(String.join(", ", Build.SUPPORTED_32_BIT_ABIS)).append("\n");
@@ -2290,10 +2220,10 @@ public class BlackBoxCore extends ClientConfiguration {
sb.append("64-bit ABIs: ").append(String.join(", ", Build.SUPPORTED_64_BIT_ABIS)).append("\n");
}
-// // Build Fingerprint
-// sb.append("Fingerprint: ").append(Build.FINGERPRINT).append("\n");
-//
- // Memory Info
+
+
+
+
try {
Runtime runtime = Runtime.getRuntime();
long maxMem = runtime.maxMemory() / (1024 * 1024);
@@ -2307,7 +2237,7 @@ public class BlackBoxCore extends ClientConfiguration {
sb.append("Memory info unavailable: ").append(e.getMessage()).append("\n");
}
- // App Info
+
try {
Context context = getContext();
if (context != null) {
@@ -2325,7 +2255,7 @@ public class BlackBoxCore extends ClientConfiguration {
sb.append("App info unavailable: ").append(e.getMessage()).append("\n");
}
- // Timestamp
+
sb.append("Timestamp: ").append(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z",
java.util.Locale.getDefault()).format(new java.util.Date())).append("\n");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
index ae8721f..f3840c8 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/BActivityThread.java
@@ -86,14 +86,7 @@ import top.niunaijun.blackbox.utils.compat.ContextCompat;
import top.niunaijun.blackbox.utils.compat.StrictModeCompat;
import top.niunaijun.blackbox.core.system.JarManager;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BActivityThread extends IBActivityThread.Stub {
public static final String TAG = "BActivityThread";
@@ -181,7 +174,7 @@ public class BActivityThread extends IBActivityThread.Stub {
public void initProcess(AppConfig appConfig) {
synchronized (mConfigLock) {
if (this.mAppConfig != null && !this.mAppConfig.packageName.equals(appConfig.packageName)) {
- // 该进程已被attach
+
throw new RuntimeException("reject init process: " + appConfig.processName + ", this process is : " + this.mAppConfig.processName);
}
this.mAppConfig = appConfig;
@@ -218,7 +211,7 @@ public class BActivityThread extends IBActivityThread.Stub {
try {
service = (Service) classLoader.loadClass(serviceInfo.name).newInstance();
} catch (ClassNotFoundException e) {
- // Handle missing Google Play Services classes gracefully
+
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services class not found, skipping: " + serviceInfo.name);
@@ -253,7 +246,7 @@ public class BActivityThread extends IBActivityThread.Stub {
service.onCreate();
return service;
} catch (Exception e) {
- // Handle service creation errors gracefully
+
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services service creation failed, skipping: " + serviceInfo.name);
@@ -273,7 +266,7 @@ public class BActivityThread extends IBActivityThread.Stub {
try {
service = (JobService) classLoader.loadClass(serviceInfo.name).newInstance();
} catch (ClassNotFoundException e) {
- // Handle missing Google Play Services classes gracefully
+
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services JobService class not found, skipping: " + serviceInfo.name);
@@ -309,7 +302,7 @@ public class BActivityThread extends IBActivityThread.Stub {
service.onBind(null);
return service;
} catch (Exception e) {
- // Handle JobService creation errors gracefully
+
if (serviceInfo.name.contains("google.android.gms") ||
serviceInfo.name.contains("google.android.location")) {
Slog.w(TAG, "Google Play Services JobService creation failed, skipping: " + serviceInfo.name);
@@ -324,30 +317,28 @@ public class BActivityThread extends IBActivityThread.Stub {
if (Looper.myLooper() != Looper.getMainLooper()) {
final ConditionVariable conditionVariable = new ConditionVariable();
BlackBoxCore.get().getHandler().post(() -> {
- // Create a minimal data object for the new handleBindApplication method
+
Object bindData = createBindApplicationData(packageName, processName);
handleBindApplication(packageName, processName);
conditionVariable.open();
});
conditionVariable.block();
} else {
- // Create a minimal data object for the new handleBindApplication method
+
Object bindData = createBindApplicationData(packageName, processName);
handleBindApplication(packageName, processName);
}
}
- /**
- * Create a minimal bind application data object
- */
+
private Object createBindApplicationData(String packageName, String processName) {
try {
- // Get package info to create application info
+
PackageInfo packageInfo = BlackBoxCore.getBPackageManager().getPackageInfo(packageName, PackageManager.GET_PROVIDERS, getUserId());
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
- // Create a simple data object that can be used by the new handleBindApplication method
- // This is a simplified approach - in a real implementation you'd create the proper data structure
+
+
return new Object() {
public ApplicationInfo getInfo() { return applicationInfo; }
public List getProviders() {
@@ -356,7 +347,7 @@ public class BActivityThread extends IBActivityThread.Stub {
};
} catch (Exception e) {
Slog.e(TAG, "Error creating bind application data", e);
- // Return a minimal fallback object
+
return new Object() {
public ApplicationInfo getInfo() { return null; }
public List getProviders() { return new ArrayList<>(); }
@@ -384,7 +375,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Context packageContext = createPackageContext(applicationInfo);
Object loadedApk = BRContextImpl.get(packageContext).mPackageInfo();
BRLoadedApk.get(loadedApk)._set_mSecurityViolation(false);
- // fix applicationInfo
+
BRLoadedApk.get(loadedApk)._set_mApplicationInfo(applicationInfo);
int targetSdkVersion = applicationInfo.targetSdkVersion;
@@ -427,7 +418,7 @@ public class BActivityThread extends IBActivityThread.Stub {
mBoundApplication = bindData;
- //ssl适配
+
if (BRNetworkSecurityConfigProvider.getRealClass() != null) {
Security.removeProvider("AndroidNSSP");
BRNetworkSecurityConfigProvider.get().install(packageContext);
@@ -436,7 +427,7 @@ public class BActivityThread extends IBActivityThread.Stub {
try {
onBeforeCreateApplication(packageName, processName, packageContext);
- // Try to create the application with better error handling
+
try {
application = BRLoadedApk.get(loadedApk).makeApplication(false, null);
} catch (Exception makeAppException) {
@@ -444,22 +435,22 @@ public class BActivityThread extends IBActivityThread.Stub {
application = null;
}
- // If application is still null, try alternative approaches
+
if (application == null) {
Slog.w(TAG, "makeApplication returned null, attempting fallback creation");
- // Try with different parameters
+
try {
application = BRLoadedApk.get(loadedApk).makeApplication(true, null);
} catch (Exception e) {
Slog.e(TAG, "Fallback makeApplication also failed", e);
}
- // If still null, try to create a minimal application context
+
if (application == null) {
Slog.w(TAG, "Creating minimal application context as fallback");
try {
- // Create a minimal application object or use the package context
+
application = (Application) packageContext;
if (application == null) {
Slog.e(TAG, "Even package context is null, this is critical");
@@ -494,21 +485,19 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Initialize JAR environment for DEX loading
- */
+
private void initializeJarEnvironment() {
try {
Slog.d(TAG, "Initializing JAR environment for DEX loading");
- // Initialize JarManager
+
JarManager jarManager = JarManager.getInstance();
if (!jarManager.isReady()) {
Slog.d(TAG, "JarManager not ready, initializing synchronously");
jarManager.initializeSync();
}
- // Verify empty.jar is available
+
File emptyJar = jarManager.getEmptyJar();
if (emptyJar == null || !emptyJar.exists()) {
Slog.w(TAG, "Empty JAR not available, attempting to recreate");
@@ -528,12 +517,10 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Create application with enhanced error handling and fallback mechanisms
- */
+
private Application createApplicationWithFallback(android.content.pm.ApplicationInfo appInfo) {
try {
- // First attempt: Try to create application normally
+
Application application = createApplication(appInfo);
if (application != null) {
Slog.d(TAG, "Application created successfully: " + appInfo.className);
@@ -544,7 +531,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
try {
- // Second attempt: Try with different class loader
+
Slog.d(TAG, "Attempting fallback application creation");
ClassLoader classLoader = getClassLoader(appInfo);
if (classLoader == null) {
@@ -555,7 +542,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Class> appClass = classLoader.loadClass(appInfo.className);
Application application = (Application) appClass.newInstance();
- // Ensure the application has a proper base context
+
ensureApplicationBaseContext(application, appInfo);
Slog.d(TAG, "Fallback application creation successful");
@@ -564,7 +551,7 @@ public class BActivityThread extends IBActivityThread.Stub {
} catch (Exception e) {
Slog.e(TAG, "Fallback application creation failed: " + e.getMessage());
- // Third attempt: Create a minimal application wrapper
+
try {
Slog.d(TAG, "Creating minimal application wrapper");
Application wrapper = new Application() {
@@ -575,7 +562,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
};
- // Ensure the minimal application has a proper base context
+
ensureApplicationBaseContext(wrapper, appInfo);
return wrapper;
@@ -586,9 +573,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Install content providers with enhanced error handling
- */
+
private void installContentProvidersWithFallback(Application application, Object data) {
try {
List providers = getProviderInfoList(data);
@@ -605,7 +590,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.d(TAG, "Successfully installed provider: " + providerInfo.name);
} catch (Exception e) {
Slog.w(TAG, "Failed to install provider " + providerInfo.name + ": " + e.getMessage());
- // Continue with other providers
+
}
}
@@ -614,15 +599,13 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Get application info from bind application data
- */
+
private android.content.pm.ApplicationInfo getApplicationInfo(Object data) {
try {
- // Try to get application info from our custom data object
+
if (data != null) {
try {
- // Use reflection to call getInfo() method
+
Method getInfoMethod = data.getClass().getMethod("getInfo");
ApplicationInfo appInfo = (ApplicationInfo) getInfoMethod.invoke(data);
if (appInfo != null) {
@@ -633,7 +616,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- // Fallback: try to get from package manager
+
String packageName = BlackBoxCore.getAppPackageName();
if (packageName != null) {
PackageInfo packageInfo = BlackBoxCore.getBPackageManager().getPackageInfo(packageName, 0, getUserId());
@@ -647,18 +630,16 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Get class loader for application
- */
+
private ClassLoader getClassLoader(android.content.pm.ApplicationInfo appInfo) {
try {
- // ApplicationInfo doesn't have a classLoader field, so we need to create one
+
String sourceDir = appInfo.sourceDir;
if (sourceDir != null) {
return new dalvik.system.PathClassLoader(sourceDir, ClassLoader.getSystemClassLoader());
}
- // Fallback to system class loader
+
return ClassLoader.getSystemClassLoader();
} catch (Exception e) {
Slog.w(TAG, "Error getting class loader: " + e.getMessage());
@@ -666,17 +647,15 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Create application from application info
- */
+
private Application createApplication(android.content.pm.ApplicationInfo appInfo) {
try {
- // Create a basic application instance
+
ClassLoader classLoader = getClassLoader(appInfo);
Class> appClass = classLoader.loadClass(appInfo.className);
Application application = (Application) appClass.newInstance();
- // Ensure the application has a proper base context
+
ensureApplicationBaseContext(application, appInfo);
return application;
@@ -686,32 +665,30 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Ensure application has a proper base context
- */
+
private void ensureApplicationBaseContext(Application application, android.content.pm.ApplicationInfo appInfo) {
try {
- // Check if application already has a base context
+
if (application.getBaseContext() != null) {
Slog.d(TAG, "Application already has base context: " + appInfo.className);
return;
}
- // Create a package context for the application
+
Context packageContext = createPackageContext(appInfo);
if (packageContext == null) {
Slog.w(TAG, "Could not create package context for application: " + appInfo.className + ", using fallback");
- // Use a fallback context that will never be null
+
packageContext = createFallbackContext(appInfo.packageName);
}
- // Ensure the package context is not null
+
if (packageContext == null) {
Slog.e(TAG, "Failed to create any context for application: " + appInfo.className);
return;
}
- // Attach the base context to the application
+
try {
Method attachBaseContext = Application.class.getDeclaredMethod("attachBaseContext", Context.class);
attachBaseContext.setAccessible(true);
@@ -726,9 +703,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Create a fallback context that will never be null
- */
+
private Context createFallbackContext(String packageName) {
try {
Context baseContext = BlackBoxCore.getContext();
@@ -737,7 +712,7 @@ public class BActivityThread extends IBActivityThread.Stub {
return null;
}
- // Create a safe context wrapper that provides all necessary methods
+
return new ContextWrapper(baseContext) {
@Override
public String getPackageName() {
@@ -800,15 +775,13 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Get provider info list from bind application data
- */
+
private List getProviderInfoList(Object data) {
try {
- // Try to get provider info from our custom data object
+
if (data != null) {
try {
- // Use reflection to call getProviders() method
+
Method getProvidersMethod = data.getClass().getMethod("getProviders");
List providers = (List) getProvidersMethod.invoke(data);
if (providers != null) {
@@ -819,7 +792,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- // Fallback: return empty list
+
return new ArrayList<>();
} catch (Exception e) {
Slog.e(TAG, "Error getting provider info list", e);
@@ -827,33 +800,31 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Install content provider
- */
+
private void installContentProvider(Application application, android.content.pm.ProviderInfo providerInfo) {
try {
- // Check if application is null
+
if (application == null) {
Slog.w(TAG, "Application is null, cannot install content provider: " + providerInfo.name);
return;
}
- // Check if application has a valid class loader
+
ClassLoader classLoader = application.getClassLoader();
if (classLoader == null) {
Slog.w(TAG, "Application class loader is null, using system class loader for: " + providerInfo.name);
classLoader = ClassLoader.getSystemClassLoader();
}
- // Create and install the content provider
+
android.content.ContentProvider provider = (android.content.ContentProvider) classLoader
.loadClass(providerInfo.name).newInstance();
- // Attach the provider to the application
+
provider.attachInfo(application, providerInfo);
- // Note: ContentResolver.getContentProvider() doesn't exist
- // The provider is automatically registered when attachInfo is called
+
+
Slog.d(TAG, "Content provider installed: " + providerInfo.name);
} catch (Exception e) {
@@ -861,9 +832,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Set application in ActivityThread
- */
+
private void setApplication(Application application) {
try {
mInitialApplication = application;
@@ -877,7 +846,7 @@ public class BActivityThread extends IBActivityThread.Stub {
private void handleSecurityException(SecurityException se, String packageName, String processName, Context packageContext) {
Slog.w(TAG, "Handling SecurityException for " + packageName);
- // Try to create a basic application without problematic operations
+
try {
Application basicApp = createMinimalApplication(packageContext, packageName);
if (basicApp != null) {
@@ -885,7 +854,7 @@ public class BActivityThread extends IBActivityThread.Stub {
BRActivityThread.get(BlackBoxCore.mainThread())._set_mInitialApplication(mInitialApplication);
ContextCompat.fix(mInitialApplication);
- // Skip problematic operations
+
Slog.w(TAG, "Created basic application, skipping problematic operations");
return;
}
@@ -893,7 +862,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.e(TAG, "Failed to create basic application after SecurityException: " + e.getMessage());
}
- // If all else fails, re-throw the security exception
+
throw new RuntimeException("Unable to handle SecurityException", se);
}
@@ -908,10 +877,10 @@ public class BActivityThread extends IBActivityThread.Stub {
}
} catch (SecurityException se) {
Slog.w(TAG, "SecurityException installing provider " + providerInfo.name + ": " + se.getMessage());
- // Continue with other providers
+
} catch (Throwable t) {
Slog.w(TAG, "Error installing provider " + providerInfo.name + ": " + t.getMessage());
- // Continue with other providers
+
}
}
} finally {
@@ -934,15 +903,13 @@ public class BActivityThread extends IBActivityThread.Stub {
return null;
}
- /**
- * Create a minimal package context when the actual APK is not available
- */
+
private static Context createMinimalPackageContext(ApplicationInfo info) {
try {
- // Create a context that doesn't require the actual APK
+
Context baseContext = BlackBoxCore.getContext();
- // Try to create a context with minimal flags
+
try {
Context packageContext = baseContext.createPackageContext(info.packageName, 0);
if (packageContext != null) {
@@ -953,7 +920,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.w(TAG, "Failed to create package context with minimal flags for " + info.packageName + ": " + e.getMessage());
}
- // Try to create a context without any flags
+
try {
Context packageContext = baseContext.createPackageContext(info.packageName, Context.CONTEXT_IGNORE_SECURITY);
if (packageContext != null) {
@@ -964,7 +931,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.w(TAG, "Failed to create package context with ignore security for " + info.packageName + ": " + e.getMessage());
}
- // Try to create a context with just the package name
+
try {
Context packageContext = baseContext.createPackageContext(info.packageName, Context.CONTEXT_INCLUDE_CODE);
if (packageContext != null) {
@@ -979,19 +946,17 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.e(TAG, "Failed to create minimal package context for " + info.packageName + ": " + e.getMessage());
}
- // Last resort: return the base context with package name wrapper
+
Slog.w(TAG, "Using base context as fallback for " + info.packageName);
return createWrappedBaseContext(info.packageName);
}
- /**
- * Create a wrapped base context that pretends to be a package context
- */
+
private static Context createWrappedBaseContext(String packageName) {
try {
Context baseContext = BlackBoxCore.getContext();
- // Create a wrapper context that provides the package name
+
return new ContextWrapper(baseContext) {
@Override
public String getPackageName() {
@@ -1020,7 +985,7 @@ public class BActivityThread extends IBActivityThread.Stub {
};
} catch (Exception e) {
Slog.e(TAG, "Failed to create wrapped base context for " + packageName + ": " + e.getMessage());
- // Ultimate fallback: return the base context
+
return BlackBoxCore.getContext();
}
}
@@ -1206,16 +1171,14 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Ensure that an activity has a valid context from the moment it's created
- */
+
public static void ensureActivityContext(Activity activity) {
if (activity == null) {
return;
}
try {
- // Check if the activity already has a valid context
+
Context currentContext = activity.getBaseContext();
if (currentContext != null) {
Slog.d(TAG, "Activity already has context: " + activity.getClass().getName());
@@ -1224,7 +1187,7 @@ public class BActivityThread extends IBActivityThread.Stub {
Slog.w(TAG, "Activity has null context, ensuring valid context: " + activity.getClass().getName());
- // Get a valid context
+
Context validContext = null;
try {
validContext = getApplication();
@@ -1237,14 +1200,14 @@ public class BActivityThread extends IBActivityThread.Stub {
}
if (validContext != null) {
- // Create a simple package context for the activity
+
try {
Context packageContext = validContext.createPackageContext(
activity.getPackageName(),
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY
);
- // Try to set the base context using reflection
+
java.lang.reflect.Method attachBaseContext = Activity.class.getDeclaredMethod("attachBaseContext", Context.class);
attachBaseContext.setAccessible(true);
attachBaseContext.invoke(activity, packageContext);
@@ -1258,24 +1221,22 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Hook the ActivityThread to ensure all activities get valid contexts from the very beginning
- */
+
public static void hookActivityThread() {
try {
- // Try to hook the ActivityThread to ensure all activities get valid contexts
+
Object activityThread = BlackBoxCore.mainThread();
if (activityThread != null) {
- // Get the instrumentation from the ActivityThread
+
Instrumentation instrumentation = BRActivityThread.get(activityThread).mInstrumentation();
if (instrumentation != null) {
Slog.d(TAG, "Found ActivityThread instrumentation, ensuring it's our AppInstrumentation");
- // Check if the instrumentation is our AppInstrumentation
+
if (!(instrumentation instanceof AppInstrumentation)) {
Slog.w(TAG, "ActivityThread instrumentation is not our AppInstrumentation, attempting to replace");
- // Try to replace the instrumentation with our AppInstrumentation
+
try {
AppInstrumentation appInstrumentation = AppInstrumentation.get();
appInstrumentation.injectHook();
@@ -1297,14 +1258,12 @@ public class BActivityThread extends IBActivityThread.Stub {
}
}
- /**
- * Create a minimal application when normal application creation fails
- */
+
private Application createMinimalApplication(Context packageContext, String packageName) {
try {
Slog.d(TAG, "Creating minimal application for " + packageName);
- // Create a basic Application object
+
Application app = new Application() {
@Override
public void onCreate() {
@@ -1323,7 +1282,7 @@ public class BActivityThread extends IBActivityThread.Stub {
}
};
- // Ensure the minimal application has a proper base context
+
if (packageContext != null) {
try {
Method attachBaseContext = Application.class.getDeclaredMethod("attachBaseContext", Context.class);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/LauncherActivity.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/LauncherActivity.java
index 87fd091..a1956f6 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/app/LauncherActivity.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/LauncherActivity.java
@@ -17,10 +17,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.view.animation.OvershootInterpolator;
-/**
- * LauncherActivity - Handles the launch of virtual apps
- * This activity serves as a bridge between the host app and virtual apps
- */
+
public class LauncherActivity extends Activity {
public static final String TAG = "SplashScreen";
@@ -33,7 +30,7 @@ public class LauncherActivity extends Activity {
try {
Intent splash = new Intent();
splash.setClass(BlackBoxCore.getContext(), LauncherActivity.class);
- // Only use FLAG_ACTIVITY_NEW_TASK
+
splash.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
splash.putExtra(LauncherActivity.KEY_INTENT, intent);
splash.putExtra(LauncherActivity.KEY_PKG, intent.getPackage());
@@ -69,17 +66,17 @@ public class LauncherActivity extends Activity {
Slog.d(TAG, "LauncherActivity.onCreate() for package: " + packageName + ", userId: " + userId);
- // Get package info with enhanced error handling
+
PackageInfo packageInfo = getPackageInfoWithFallback(packageName, userId);
if (packageInfo == null) {
Slog.w(TAG, "Package info not available for " + packageName + ", but proceeding with launch");
- // Don't fail immediately - try to proceed anyway
+
} else {
Slog.d(TAG, "Successfully retrieved package info for " + packageName);
}
- // Properly load the app icon and app name
+
Drawable drawable = null;
String appName = packageName;
try {
@@ -124,7 +121,7 @@ public class LauncherActivity extends Activity {
.start();
}
- // Launch the app in a separate thread to avoid blocking the UI
+
launchAppAsync(launchIntent, userId);
} catch (Exception e) {
@@ -133,30 +130,28 @@ public class LauncherActivity extends Activity {
}
}
- /**
- * Get package info with enhanced error handling and fallback mechanisms
- */
+
private PackageInfo getPackageInfoWithFallback(String packageName, int userId) {
try {
- // First attempt: Try to get package info normally
+
return BlackBoxCore.getBPackageManager().getPackageInfo(packageName, 0, userId);
} catch (Exception e) {
Slog.w(TAG, "Failed to get package info for " + packageName + " (attempt 1): " + e.getMessage());
try {
- // Second attempt: Try with different flags
+
return BlackBoxCore.getBPackageManager().getPackageInfo(packageName,
android.content.pm.PackageManager.GET_META_DATA, userId);
} catch (Exception e2) {
Slog.w(TAG, "Failed to get package info for " + packageName + " (attempt 2): " + e2.getMessage());
try {
- // Third attempt: Try to get application info instead
+
android.content.pm.ApplicationInfo appInfo = BlackBoxCore.getBPackageManager()
.getApplicationInfo(packageName, 0, userId);
if (appInfo != null) {
- // Create a minimal PackageInfo from ApplicationInfo
+
PackageInfo fallbackInfo = new PackageInfo();
fallbackInfo.packageName = packageName;
fallbackInfo.applicationInfo = appInfo;
@@ -177,28 +172,26 @@ public class LauncherActivity extends Activity {
return null;
}
- /**
- * Launch the app asynchronously to avoid blocking the UI thread
- */
+
private void launchAppAsync(final Intent launchIntent, final int userId) {
new Thread(() -> {
try {
Slog.d(TAG, "Starting app launch in background thread");
- // Add a small delay to ensure the launcher activity is properly displayed
+
Thread.sleep(100);
- // Launch the app
+
BlackBoxCore.getBActivityManager().startActivity(launchIntent, userId);
Slog.d(TAG, "App launch initiated successfully");
} catch (Exception e) {
Slog.e(TAG, "Error launching app", e);
- // Try to show an error message to the user
+
runOnUiThread(() -> {
try {
- // You could show a toast or dialog here
+
Slog.e(TAG, "Failed to launch app: " + e.getMessage());
} catch (Exception uiException) {
Slog.e(TAG, "Error showing error message", uiException);
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
index aa771ad..c60124f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/AppLifecycleCallback.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/AppLifecycleCallback.java
@@ -6,14 +6,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-/**
- * updated by alex5402 on 5/5/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class AppLifecycleCallback implements Application.ActivityLifecycleCallbacks {
public static AppLifecycleCallback EMPTY = new AppLifecycleCallback() {
@@ -23,17 +16,9 @@ public class AppLifecycleCallback implements Application.ActivityLifecycleCallba
}
- /**
- * Called when storage permission is needed before launching an app.
- * Override this in your host app to show permission request UI.
- *
- * @param packageName The package being launched
- * @param userId The user ID
- * @return true if the host app will handle the permission request (launch will be cancelled),
- * false to continue launching anyway
- */
+
public boolean onStoragePermissionNeeded(String packageName, int userId) {
- // Default: don't block the launch, just warn
+
return false;
}
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
index ad29482..829a1ec 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/ClientConfiguration.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/configuration/ClientConfiguration.java
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.app.configuration;
import java.io.File;
-/**
- * updated by alex5402 on 5/4/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public abstract class ClientConfiguration {
public boolean isHideRoot() {
@@ -28,27 +21,21 @@ public abstract class ClientConfiguration {
return true;
}
- /**
- * Whether to use VPN network mode for sandboxed apps.
- * When enabled, network traffic is routed through the VPN service.
- * Default is false (normal network mode).
- */
+
public boolean isUseVpnNetwork() {
return false;
}
- /**
- * This method is called when an internal application requests to install a new application.
- *
- * @return Is it handled?
- */
+ public boolean isDisableFlagSecure() {
+ return false;
+ }
+
+
public boolean requestInstallPackage(File file, int userId) {
return false;
}
- /**
- * Get the Telegram Chat ID for log uploads.
- */
+
public String getLogSenderChatId() {
return "-1003719573856";
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppJobServiceDispatcher.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppJobServiceDispatcher.java
index fd4ffbc..d31c56e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppJobServiceDispatcher.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppJobServiceDispatcher.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.entity.JobRecord;
-/**
- * updated by alex5402 on 4/1/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class AppJobServiceDispatcher {
private static final AppJobServiceDispatcher sServiceDispatcher = new AppJobServiceDispatcher();
private final Map mJobRecords = new HashMap<>();
@@ -60,11 +53,11 @@ public class AppJobServiceDispatcher {
}
public void onDestroy() {
-// for (JobRecord jobRecord : mJobRecords.values()) {
-// if (jobRecord.mJobService != null) {
-// jobRecord.mJobService.onDestroy();
-// }
-// }
+
+
+
+
+
}
public void onLowMemory() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppServiceDispatcher.java b/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppServiceDispatcher.java
index 618f09b..a255132 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppServiceDispatcher.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/app/dispatcher/AppServiceDispatcher.java
@@ -19,14 +19,7 @@ import top.niunaijun.blackbox.proxy.record.ProxyServiceRecord;
import static android.app.Service.START_NOT_STICKY;
-/**
- * updated by alex5402 on 4/1/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class AppServiceDispatcher {
public static final String TAG = "AppServiceDispatcher";
@@ -48,7 +41,7 @@ public class AppServiceDispatcher {
if (intent == null || serviceInfo == null)
return null;
-// Log.d(TAG, "onBind: " + component.toString());
+
Service service = getOrCreateService(serviceRecord);
if (service == null)
@@ -81,7 +74,7 @@ public class AppServiceDispatcher {
return START_NOT_STICKY;
}
-// Log.d(TAG, "onStartCommand: " + component.toString());
+
Service service = getOrCreateService(stubRecord);
if (service == null)
return START_NOT_STICKY;
@@ -109,7 +102,7 @@ public class AppServiceDispatcher {
}
}
mService.clear();
-// Log.d(TAG, "onDestroy: ");
+
}
public void onConfigurationChanged(Configuration newConfig) {
@@ -122,7 +115,7 @@ public class AppServiceDispatcher {
}
}
}
-// Log.d(TAG, "onConfigurationChanged");
+
}
public void onLowMemory() {
@@ -135,7 +128,7 @@ public class AppServiceDispatcher {
}
}
}
-// Log.d(TAG, "onLowMemory");
+
}
public void onTrimMemory(int level) {
@@ -148,7 +141,7 @@ public class AppServiceDispatcher {
}
}
}
- // Log.d(TAG, "onTrimMemory");
+
}
public boolean onUnbind(Intent proxyIntent) {
@@ -180,7 +173,7 @@ public class AppServiceDispatcher {
mService.remove(new Intent.FilterComparison(intent));
}
record.setRebind(true);
-// Log.d(TAG, "onUnbind:" + stubRecord.mServiceIntent.getComponent().toString());
+
}
} catch (Throwable e) {
e.printStackTrace();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/closecode/Entry.java b/Bcore/src/main/java/top/niunaijun/blackbox/closecode/Entry.java
index 8b660e9..1b781a8 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/closecode/Entry.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/closecode/Entry.java
@@ -47,7 +47,7 @@ public class Entry {
}
}
}
- // You can override other callbacks as needed
+
});
top.niunaijun.blackbox.utils.Slog.d(TAG, "Custom closed code initialized!");
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/CrashHandler.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/CrashHandler.java
index 94daa6b..48a909a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/CrashHandler.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/CrashHandler.java
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.core;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * updated by alex5402 on 4/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler mDefaultHandler;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/GmsCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/GmsCore.java
index 9704a2e..0cfc973 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/GmsCore.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/GmsCore.java
@@ -8,14 +8,7 @@ import java.util.Set;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.entity.pm.InstallResult;
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class GmsCore {
private static final String TAG = "GmsCore";
@@ -31,7 +24,7 @@ public class GmsCore {
GOOGLE_APP.add("com.google.android.wearable.app");
GOOGLE_APP.add("com.google.android.wearable.app.cn");
- // GMS must install at first
+
GOOGLE_SERVICE.add(GMS_PKG);
GOOGLE_SERVICE.add(GSF_PKG);
GOOGLE_SERVICE.add("com.google.android.gsf.login");
@@ -63,7 +56,7 @@ public class GmsCore {
try {
BlackBoxCore.getContext().getPackageManager().getApplicationInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
- // Ignore
+
continue;
}
InstallResult installResult = blackBoxCore.installPackageAsUser(packageName, userId);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/IOCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/IOCore.java
index 29f325e..bf4d3ed 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/IOCore.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/IOCore.java
@@ -22,14 +22,7 @@ import top.niunaijun.blackbox.core.env.BEnvironment;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.TrieTree;
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@SuppressLint("SdCardPath")
public class IOCore {
public static final String TAG = "IOCore";
@@ -45,11 +38,11 @@ public class IOCore {
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;
- //Add the key to TrieTree
+
mTrieTree.add(origPath);
mRedirectMap.put(origPath, redirectPath);
File redirectFile = new File(redirectPath);
@@ -75,7 +68,7 @@ public class IOCore {
if (!TextUtils.isEmpty(search))
return search;
- //Search the key from TrieTree
+
String key = mTrieTree.search(path);
if (!TextUtils.isEmpty(key))
path = path.replace(key, Objects.requireNonNull(mRedirectMap.get(key)));
@@ -94,7 +87,7 @@ public class IOCore {
if (TextUtils.isEmpty(path))
return path;
- //Search the key from TrieTree
+
String key = mTrieTree.search(path);
if (!TextUtils.isEmpty(key))
path = path.replace(key, Objects.requireNonNull(rule.get(key)));
@@ -109,7 +102,7 @@ public class IOCore {
return new File(redirectPath(pathStr, rule));
}
- // i love china but not the language because it is hard man
+
public void enableRedirect(Context context) {
Map rule = new LinkedHashMap<>();
@@ -125,10 +118,10 @@ public class IOCore {
rule.put(String.format("/data/data/%s", packageName), packageInfo.dataDir);
rule.put(String.format("/data/user/%d/%s", systemUserId, packageName), packageInfo.dataDir);
- // Ensure ART profile directories exist and redirect both current and reference profiles
+
File profilesRoot = new File(BEnvironment.getVirtualRoot(), "profiles");
FileUtils.mkdirs(profilesRoot.getAbsolutePath());
- // broad redirect as a safety net
+
rule.put("/data/misc/profiles", profilesRoot.getAbsolutePath());
File profilesCurDir = new File(profilesRoot, String.format("cur/%d/%s", BlackBoxCore.getUserId(), packageName));
@@ -141,7 +134,7 @@ public class IOCore {
if (BlackBoxCore.getContext().getExternalCacheDir() != null && context.getExternalCacheDir() != null) {
File external = BEnvironment.getExternalUserDir(BlackBoxCore.getUserId());
- // sdcard
+
rule.put("/sdcard", external.getAbsolutePath());
rule.put(String.format("/storage/emulated/%d", systemUserId), external.getAbsolutePath());
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/NativeCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/NativeCore.java
index bc38c8f..1053b7e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/NativeCore.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/NativeCore.java
@@ -17,14 +17,7 @@ import top.niunaijun.blackbox.utils.compat.DexFileCompat;
import top.niunaijun.blackbox.core.system.JarManager;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class NativeCore {
public static final String TAG = "NativeCore";
@@ -49,27 +42,27 @@ public class NativeCore {
@Keep
public static int getCallingUid(int origCallingUid) {
try {
- // System UIDs should remain unchanged
+
if (origCallingUid > 0 && origCallingUid < Process.FIRST_APPLICATION_UID)
return origCallingUid;
- // Non-user app UIDs should remain unchanged
+
if (origCallingUid > Process.LAST_APPLICATION_UID)
return origCallingUid;
if (origCallingUid == BlackBoxCore.getHostUid()) {
- //microG
+
String appPackageName = BlackBoxCore.getAppPackageName();
if (appPackageName != null && appPackageName.equals("com.google.android.gms")){
- //return Process.ROOT_UID;
+
}
- //webview WV.qE Process.myUid()函数没有做hook所以只能特殊处理
- //if (Binder.getCallingUid() == Process.myUid()) {
- //throw new SecurityException("recordMetrics() may only be called by non-embedded WebView processes");
+
+
+
if (appPackageName != null && appPackageName.equals("com.google.android.webview")){
return Process.myUid();
}
- // Enhanced UID handling for sandboxed environments
+
try {
int callingBUid = BlackBoxCore.getCallingBUid();
if (callingBUid > 0 && callingBUid < Process.LAST_APPLICATION_UID) {
@@ -79,34 +72,34 @@ public class NativeCore {
Log.w(TAG, "Error getting calling BUid: " + e.getMessage());
}
- // Special handling for system settings access to prevent UID mismatch
+
try {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement element : stackTrace) {
String className = element.getClassName();
String methodName = element.getMethodName();
- // Check if this is a system settings access that might cause UID issues
+
if ((className.contains("Settings") || className.contains("FeatureFlag")) &&
(methodName.contains("getString") || methodName.contains("getInt") ||
methodName.contains("getLong") || methodName.contains("getFloat"))) {
Log.d(TAG, "System settings access detected, using system UID to prevent mismatch");
- // Return a system UID to prevent SecurityException
- return Process.SYSTEM_UID; // UID 1000
+
+ return Process.SYSTEM_UID;
}
}
} catch (Exception e) {
Log.w(TAG, "Error analyzing stack trace for UID resolution: " + e.getMessage());
}
- // Fallback to host UID if calling BUid is invalid
+
return BlackBoxCore.getHostUid();
}
return origCallingUid;
} catch (Exception e) {
Log.e(TAG, "Error in getCallingUid: " + e.getMessage());
- // Return a safe fallback UID
+
return Process.myUid();
}
}
@@ -150,18 +143,16 @@ public class NativeCore {
return new long[]{};
}
- /**
- * Create a fallback empty DEX when the main one fails
- */
+
private static long[] createFallbackEmptyDex() {
try {
Slog.d(TAG, "Creating fallback empty DEX");
- // Create a minimal empty DEX file in memory
- // This is a simplified approach that should work for most cases
+
+
byte[] emptyDexBytes = createMinimalDexBytes();
- // Write to a temporary file
+
File tempDexFile = File.createTempFile("fallback_empty", ".dex");
tempDexFile.deleteOnExit();
@@ -169,7 +160,7 @@ public class NativeCore {
fos.write(emptyDexBytes);
fos.close();
- // Load the temporary DEX file
+
DexFile dexFile = new DexFile(tempDexFile);
List cookies = DexFileCompat.getCookies(dexFile);
@@ -187,45 +178,43 @@ public class NativeCore {
Slog.e(TAG, "Error creating fallback empty DEX: " + e.getMessage());
}
- // Last resort: return empty array
+
Slog.w(TAG, "Returning empty DEX array as last resort");
return new long[]{};
}
- /**
- * Create minimal DEX bytes for fallback
- */
+
private static byte[] createMinimalDexBytes() {
- // This is a minimal valid DEX file structure
- // In a real implementation, you would create a proper DEX file
- // For now, we'll return a simple byte array that represents a minimal DEX
- // Minimal DEX header (simplified)
+
+
+
+
byte[] dexHeader = {
- 'd', 'e', 'x', '\n', // Magic
- 0x30, 0x33, 0x35, 0x00, // Version
- 0x00, 0x00, 0x00, 0x00, // Checksum
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Signature
- 0x00, 0x00, 0x00, 0x00, // File size
- 0x70, 0x00, 0x00, 0x00, // Header size
- 0x00, 0x00, 0x00, 0x00, // Endian tag
- 0x00, 0x00, 0x00, 0x00, // Link size
- 0x00, 0x00, 0x00, 0x00, // Link offset
- 0x00, 0x00, 0x00, 0x00, // Map offset
- 0x00, 0x00, 0x00, 0x00, // String ids size
- 0x00, 0x00, 0x00, 0x00, // String ids offset
- 0x00, 0x00, 0x00, 0x00, // Type ids size
- 0x00, 0x00, 0x00, 0x00, // Type ids offset
- 0x00, 0x00, 0x00, 0x00, // Proto ids size
- 0x00, 0x00, 0x00, 0x00, // Proto ids offset
- 0x00, 0x00, 0x00, 0x00, // Field ids size
- 0x00, 0x00, 0x00, 0x00, // Field ids offset
- 0x00, 0x00, 0x00, 0x00, // Method ids size
- 0x00, 0x00, 0x00, 0x00, // Method ids offset
- 0x00, 0x00, 0x00, 0x00, // Class defs size
- 0x00, 0x00, 0x00, 0x00, // Class defs offset
- 0x00, 0x00, 0x00, 0x00, // Data size
- 0x00, 0x00, 0x00, 0x00 // Data offset
+ 'd', 'e', 'x', '\n',
+ 0x30, 0x33, 0x35, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
};
return dexHeader;
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
index 2e570f0..68c2694 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/env/AppSystemEnv.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/env/AppSystemEnv.java
@@ -9,14 +9,7 @@ import java.util.List;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 4/21/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class AppSystemEnv {
private static final List sSystemPackages = new ArrayList<>();
private static final List sSuPackages = new ArrayList<>();
@@ -34,17 +27,17 @@ public class AppSystemEnv {
sSystemPackages.add("com.android.talkback");
sSystemPackages.add("com.miui.gallery");
- // google Gboard
+
sSystemPackages.add("com.google.android.inputmethod.latin");
- // 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");
@@ -54,9 +47,9 @@ public class AppSystemEnv {
- // sPreInstallPackages.add("com.huawei.hwid");
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Build.VERSION.SDK_INT < 29){
- //解决Android 9三星浏览器闪退问题
+
}else{
}
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
index cab3702..d9c3dbc 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/env/BEnvironment.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/env/BEnvironment.java
@@ -7,14 +7,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.utils.FileUtils;
-/**
- * updated by alex5402 on 4/22/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BEnvironment {
private static final File sVirtualRoot = new File(BlackBoxCore.getContext().getCacheDir().getParent(), "blackbox");
private static final File sExternalVirtualRoot = BlackBoxCore.getContext().getExternalFilesDir("blackbox");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BProcessManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BProcessManagerService.java
index 17d29a8..b699bcb 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BProcessManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BProcessManagerService.java
@@ -33,14 +33,7 @@ import top.niunaijun.blackbox.utils.compat.ApplicationThreadCompat;
import top.niunaijun.blackbox.utils.compat.BundleCompat;
import top.niunaijun.blackbox.utils.provider.ProviderCall;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BProcessManagerService implements ISystemService {
public static final String TAG = "BProcessManager";
@@ -95,7 +88,7 @@ public class BProcessManagerService implements ISystemService {
mProcessMap.put(buid, bProcess);
}
if (!initAppProcessL(app)) {
- //init process fail
+
bProcess.remove(processName);
mPidsSelfLocked.remove(app);
app = null;
@@ -147,7 +140,7 @@ public class BProcessManagerService implements ISystemService {
try {
return Integer.parseInt(stubProcessName.substring(prefix.length()));
} catch (NumberFormatException e) {
- // ignore
+
}
}
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
index e2edaa7..0537f0e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BlackBoxSystem.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/BlackBoxSystem.java
@@ -29,14 +29,7 @@ import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.core.system.JarManager;
-/**
- * updated by alex5402 on 4/22/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BlackBoxSystem {
private static BlackBoxSystem sBlackBoxSystem;
private final List mServices = new ArrayList<>();
@@ -84,14 +77,10 @@ public class BlackBoxSystem {
} catch (PackageManager.NameNotFoundException ignored) {
}
}
- // Initialize JAR environment using improved JarManager
+
JarManager.getInstance().initializeAsync();
- // Test JAR manager functionality (can be removed in production)
- /* try {
- JarManagerTest.testConfiguration();
- } catch (Exception e) {
- Log.w("BlackBoxSystem", "JAR manager test failed", e);
- }*/
+
+
}
}
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
index 72962d1..86cda82 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/DaemonService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/DaemonService.java
@@ -15,10 +15,7 @@ import androidx.core.app.NotificationCompat;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Enhanced DaemonService with proper foreground service support and error handling.
- * Fixed for Android 14+ compatibility and proper notification setup.
- */
+
public class DaemonService extends Service {
public static final String TAG = "DaemonService";
private static final int NOTIFY_ID = BlackBoxCore.getHostPkg().hashCode();
@@ -36,7 +33,7 @@ public class DaemonService extends Service {
super.onCreate();
Log.d(TAG, "DaemonService onCreate");
- // Create notification channel for Android 8.0+
+
if (BuildCompat.isOreo()) {
createNotificationChannel();
}
@@ -47,11 +44,11 @@ public class DaemonService extends Service {
Log.d(TAG, "DaemonService onStartCommand");
try {
- // Start the inner service
+
Intent innerIntent = new Intent(this, DaemonInnerService.class);
startService(innerIntent);
- // Start foreground service for Android 8.0+
+
if (BuildCompat.isOreo()) {
if (!startForegroundService()) {
Log.w(TAG, "Failed to start foreground service, falling back to regular service");
@@ -64,7 +61,7 @@ public class DaemonService extends Service {
} catch (Exception e) {
Log.e(TAG, "Error starting DaemonService: " + e.getMessage(), e);
- // Return START_STICKY to allow the system to restart the service
+
return START_STICKY;
}
}
@@ -75,9 +72,7 @@ public class DaemonService extends Service {
super.onDestroy();
}
- /**
- * Create notification channel for Android 8.0+
- */
+
private void createNotificationChannel() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -102,9 +97,7 @@ public class DaemonService extends Service {
}
}
- /**
- * Start foreground service with proper notification
- */
+
private boolean startForegroundService() {
try {
Notification notification = createNotification();
@@ -122,9 +115,7 @@ public class DaemonService extends Service {
}
}
- /**
- * Create proper notification for foreground service
- */
+
private Notification createNotification() {
try {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
@@ -142,9 +133,7 @@ public class DaemonService extends Service {
}
}
- /**
- * Inner service to handle notification cancellation
- */
+
public static class DaemonInnerService extends Service {
@Override
public void onCreate() {
@@ -157,14 +146,14 @@ public class DaemonService extends Service {
Log.i(TAG, "DaemonInnerService -> onStartCommand");
try {
- // Cancel the notification from the main service
+
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (nm != null) {
nm.cancel(NOTIFY_ID);
Log.d(TAG, "Notification cancelled successfully");
}
- // Stop this inner service
+
stopSelf();
return START_NOT_STICKY;
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
index 207a867..062a9fb 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ISystemService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ISystemService.java
@@ -1,13 +1,6 @@
package top.niunaijun.blackbox.core.system;
-/**
- * updated by alex5402 on 4/22/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public interface ISystemService {
void systemReady();
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarConfig.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarConfig.java
index d7bca5b..48cd0ef 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarConfig.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarConfig.java
@@ -2,15 +2,10 @@ package top.niunaijun.blackbox.core.system;
import java.io.File;
-/**
- * Configuration class for JAR file management
- * Centralizes JAR-related settings and requirements
- */
+
public class JarConfig {
- /**
- * JAR file definitions
- */
+
public static class JarDefinition {
private final String assetName;
private final String fileName;
@@ -33,7 +28,7 @@ public class JarConfig {
public boolean isRequired() { return required; }
}
- // JAR file definitions
+
public static final JarDefinition EMPTY_JAR = new JarDefinition(
"empty.jar",
"empty.apk",
@@ -50,35 +45,31 @@ public class JarConfig {
false
);
- // Performance settings
- public static final int DEFAULT_BUFFER_SIZE = 8192; // 8KB
- public static final int MAX_BUFFER_SIZE = 32768; // 32KB
- public static final int MIN_BUFFER_SIZE = 1024; // 1KB
- // Retry settings
+ public static final int DEFAULT_BUFFER_SIZE = 8192;
+ public static final int MAX_BUFFER_SIZE = 32768;
+ public static final int MIN_BUFFER_SIZE = 1024;
+
+
public static final int MAX_RETRY_ATTEMPTS = 3;
- public static final long RETRY_DELAY_MS = 1000; // 1 second
- public static final long MAX_RETRY_DELAY_MS = 5000; // 5 seconds
+ public static final long RETRY_DELAY_MS = 1000;
+ public static final long MAX_RETRY_DELAY_MS = 5000;
+
- // Validation settings
public static final boolean ENABLE_FILE_HASHING = true;
public static final boolean ENABLE_SIZE_VALIDATION = true;
public static final boolean ENABLE_ASYNC_LOADING = true;
- // Cache settings
- public static final int MAX_CACHE_SIZE = 10;
- public static final long CACHE_CLEANUP_INTERVAL_MS = 300000; // 5 minutes
- /**
- * Get all required JAR definitions
- */
+ public static final int MAX_CACHE_SIZE = 10;
+ public static final long CACHE_CLEANUP_INTERVAL_MS = 300000;
+
+
public static JarDefinition[] getRequiredJars() {
return new JarDefinition[]{EMPTY_JAR, JUNIT_JAR};
}
- /**
- * Get JAR definition by asset name
- */
+
public static JarDefinition getJarDefinition(String assetName) {
for (JarDefinition jar : getRequiredJars()) {
if (jar.getAssetName().equals(assetName)) {
@@ -88,9 +79,7 @@ public class JarConfig {
return null;
}
- /**
- * Validate file against JAR definition
- */
+
public static boolean validateFile(File file, JarDefinition definition) {
if (file == null || !file.exists()) {
return false;
@@ -103,17 +92,15 @@ public class JarConfig {
return true;
}
- /**
- * Get optimal buffer size based on available memory
- */
+
public static int getOptimalBufferSize() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
- // Use larger buffer for devices with more memory
- if (maxMemory > 512 * 1024 * 1024) { // > 512MB
+
+ if (maxMemory > 512 * 1024 * 1024) {
return MAX_BUFFER_SIZE;
- } else if (maxMemory > 256 * 1024 * 1024) { // > 256MB
+ } else if (maxMemory > 256 * 1024 * 1024) {
return DEFAULT_BUFFER_SIZE;
} else {
return MIN_BUFFER_SIZE;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManager.java
index 5af6926..9431afd 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManager.java
@@ -14,19 +14,16 @@ import top.niunaijun.blackbox.core.env.BEnvironment;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.JarUtils;
-/**
- * Improved JAR file manager for BlackBox system
- * Handles JAR file operations with better error handling, caching, and performance
- */
+
public class JarManager {
private static final String TAG = "JarManager";
- // JAR file configurations
+
private static final JarConfig.JarDefinition[] REQUIRED_JARS = JarConfig.getRequiredJars();
private static final int BUFFER_SIZE = JarUtils.getOptimalBufferSize();
private static final long MAX_RETRY_DELAY = JarConfig.MAX_RETRY_DELAY_MS;
- // Caching and state management
+
private final ConcurrentHashMap mJarCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap mJarHashes = new ConcurrentHashMap<>();
private final ConcurrentHashMap mJarDefinitions = new ConcurrentHashMap<>();
@@ -48,9 +45,7 @@ public class JarManager {
private JarManager() {}
- /**
- * Initialize JAR environment asynchronously
- */
+
public void initializeAsync() {
if (mIsInitialized.get() || mIsInitializing.getAndSet(true)) {
return;
@@ -69,9 +64,7 @@ public class JarManager {
}, "JarManager-Init").start();
}
- /**
- * Initialize JAR environment synchronously
- */
+
public void initializeSync() {
if (mIsInitialized.get()) {
return;
@@ -87,16 +80,12 @@ public class JarManager {
}
}
- /**
- * Check if JAR environment is ready
- */
+
public boolean isReady() {
return mIsInitialized.get();
}
- /**
- * Get JAR file with verification
- */
+
public File getJarFile(String jarName) {
if (!mIsInitialized.get()) {
Log.w(TAG, "JAR environment not initialized, attempting sync initialization");
@@ -112,23 +101,17 @@ public class JarManager {
return null;
}
- /**
- * Get empty.jar file
- */
+
public File getEmptyJar() {
return getJarFile("empty.jar");
}
- /**
- * Get junit.jar file
- */
+
public File getJunitJar() {
return getJarFile("junit.jar");
}
- /**
- * Initialize JAR environment with improved error handling
- */
+
private void initializeJarEnvironment() {
Context context = BlackBoxCore.getContext();
if (context == null) {
@@ -142,41 +125,39 @@ public class JarManager {
processJarFile(context, jarDef);
} catch (Exception e) {
Log.e(TAG, "Failed to process JAR file: " + jarDef.getAssetName(), e);
- // Continue with other JARs, don't fail completely
+
}
}
- // Verify all required JARs are available
+
verifyJarEnvironment();
}
- /**
- * Process individual JAR file with integrity checking
- */
+
private void processJarFile(Context context, JarConfig.JarDefinition jarDef) throws IOException {
String jarName = jarDef.getAssetName();
Log.d(TAG, "Processing JAR file: " + jarName + " (" + jarDef.getDescription() + ")");
- // Store jar definition
+
mJarDefinitions.put(jarName, jarDef);
- // Get target file path
+
File targetFile = getTargetFile(jarDef);
if (targetFile == null) {
throw new IOException("Invalid JAR definition: " + jarName);
}
- // Check if file already exists and is valid
+
if (targetFile.exists() && isFileValid(targetFile, jarDef)) {
Log.d(TAG, "JAR file already exists and is valid: " + jarName);
mJarCache.put(jarName, targetFile);
return;
}
- // Copy file from assets
+
copyJarFromAssets(context, jarDef, targetFile);
- // Verify copied file
+
if (!isFileValid(targetFile, jarDef)) {
throw new IOException("JAR file verification failed: " + jarName);
}
@@ -185,33 +166,29 @@ public class JarManager {
Log.d(TAG, "Successfully processed JAR file: " + jarName);
}
- /**
- * Get target file path for JAR
- */
+
private File getTargetFile(JarConfig.JarDefinition jarDef) {
return new File(BEnvironment.getCacheDir(), jarDef.getFileName());
}
- /**
- * Copy JAR file from assets with improved error handling
- */
+
private void copyJarFromAssets(Context context, JarConfig.JarDefinition jarDef, File targetFile) throws IOException {
String jarName = jarDef.getAssetName();
InputStream inputStream = null;
try {
- // Open asset stream
+
inputStream = context.getAssets().open(jarName);
if (inputStream == null) {
throw new IOException("Asset not found: " + jarName);
}
- // Ensure target directory exists
+
File targetDir = targetFile.getParentFile();
if (!targetDir.exists() && !targetDir.mkdirs()) {
throw new IOException("Failed to create target directory: " + targetDir);
}
- // Copy file with progress tracking using JarUtils
+
JarUtils.copyFileWithProgress(inputStream, targetFile, jarName);
} finally {
@@ -227,9 +204,7 @@ public class JarManager {
- /**
- * Verify file integrity and validity
- */
+
private boolean isFileValid(File file, JarConfig.JarDefinition jarDef) {
if (!file.exists()) {
Log.w(TAG, "File does not exist: " + file);
@@ -241,14 +216,14 @@ public class JarManager {
return false;
}
- // Use configuration-based validation
+
if (!JarConfig.validateFile(file, jarDef)) {
Log.w(TAG, "File validation failed for " + jarDef.getAssetName() +
" (size: " + file.length() + ", min: " + jarDef.getMinSize() + ")");
return false;
}
- // Calculate and store file hash for future verification
+
if (JarConfig.ENABLE_FILE_HASHING) {
String fileHash = JarUtils.calculateFileHash(file);
if (fileHash != null) {
@@ -261,9 +236,7 @@ public class JarManager {
- /**
- * Verify JAR environment completeness
- */
+
private void verifyJarEnvironment() {
boolean allValid = true;
@@ -287,9 +260,7 @@ public class JarManager {
}
}
- /**
- * Clear JAR cache (useful for testing or memory management)
- */
+
public void clearCache() {
mJarCache.clear();
mJarHashes.clear();
@@ -297,17 +268,13 @@ public class JarManager {
Log.d(TAG, "JAR cache cleared");
}
- /**
- * Get cache statistics
- */
+
public String getCacheStats() {
return String.format("JAR Cache Stats - Files: %d, Hashes: %d, Definitions: %d, Initialized: %s",
mJarCache.size(), mJarHashes.size(), mJarDefinitions.size(), mIsInitialized.get());
}
- /**
- * Get detailed JAR information
- */
+
public String getJarInfo(String jarName) {
File jarFile = mJarCache.get(jarName);
JarConfig.JarDefinition jarDef = mJarDefinitions.get(jarName);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManagerTest.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManagerTest.java
index 93b79c7..915c5c4 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManagerTest.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/JarManagerTest.java
@@ -2,45 +2,40 @@ package top.niunaijun.blackbox.core.system;
import android.util.Log;
-/**
- * Simple test class for JarManager improvements
- * This can be used to verify the JAR management system works correctly
- */
+
public class JarManagerTest {
private static final String TAG = "JarManagerTest";
- /**
- * Test JAR manager functionality
- */
+
public static void testJarManager() {
Log.i(TAG, "Starting JAR Manager test");
try {
JarManager jarManager = JarManager.getInstance();
- // Test async initialization
+
Log.d(TAG, "Testing async initialization");
jarManager.initializeAsync();
- // Wait a bit for async initialization
+
Thread.sleep(2000);
- // Test sync initialization if needed
+
if (!jarManager.isReady()) {
Log.d(TAG, "Async initialization not complete, trying sync");
jarManager.initializeSync();
}
- // Test JAR file retrieval
+
Log.d(TAG, "Testing JAR file retrieval");
testJarFileRetrieval(jarManager);
- // Test cache statistics
+
Log.d(TAG, "Testing cache statistics");
String stats = jarManager.getCacheStats();
Log.i(TAG, "Cache stats: " + stats);
- // Test individual JAR info
+
Log.d(TAG, "Testing individual JAR info");
String emptyJarInfo = jarManager.getJarInfo("empty.jar");
String junitJarInfo = jarManager.getJarInfo("junit.jar");
@@ -55,25 +50,23 @@ public class JarManagerTest {
}
}
- /**
- * Test JAR file retrieval
- */
+
private static void testJarFileRetrieval(JarManager jarManager) {
- // Test empty.jar
+
if (jarManager.getEmptyJar() != null) {
Log.d(TAG, "Empty JAR retrieved successfully");
} else {
Log.w(TAG, "Empty JAR retrieval failed");
}
- // Test junit.jar
+
if (jarManager.getJunitJar() != null) {
Log.d(TAG, "JUnit JAR retrieved successfully");
} else {
Log.w(TAG, "JUnit JAR retrieval failed");
}
- // Test generic retrieval
+
if (jarManager.getJarFile("empty.jar") != null) {
Log.d(TAG, "Generic JAR retrieval for empty.jar successful");
} else {
@@ -81,13 +74,11 @@ public class JarManagerTest {
}
}
- /**
- * Test configuration
- */
+
public static void testConfiguration() {
Log.i(TAG, "Testing JAR configuration");
- // Test JAR definitions
+
JarConfig.JarDefinition[] jars = JarConfig.getRequiredJars();
Log.d(TAG, "Found " + jars.length + " JAR definitions");
@@ -99,11 +90,11 @@ public class JarManagerTest {
", Description: " + jar.getDescription());
}
- // Test buffer size calculation
+
int bufferSize = JarConfig.getOptimalBufferSize();
Log.d(TAG, "Optimal buffer size: " + bufferSize + " bytes");
- // Test file validation
+
boolean enableValidation = JarConfig.ENABLE_SIZE_VALIDATION;
boolean enableHashing = JarConfig.ENABLE_FILE_HASHING;
boolean enableAsync = JarConfig.ENABLE_ASYNC_LOADING;
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
index eb10f69..bf84cad 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ServiceManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/ServiceManager.java
@@ -16,14 +16,7 @@ import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
import top.niunaijun.blackbox.core.system.user.BUserManagerService;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ServiceManager {
private static ServiceManager sServiceManager = null;
public static final String ACTIVITY_MANAGER = "activity_manager";
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
index eaee62c..a113e5c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/SystemCallProvider.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/SystemCallProvider.java
@@ -13,14 +13,7 @@ import androidx.annotation.Nullable;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.BundleCompat;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class SystemCallProvider extends ContentProvider {
public static final String TAG = "SystemCallProvider";
@@ -70,7 +63,7 @@ public class SystemCallProvider extends ContentProvider {
return super.call(method, arg, extras);
} catch (Exception e) {
Slog.e(TAG, "Error in SystemCallProvider call method: " + method, e);
- // Return a bundle with error information
+
Bundle errorBundle = new Bundle();
errorBundle.putString("error", e.getMessage());
return errorBundle;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccount.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccount.java
index 5dbf59c..f96af71 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccount.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccount.java
@@ -7,9 +7,7 @@ import android.os.Parcelable;
import java.util.HashMap;
import java.util.LinkedHashMap;
-/**
- * Created by BlackBox on 2022/3/3.
- */
+
public class BAccount implements Parcelable {
public Account account;
public String password;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccountManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccountManagerService.java
index 9a5726b..ed08606 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccountManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BAccountManagerService.java
@@ -70,9 +70,7 @@ import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.AccountManagerCompat;
-/**
- * Created by BlackBox on 2022/3/3.
- */
+
@SuppressLint("InlinedApi")
public class BAccountManagerService extends IBAccountManagerService.Stub implements ISystemService , PackageMonitor {
private static final String TAG = "AccountManagerService";
@@ -81,7 +79,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
- // Messages that can be sent on mHandler
+
private static final int MESSAGE_TIMED_OUT = 3;
private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
@@ -201,7 +199,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public AuthenticatorDescription[] getAuthenticatorTypes(int userId) throws RemoteException {
- // Only allow the system process to read accounts of other users
+
BUserAccounts userAccounts = getUserAccounts(userId);
List authenticatorDescriptions = new ArrayList<>();
synchronized (userAccounts.lock) {
@@ -217,7 +215,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public Account[] getAccountsForPackage(String packageName, int uid, int userId) throws RemoteException {
- // Only allow the system process to read accounts of other users
+
BUserAccounts userAccounts = getUserAccounts(userId);
List accounts = new ArrayList<>();
synchronized (userAccounts.lock) {
@@ -233,7 +231,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public Account[] getAccountsByTypeForPackage(String type, String packageName, int userId) throws RemoteException {
- // Only allow the system process to read accounts of other users
+
BUserAccounts userAccounts = getUserAccounts(userId);
List accounts = new ArrayList<>();
synchronized (userAccounts.lock) {
@@ -274,7 +272,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (ArrayUtils.isEmpty(features)) {
Account[] accountsWithManagedNotVisible = getAccountsFromCache(
userAccounts, accountType, opPackageName,
- true /* include managed not visible */);
+ true );
handleGetAccountsResult(
response, accountsWithManagedNotVisible, opPackageName, userId);
return;
@@ -297,7 +295,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void onError(int errorCode, String errorMessage)
throws RemoteException {
- // Will not be called in this case.
+
}
};
new GetAccountsByTypeAndFeatureSession(
@@ -307,7 +305,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
features,
userId,
opPackageName,
- true /* include managed not visible */).bind();
+ true ).bind();
}
@Override
@@ -316,7 +314,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (type == null) throw new IllegalArgumentException("accountType is null");
String opPackageName = getCallingPackageName();
- // check visibleAccountTypes
+
BUserAccounts userAccounts = getUserAccounts(userId);
if (features == null || features.length == 0) {
Account[] accounts = getAccountsFromCache(userAccounts, type,
@@ -333,7 +331,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
features,
userId,
opPackageName,
- false /* include managed not visible */).bind();
+ false ).bind();
}
@Override
@@ -345,12 +343,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public void removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId) throws RemoteException {
Preconditions.checkArgument(account != null, "account cannot be null");
Preconditions.checkArgument(response != null, "response cannot be null");
- // Only allow the system process to modify accounts of other users
- /*
- * Only the system, authenticator or profile owner should be allowed to remove accounts for
- * that authenticator. This will let users remove accounts (via Settings in the system) but
- * not arbitrary applications (like competing authenticators).
- */
+
+
BUserAccounts accounts = getUserAccounts(userId);
new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
}
@@ -364,10 +358,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
+ ", pid " + Binder.getCallingPid());
}
if (account == null) {
- /*
- * Null accounts should result in returning false, as per
- * AccountManage.addAccountExplicitly(...) java doc.
- */
+
Log.e(TAG, "account is null");
return false;
}
@@ -395,8 +386,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
Slog.d(TAG, "Copying account " + account.toString()
+ " from user " + userFrom + " to user " + userTo);
new Session(fromAccounts, response, account.type, false,
- false /* stripAuthTokenFromResult */, account.name,
- false /* authDetailsRequired */) {
+ false , account.name,
+ false ) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
@@ -412,7 +403,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public void onResult(Bundle result) {
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
- // Create a Session for the target user and pass in the bundle
+
completeCloningAccount(response, result, account, toAccounts, userFrom);
} else {
super.onResult(result);
@@ -518,7 +509,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) throws RemoteException {
- // system
+
}
@Override
@@ -545,10 +536,10 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final boolean customTokens =
authenticatorInfo != null && authenticatorInfo.desc.customTokens;
- // Get the calling package. We will use it for the purpose of caching.
+
final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
- // let authenticator know the identity of the caller
+
loginOptions.putInt(AccountManager.KEY_CALLER_UID, Binder.getCallingUid());
loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
@@ -556,8 +547,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
loginOptions.putBoolean(AccountManagerCompat.KEY_NOTIFY_ON_FAILURE, true);
}
- // if the caller has permission, do the peek. otherwise go the more expensive
- // route of starting a Session
+
+
if (!customTokens) {
String authToken = readAuthTokenInternal(accounts, account, authTokenType);
if (authToken != null) {
@@ -571,11 +562,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
if (customTokens) {
- /*
- * Look up tokens in the new cache only if the loginOptions don't have parameters
- * outside of those expected to be injected by the AccountManager, e.g.
- * ANDORID_PACKAGE_NAME.
- */
+
String token = readCachedTokenInternal(
accounts,
account,
@@ -599,9 +586,9 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
response,
account.type,
expectActivityLaunch,
- false /* stripAuthTokenFromResult */,
+ false ,
account.name,
- false /* authDetailsRequired */) {
+ false ) {
@Override
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
@@ -614,8 +601,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void run() throws RemoteException {
- // If the caller doesn't have permission then create and return the
- // "grant permission" intent instead of the "getAuthToken" intent.
+
+
mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
}
@@ -655,11 +642,11 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
if (intent != null && notifyOnAuthFailure && !customTokens) {
-// doNotification(
-// mAccounts,
-// account,
-// result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
-// intent, "android", accounts.userId);
+
+
+
+
+
}
}
super.onResult(result);
@@ -672,16 +659,16 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
-// final int pid = Binder.getCallingPid();
-// final int uid = Binder.getCallingUid();
+
+
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
-// options.putInt(AccountManager.KEY_CALLER_UID, uid);
-// options.putInt(AccountManager.KEY_CALLER_PID, pid);
+
+
BUserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, expectActivityLaunch,
- true /* stripAuthTokenFromResult */, null /* accountName */,
- false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
+ true , null ,
+ false , true ) {
@Override
public void run() throws RemoteException {
mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
@@ -699,7 +686,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void addAccountAsUser(IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle options, int userId) throws RemoteException {
- // ignore
+
}
@Override
@@ -709,8 +696,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
long identityToken = clearCallingIdentity();
BUserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, account.type, expectActivityLaunch,
- true /* stripAuthTokenFromResult */, account.name,
- false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
+ true , account.name,
+ false , true ) {
@Override
public void run() throws RemoteException {
mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
@@ -733,8 +720,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
BUserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, expectActivityLaunch,
- true /* stripAuthTokenFromResult */, null /* accountName */,
- false /* authDetailsRequired */) {
+ true , null ,
+ false ) {
@Override
public void run() throws RemoteException {
mAuthenticator.editProperties(this, mAccountType);
@@ -749,7 +736,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void confirmCredentialsAsUser(IAccountManagerResponse response, Account account, Bundle options, boolean expectActivityLaunch, int userId) throws RemoteException {
- // ignore
+
}
@Override
@@ -765,13 +752,13 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public void getAuthTokenLabel(IAccountManagerResponse response, String accountType, String authTokenType, int userId) throws RemoteException {
Preconditions.checkArgument(accountType != null, "accountType cannot be null");
Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null");
-// if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
-// throw new SecurityException("can only call from system");
-// }
+
+
+
BUserAccounts accounts = getUserAccounts(userId);
- new Session(accounts, response, accountType, false /* expectActivityLaunch */,
- false /* stripAuthTokenFromResult */, null /* accountName */,
- false /* authDetailsRequired */) {
+ new Session(accounts, response, accountType, false ,
+ false , null ,
+ false ) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAuthTokenLabel"
@@ -855,7 +842,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
String authTokenType) {
if (accounts == null)
return null;
- // If not cached yet - do slow path and sync with db if necessary
+
synchronized (accounts.lock) {
Map authToken = accounts.getAuthToken(account);
return authToken.get(authTokenType);
@@ -866,8 +853,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final Bundle accountCredentials, final Account account, final BUserAccounts targetUser,
final int parentUserId){
new Session(targetUser, response, account.type, false,
- false /* stripAuthTokenFromResult */, account.name,
- false /* authDetailsRequired */) {
+ false , account.name,
+ false ) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
@@ -876,7 +863,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void run() throws RemoteException {
- // Confirm that the owner's account still exists before this step.
+
for (Account acc : getAccounts(parentUserId, mContext.getPackageName())) {
if (acc.equals(account)) {
mAuthenticator.addAccountFromCredentials(
@@ -888,10 +875,10 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void onResult(Bundle result) {
- // TODO: Anything to do if if succedded?
- // TODO: If it failed: Show error notification? Should we remove the shadow
- // account to avoid retries?
- // TODO: what we do with the visibility?
+
+
+
+
super.onResult(result);
}
@@ -899,8 +886,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void onError(int errorCode, String errorMessage) {
super.onError(errorCode, errorMessage);
- // TODO: Show error notification to user
- // TODO: Should we remove the shadow account so that it doesn't keep trying?
+
+
}
}.bind();
@@ -915,13 +902,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public boolean addAccountExplicitlyWithVisibility(Account account, String password,
Bundle extras, Map packageToVisibility, int userId) {
- /*
- * Child users are not allowed to add accounts. Only the accounts that are shared by the
- * parent profile can be added to child profile.
- *
- * TODO: Only allow accounts that were shared to be added by a limited user.
- */
- // fails if the account already exists
+
+
BUserAccounts accounts = getUserAccounts(userId);
return addAccountInternal(accounts, account, password, extras,
(Map) packageToVisibility);
@@ -1009,8 +991,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (packageToVisibility != null) {
for (Map.Entry entry : packageToVisibility.entrySet()) {
- setAccountVisibility(account, entry.getKey() /* package */,
- entry.getValue() /* visibility */,
+ setAccountVisibility(account, entry.getKey() ,
+ entry.getValue() ,
accounts);
}
}
@@ -1079,22 +1061,15 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
firstPass.put(account, visibility);
}
}
-// Map secondPass =
-// filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
-//
-// Account[] filtered = new Account[secondPass.size()];
-// filtered = secondPass.keySet().toArray(filtered);
+
+
+
+
+
return firstPass.keySet().toArray(new Account[]{});
}
- /**
- * Method which handles default values for Account visibility.
- *
- * @param account The account to check visibility.
- * @param packageName Package name to check visibility
- * @param accounts UserAccount that currently hosts the account and application
- * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
- */
+
private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
BUserAccounts accounts) {
if (accounts == null) {
@@ -1105,7 +1080,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
return AccountManager.VISIBILITY_NOT_VISIBLE;
}
- // Return stored value if it was set.
+
int visibility = getAccountVisibilityFromCache(account, packageName, accounts);
if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
return visibility;
@@ -1113,14 +1088,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
return AccountManager.VISIBILITY_NOT_VISIBLE;
}
- /**
- * Method returns visibility for given account and package name.
- *
- * @param account The account to check visibility.
- * @param packageName Package name to check visibility.
- * @param accounts UserAccount that currently hosts the account and application
- * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
- */
+
private int getAccountVisibilityFromCache(Account account, String packageName,
BUserAccounts accounts) {
synchronized (accounts.lock) {
@@ -1144,7 +1112,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
int userId) {
if (needToStartChooseAccountActivity(accounts, callingPackage, userId)) {
-// startChooseAccountActivityWithAccounts(response, accounts, callingPackage);
+
return;
}
if (accounts.length == 1) {
@@ -1154,7 +1122,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
onResult(response, bundle);
return;
}
- // No qualified account exists, return an empty Bundle.
+
onResult(response, new Bundle());
}
@@ -1223,8 +1191,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
public RemoveAccountSession(BUserAccounts accounts, IAccountManagerResponse response,
Account account, boolean expectActivityLaunch) {
super(accounts, response, account.type, expectActivityLaunch,
- true /* stripAuthTokenFromResult */, account.name,
- false /* authDetailsRequired */);
+ true , account.name,
+ false );
mAccount = account;
}
@@ -1281,9 +1249,9 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
int userId,
String packageName,
boolean includeManagedNotVisible) {
- super(accounts, response, type, false /* expectActivityLaunch */,
- true /* stripAuthTokenFromResult */, null /* accountName */,
- false /* authDetailsRequired */);
+ super(accounts, response, type, false ,
+ true , null ,
+ false );
mUserId = userId;
mFeatures = features;
mPackageName = packageName;
@@ -1293,7 +1261,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
@Override
public void run() throws RemoteException {
mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType, mPackageName, mIncludeManagedNotVisible);
- // check whether each account matches the requested features
+
mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
mCurrentAccount = 0;
@@ -1308,10 +1276,10 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final IAccountAuthenticator accountAuthenticator = mAuthenticator;
if (accountAuthenticator == null) {
- // It is possible that the authenticator has died, which is indicated by
- // mAuthenticator being set to null. If this happens then just abort.
- // There is no need to send back a result or error in this case since
- // that already happened when mAuthenticator was cleared.
+
+
+
+
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "checkAccount: aborting session since we are no longer"
+ " connected to the authenticator, " + toDebugString());
@@ -1355,7 +1323,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
response.onResult(result);
} catch (RemoteException e) {
- // if the caller is dead then there is no one to care about remote exceptions
+
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "failure while notifying response", e);
}
@@ -1426,7 +1394,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
AttributeSet attributeSet = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
- // Nothing to do
+
}
if (AccountManager.AUTHENTICATOR_ATTRIBUTES_NAME.equals(parser.getName())) {
AuthenticatorDescription desc = parseAuthenticatorDescription(
@@ -1450,12 +1418,12 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
final boolean mExpectActivityLaunch;
final long mCreationTime;
final String mAccountName;
- // Indicates if we need to add auth details(like last credential time)
+
final boolean mAuthDetailsRequired;
- // If set, we need to update the last authenticated time. This is
- // currently
- // used on
- // successful confirming credentials.
+
+
+
+
final boolean mUpdateLastAuthenticatedTime;
public int mNumResults = 0;
@@ -1471,14 +1439,14 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
boolean authDetailsRequired) {
this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult,
- accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */);
+ accountName, authDetailsRequired, false );
}
public Session(BUserAccounts accounts, IAccountManagerResponse response, String accountType,
boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
boolean authDetailsRequired, boolean updateLastAuthenticatedTime) {
super();
- //if (response == null) throw new IllegalArgumentException("response is null");
+
if (accountType == null) throw new IllegalArgumentException("accountType is null");
mAccounts = accounts;
mStripAuthTokenFromResult = stripAuthTokenFromResult;
@@ -1495,7 +1463,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
if (response != null) {
try {
- response.asBinder().linkToDeath(this, 0 /* flags */);
+ response.asBinder().linkToDeath(this, 0 );
} catch (RemoteException e) {
mResponse = null;
binderDied();
@@ -1505,25 +1473,18 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
IAccountManagerResponse getResponseAndClose() {
if (mResponse == null) {
- // this session has already been closed
+
return null;
}
IAccountManagerResponse response = mResponse;
- close(); // this clears mResponse so we need to save the response before this call
+ close();
return response;
}
- /**
- * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our
- * security policy.
- *
- * In particular we want to make sure that the Authenticator doesn't try to trick users
- * into launching arbitrary intents on the device via by tricking to click authenticator
- * supplied entries in the system Settings app.
- */
+
protected boolean checkKeyIntent(int authUid, Intent intent) {
- // Explicitly set an empty ClipData to ensure that we don't offer to
- // promote any Uris contained inside for granting purposes
+
+
if (intent.getClipData() == null) {
intent.setClipData(ClipData.newPlainText(null, null));
}
@@ -1537,7 +1498,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
if (resolveInfo == null) {
return false;
}
- // check hasSignatureCapability
+
return true;
} finally {
Binder.restoreCallingIdentity(bid);
@@ -1547,15 +1508,15 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
private void close() {
synchronized (mSessions) {
if (mSessions.remove(toString()) == null) {
- // the session was already closed, so bail out now
+
return;
}
}
if (mResponse != null) {
- // stop listening for response deaths
- mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
+
+ mResponse.asBinder().unlinkToDeath(this, 0 );
- // clear this so that we don't accidentally send any further results
+
mResponse = null;
}
cancelTimeout();
@@ -1656,9 +1617,9 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
boolean isSuccessfulUpdateCredsOrAddAccount =
result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
&& result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
- // We should only update lastAuthenticated time, if
- // mUpdateLastAuthenticatedTime is true and the confirmRequest
- // or updateRequest was successful
+
+
+
boolean needUpdate = mUpdateLastAuthenticatedTime
&& (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount);
if (needUpdate || mAuthDetailsRequired) {
@@ -1694,8 +1655,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
Account account = new Account(accountName, accountType);
-// cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
-// new UserHandle(mAccounts.userId));
+
+
}
}
IAccountManagerResponse response;
@@ -1724,7 +1685,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
(intent == null)) {
- // All AccountManager error codes are greater than 0
+
response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
result.getString(AccountManager.KEY_ERROR_MESSAGE));
} else {
@@ -1732,7 +1693,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
}
} catch (RemoteException e) {
- // if the caller is dead then there is no one to care about remote exceptions
+
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "failure while notifying response", e);
}
@@ -1768,10 +1729,7 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
}
}
- /**
- * find the component name for the authenticator and initiate a bind
- * if no authenticator or the bind fails then return false, otherwise return true
- */
+
private boolean bindToAuthenticator(String authenticatorType) {
AuthenticatorInfo authenticatorInfo = mAuthenticatorCache.authenticators.get(authenticatorType);
if (authenticatorInfo == null) {
@@ -1782,27 +1740,27 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
return false;
}
-// if (!isLocalUnlockedUser(mAccounts.userId)
-// && !authenticatorInfo.componentInfo.directBootAware) {
-// Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName
-// + " which isn't encryption aware");
-// return false;
-// }
+
+
+
+
+
+
Intent intent = new Intent();
intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
ComponentName componentName = new ComponentName(authenticatorInfo.serviceInfo.packageName, authenticatorInfo.serviceInfo.name);
intent.setComponent(componentName);
- // call userId
+
intent.putExtra("_B_|_UserId", mAccounts.userId);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "performing bindService to " + componentName);
}
int flags = Context.BIND_AUTO_CREATE;
-// if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) {
-// flags |= Context.BIND_ALLOW_INSTANT;
-// }
+
+
+
if (!mContext.bindService(intent, this, flags)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "bindService to " + componentName + " failed");
@@ -1825,8 +1783,8 @@ public class BAccountManagerService extends IBAccountManagerService.Stub impleme
try {
response.onResult(result);
} catch (RemoteException e) {
- // if the caller is dead then there is no one to care about remote
- // exceptions
+
+
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "failure while notifying response", e);
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BUserAccounts.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BUserAccounts.java
index efaf3cd..b83288c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BUserAccounts.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/BUserAccounts.java
@@ -9,9 +9,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-/**
- * Created by BlackBox on 2022/3/3.
- */
+
public class BUserAccounts implements Parcelable {
public final Object lock = new Object();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/TokenCache.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/TokenCache.java
index d2ecd5b..5ff0792 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/TokenCache.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/accounts/TokenCache.java
@@ -4,9 +4,7 @@ import android.accounts.Account;
import java.util.Objects;
-/**
- * Created by BlackBox on 2022/3/3.
- */
+
public class TokenCache {
public int userId;
public Account account;
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
index bb23c2b..0b4faf6 100644
--- 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
@@ -28,14 +28,7 @@ import top.niunaijun.blackbox.entity.am.RunningServiceInfo;
import top.niunaijun.blackbox.proxy.ProxyManifest;
import top.niunaijun.blackbox.proxy.record.ProxyServiceRecord;
-/**
- * updated by alex5402 on 4/7/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@SuppressLint("NewApi")
public class ActiveServices {
public static final String TAG = "ActiveServices";
@@ -48,7 +41,7 @@ public class ActiveServices {
ResolveInfo resolveInfo = resolveService(intent, resolvedType, userId);
if (resolveInfo == null)
return;
-// throw new RuntimeException("resolveService service exception");
+
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
ProcessRecord processRecord = BProcessManagerService.get().startProcessLocked(serviceInfo.packageName, serviceInfo.processName, userId, -1, Binder.getCallingPid());
if (processRecord == null) {
@@ -72,7 +65,7 @@ public class ActiveServices {
}
public int stopService(Intent intent, String resolvedType, int userId) {
-// ResolveInfo resolveInfo = resolveService(intent, resolvedType, userId);
+
synchronized (mRunningServiceRecords) {
RunningServiceRecord runningServiceRecord = findRunningServiceRecord(intent);
if (runningServiceRecord == null) {
@@ -275,10 +268,10 @@ public class ActiveServices {
}
public static class RunningServiceRecord extends IEmpty.Stub {
- // onStartCommand startId
+
private final AtomicInteger mStartId = new AtomicInteger(1);
private final AtomicInteger mBindCount = new AtomicInteger(0);
- // 正在连接的服务
+
private ConnectedServiceRecord mConnectedServiceRecord;
private ServiceInfo mServiceInfo;
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
index 8d32150..9d98440 100644
--- 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
@@ -9,14 +9,7 @@ import android.os.IBinder;
import top.niunaijun.blackbox.core.system.ProcessRecord;
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ActivityRecord extends Binder {
public TaskRecord task;
public IBinder token;
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
index b9c19da..7d31655 100644
--- 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
@@ -43,14 +43,7 @@ import top.niunaijun.blackbox.utils.compat.ActivityManagerCompat;
import static android.content.pm.PackageManager.GET_ACTIVITIES;
-/**
- * updated by alex5402 on 4/5/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@SuppressWarnings({"deprecation", "unchecked"})
public class ActivityStack {
public static final String TAG = "ActivityStack";
@@ -144,11 +137,11 @@ public class ActivityStack {
break;
}
- // 如果还没有task则新启动一个task
+
if (taskRecord == null || taskRecord.needNewTask()) {
return startActivityInNewTaskLocked(userId, intent, activityInfo, resultTo, launchModeFlags);
}
- // 移至前台
+
mAms.moveTaskToFront(taskRecord.id, 0);
boolean notStartToFront = false;
@@ -170,7 +163,7 @@ public class ActivityStack {
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);
@@ -181,7 +174,7 @@ public class ActivityStack {
if (singleTop) {
newIntentRecord = targetActivityRecord;
} else {
- // clearTop并且不是singleTop,目标也finish,重建。
+
targetActivityRecord.finished = true;
}
break;
@@ -198,7 +191,7 @@ public class ActivityStack {
synchronized (mLaunchingActivities) {
for (ActivityRecord launchingActivity : mLaunchingActivities) {
if (!launchingActivity.finished && launchingActivity.component.equals(intent.getComponent())) {
- // todo update onNewIntent from intent
+
ignore = true;
}
}
@@ -212,9 +205,9 @@ public class ActivityStack {
} 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);
@@ -233,17 +226,17 @@ public class ActivityStack {
newIntentRecord = topActivityRecord;
}
- // clearTask finish All
+
if (clearTask && newTask) {
for (ActivityRecord activity : taskRecord.activities) {
activity.finished = true;
}
finishAllActivity(userId);
}
- // Do NOT call finishAllActivity(userId) unless clearTask is true
+
if (newIntentRecord != null) {
- // 通知onNewIntent
+
deliverNewIntentLocked(newIntentRecord, intent);
return 0;
} else if (ignore) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BActivityManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BActivityManagerService.java
index 20eb00e..6ef4967 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BActivityManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BActivityManagerService.java
@@ -30,14 +30,7 @@ import top.niunaijun.blackbox.utils.Slog;
import static android.content.pm.PackageManager.GET_META_DATA;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BActivityManagerService extends IBActivityManagerService.Stub implements ISystemService {
public static final String TAG = "BActivityManagerService";
private static final BActivityManagerService sService = new BActivityManagerService();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BJobManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BJobManagerService.java
index 7e25000..ef0115d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BJobManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BJobManagerService.java
@@ -22,18 +22,11 @@ import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
import top.niunaijun.blackbox.entity.JobRecord;
import top.niunaijun.blackbox.proxy.ProxyManifest;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BJobManagerService extends IBJobManagerService.Stub implements ISystemService {
private static final BJobManagerService sService = new BJobManagerService();
- // process_jobId
+
private final Map mJobRecords = new HashMap<>();
public static BJobManagerService get() {
@@ -83,7 +76,7 @@ public class BJobManagerService extends IBJobManagerService.Stub implements ISys
for (String key : mJobRecords.keySet()) {
if (key.startsWith(processName + "_")) {
JobRecord jobRecord = mJobRecords.get(key);
- // todo
+
}
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BroadcastManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BroadcastManager.java
index a59bff0..11abe54 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BroadcastManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/BroadcastManager.java
@@ -21,9 +21,7 @@ import top.niunaijun.blackbox.entity.am.PendingResultData;
import top.niunaijun.blackbox.proxy.ProxyBroadcastReceiver;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Created by BlackBox on 2022/2/28.
- */
+
public class BroadcastManager implements PackageMonitor {
public static final String TAG = "BroadcastManager";
@@ -109,7 +107,7 @@ public class BroadcastManager implements PackageMonitor {
public void sendBroadcast(PendingResultData pendingResultData) {
synchronized (mReceiversData) {
- // Slog.d(TAG, "sendBroadcast: " + pendingResultData);
+
mReceiversData.put(pendingResultData.mBToken, pendingResultData);
Message obtain = Message.obtain(mHandler, MSG_TIME_OUT, pendingResultData);
mHandler.sendMessageDelayed(obtain, TIMEOUT);
@@ -118,7 +116,7 @@ public class BroadcastManager implements PackageMonitor {
public void finishBroadcast(PendingResultData data) {
synchronized (mReceiversData) {
- // Slog.d(TAG, "finishBroadcast: " + data);
+
mHandler.removeMessages(MSG_TIME_OUT, mReceiversData.get(data.mBToken));
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/PendingIntentRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/PendingIntentRecord.java
index fc25648..58cc0ec 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/PendingIntentRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/PendingIntentRecord.java
@@ -2,9 +2,7 @@ package top.niunaijun.blackbox.core.system.am;
import java.util.Objects;
-/**
- * Created by BlackBox on 2022/3/8.
- */
+
public class PendingIntentRecord {
public int uid;
public String packageName;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/TaskRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/TaskRecord.java
index fca36e5..1b8730f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/TaskRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/TaskRecord.java
@@ -5,14 +5,7 @@ import android.content.Intent;
import java.util.LinkedList;
import java.util.List;
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class TaskRecord {
public int id;
public int userId;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/UserSpace.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/UserSpace.java
index 284d1a8..1fee9cc 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/UserSpace.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/am/UserSpace.java
@@ -5,14 +5,7 @@ import android.os.IBinder;
import java.util.HashMap;
import java.util.Map;
-/**
- * updated by alex5402 on 4/25/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class UserSpace {
public final ActiveServices mActiveServices = new ActiveServices();
public final ActivityStack mStack = new ActivityStack();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/BLocationManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/BLocationManagerService.java
index 84dd4a0..ebb22df 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/BLocationManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/BLocationManagerService.java
@@ -30,14 +30,7 @@ import top.niunaijun.blackbox.utils.CloseUtils;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Fake location
- * plan1: only GPS invocation is valid and other methods like addressed by cells are intercepted at all.
- * plan2: mock fake neighboring cells from LBS database and modify the result of GPS invocation.
- * plan3: cheat internal application at being given permission to access location information but get data from BB.
- * the final testing condition requires UI demo.
- * Created by BlackBoxing on 3/8/22.
- **/
+
public class BLocationManagerService extends IBLocationManagerService.Stub implements ISystemService {
public static final String TAG = "BLocationManagerService";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/LocationRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/LocationRecord.java
index befb4b6..debc9ed 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/LocationRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/location/LocationRecord.java
@@ -1,8 +1,6 @@
package top.niunaijun.blackbox.core.system.location;
-/**
- * Created by BlackBox on 2022/3/19.
- */
+
public class LocationRecord {
public String packageName;
public int userId;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/BNotificationManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/BNotificationManagerService.java
index cd114c8..331bfb6 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/BNotificationManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/BNotificationManagerService.java
@@ -28,9 +28,7 @@ import top.niunaijun.blackbox.core.system.ISystemService;
import top.niunaijun.blackbox.core.system.ProcessRecord;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Created by BlackBox on 2022/3/15.
- */
+
public class BNotificationManagerService extends IBNotificationManagerService.Stub implements ISystemService {
private final static BNotificationManagerService sService = new BNotificationManagerService();
public static final String CHANNEL_BLACK = "@black-";
@@ -177,12 +175,12 @@ public class BNotificationManagerService extends IBNotificationManagerService.St
if (BuildCompat.isOreo()) {
NotificationOContext notificationOContext = BRNotificationO.get(notification);
- // channel
+
if (notificationOContext._check_mChannelId() != null) {
String blackChannelId = getBlackChannelId(notificationOContext.mChannelId(), userId);
notificationOContext._set_mChannelId(blackChannelId);
}
- // group
+
if (notificationOContext._check_mGroupKey() != null) {
String blackGroupId = getBlackGroupId(notificationOContext.mGroupKey(), userId);
notificationOContext._set_mGroupKey(blackGroupId);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationChannelManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationChannelManager.java
index 52ac651..bff2ac4 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationChannelManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationChannelManager.java
@@ -11,9 +11,7 @@ import androidx.annotation.RequiresApi;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * Created by BlackBox on 2022/3/18.
- */
+
public class NotificationChannelManager {
private final static NotificationChannelManager sManager = new NotificationChannelManager();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationRecord.java
index 5ffe69c..6dab604 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/notification/NotificationRecord.java
@@ -8,9 +8,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-/**
- * Created by BlackBox on 2022/3/18.
- */
+
public class NotificationRecord {
public final Map mNotificationChannels = new HashMap<>();
public final Map mNotificationChannelGroups = new HashMap<>();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/os/BStorageManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/os/BStorageManagerService.java
index 3190f7d..a5925fb 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/os/BStorageManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/os/BStorageManagerService.java
@@ -17,14 +17,7 @@ import top.niunaijun.blackbox.fake.provider.FileProvider;
import top.niunaijun.blackbox.proxy.ProxyManifest;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 4/10/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BStorageManagerService extends IBStorageManagerService.Stub implements ISystemService {
private static final BStorageManagerService sService = new BStorageManagerService();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/permission/XiaomiPermissionManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/permission/XiaomiPermissionManager.java
index 5bac9c0..216da7c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/permission/XiaomiPermissionManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/permission/XiaomiPermissionManager.java
@@ -19,24 +19,21 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Comprehensive permission manager for Xiaomi HyperOS devices
- * Handles Android 12+ notification permissions and Xiaomi background running permissions
- */
+
public class XiaomiPermissionManager {
private static final String TAG = "XiaomiPermissionManager";
private static final XiaomiPermissionManager sInstance = new XiaomiPermissionManager();
- // Xiaomi-specific permission constants
+
private static final String XIAOMI_AUTOSTART_PERMISSION = "miui.permission.USE_INTERNAL_GENERAL_API";
private static final String XIAOMI_BATTERY_OPTIMIZATION = "miui.permission.OPTIMIZE_POWER";
private static final String XIAOMI_BACKGROUND_RUNNING = "miui.permission.RUN_IN_BACKGROUND";
private static final String XIAOMI_NOTIFICATION_PERMISSION = "miui.permission.POST_NOTIFICATIONS";
- // Android 12+ notification permission
+
private static final String POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
- // Xiaomi system settings
+
private static final String XIAOMI_AUTOSTART_SETTINGS = "miui.intent.action.OP_AUTO_START";
private static final String XIAOMI_BATTERY_SETTINGS = "miui.intent.action.POWER_HIDE_MODE_APP_LIST";
private static final String XIAOMI_NOTIFICATION_SETTINGS = "miui.intent.action.NOTIFICATION_SETTINGS";
@@ -47,9 +44,7 @@ public class XiaomiPermissionManager {
private XiaomiPermissionManager() {}
- /**
- * Check if this is a Xiaomi/HyperOS device
- */
+
public boolean isXiaomiDevice() {
return BuildCompat.isMIUI() ||
Build.MANUFACTURER.toLowerCase().contains("xiaomi") ||
@@ -57,12 +52,10 @@ public class XiaomiPermissionManager {
Build.DISPLAY.toLowerCase().contains("hyperos");
}
- /**
- * Check if notification permission is granted (Android 12+)
- */
+
public boolean isNotificationPermissionGranted() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
- // Android 12- doesn't require explicit notification permission
+
return true;
}
@@ -70,37 +63,35 @@ public class XiaomiPermissionManager {
return ContextCompat.checkSelfPermission(context, POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
}
- /**
- * Check if Xiaomi background running permission is granted
- */
+
public boolean isXiaomiBackgroundPermissionGranted() {
if (!isXiaomiDevice()) {
- return true; // Not a Xiaomi device
+ return true;
}
Context context = BlackBoxCore.getContext();
- // Check various Xiaomi permissions
+
try {
- // Check autostart permission
+
if (ContextCompat.checkSelfPermission(context, XIAOMI_AUTOSTART_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
Slog.d(TAG, "Xiaomi autostart permission not granted");
return false;
}
- // Check battery optimization
+
if (ContextCompat.checkSelfPermission(context, XIAOMI_BATTERY_OPTIMIZATION) != PackageManager.PERMISSION_GRANTED) {
Slog.d(TAG, "Xiaomi battery optimization permission not granted");
return false;
}
- // Check background running
+
if (ContextCompat.checkSelfPermission(context, XIAOMI_BACKGROUND_RUNNING) != PackageManager.PERMISSION_GRANTED) {
Slog.d(TAG, "Xiaomi background running permission not granted");
return false;
}
- // Check notification permission
+
if (ContextCompat.checkSelfPermission(context, XIAOMI_NOTIFICATION_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
Slog.d(TAG, "Xiaomi notification permission not granted");
return false;
@@ -113,9 +104,7 @@ public class XiaomiPermissionManager {
}
}
- /**
- * Grant notification permission automatically (Android 12+)
- */
+
public void grantNotificationPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
Slog.d(TAG, "Notification permission not required on Android " + Build.VERSION.SDK_INT);
@@ -130,16 +119,14 @@ public class XiaomiPermissionManager {
Slog.d(TAG, "Attempting to grant notification permission automatically");
try {
- // Try to grant permission through reflection
+
grantPermissionThroughReflection(POST_NOTIFICATIONS);
} catch (Exception e) {
Slog.w(TAG, "Failed to grant notification permission automatically: " + e.getMessage());
}
}
- /**
- * Grant Xiaomi background running permissions automatically
- */
+
public void grantXiaomiBackgroundPermissions() {
if (!isXiaomiDevice()) {
Slog.d(TAG, "Not a Xiaomi device, skipping background permission grant");
@@ -154,13 +141,13 @@ public class XiaomiPermissionManager {
Slog.d(TAG, "Attempting to grant Xiaomi background permissions automatically");
try {
- // Grant various Xiaomi permissions
+
grantPermissionThroughReflection(XIAOMI_AUTOSTART_PERMISSION);
grantPermissionThroughReflection(XIAOMI_BATTERY_OPTIMIZATION);
grantPermissionThroughReflection(XIAOMI_BACKGROUND_RUNNING);
grantPermissionThroughReflection(XIAOMI_NOTIFICATION_PERMISSION);
- // Also try to disable battery optimization
+
disableBatteryOptimization();
} catch (Exception e) {
@@ -168,27 +155,23 @@ public class XiaomiPermissionManager {
}
}
- /**
- * Grant all required permissions for optimal functionality
- */
+
public void grantAllRequiredPermissions() {
Slog.d(TAG, "Granting all required permissions for optimal functionality");
- // Grant notification permission (Android 12+)
+
grantNotificationPermission();
- // Grant Xiaomi background permissions
+
grantXiaomiBackgroundPermissions();
- // Create notification channels
+
createNotificationChannels();
Slog.d(TAG, "Permission grant process completed");
}
- /**
- * Open Xiaomi permission settings for manual configuration
- */
+
public void openXiaomiPermissionSettings() {
if (!isXiaomiDevice()) {
Slog.w(TAG, "Not a Xiaomi device, cannot open Xiaomi settings");
@@ -198,7 +181,7 @@ public class XiaomiPermissionManager {
Context context = BlackBoxCore.getContext();
try {
- // Try to open Xiaomi autostart settings
+
Intent autostartIntent = new Intent(XIAOMI_AUTOSTART_SETTINGS);
autostartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(autostartIntent);
@@ -206,7 +189,7 @@ public class XiaomiPermissionManager {
} catch (Exception e) {
Slog.w(TAG, "Failed to open Xiaomi autostart settings: " + e.getMessage());
- // Fallback to general app settings
+
try {
Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", context.getPackageName(), null);
@@ -220,9 +203,7 @@ public class XiaomiPermissionManager {
}
}
- /**
- * Open notification permission settings
- */
+
public void openNotificationSettings() {
Context context = BlackBoxCore.getContext();
@@ -244,9 +225,7 @@ public class XiaomiPermissionManager {
}
}
- /**
- * Create notification channels for the app
- */
+
private void createNotificationChannels() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
@@ -261,7 +240,7 @@ public class XiaomiPermissionManager {
}
try {
- // Create main notification channel
+
android.app.NotificationChannel mainChannel = new android.app.NotificationChannel(
"blackbox_main",
"BlackBox Core",
@@ -275,7 +254,7 @@ public class XiaomiPermissionManager {
notificationManager.createNotificationChannel(mainChannel);
Slog.d(TAG, "Created main notification channel");
- // Create background service channel
+
android.app.NotificationChannel backgroundChannel = new android.app.NotificationChannel(
"blackbox_background",
"BlackBox Background",
@@ -294,9 +273,7 @@ public class XiaomiPermissionManager {
}
}
- /**
- * Disable battery optimization for the app
- */
+
private void disableBatteryOptimization() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return;
@@ -316,7 +293,7 @@ public class XiaomiPermissionManager {
if (!isIgnoringBatteryOptimizations) {
Slog.d(TAG, "App is not ignoring battery optimizations, attempting to disable");
- // Try to disable through reflection
+
try {
Method setIgnoreBatteryOptimizations = PowerManager.class.getMethod(
"setIgnoreBatteryOptimizations", String.class, boolean.class
@@ -335,17 +312,15 @@ public class XiaomiPermissionManager {
}
}
- /**
- * Grant permission through reflection (requires system privileges)
- */
+
private void grantPermissionThroughReflection(String permission) {
try {
Context context = BlackBoxCore.getContext();
- // Try to use PackageManager to grant permission
+
PackageManager packageManager = context.getPackageManager();
- // Use reflection to call grantRuntimePermission
+
Method grantRuntimePermission = PackageManager.class.getMethod(
"grantRuntimePermission", String.class, String.class, int.class
);
@@ -361,9 +336,7 @@ public class XiaomiPermissionManager {
}
}
- /**
- * Check if all required permissions are granted
- */
+
public boolean areAllPermissionsGranted() {
boolean notificationGranted = isNotificationPermissionGranted();
boolean xiaomiGranted = isXiaomiBackgroundPermissionGranted();
@@ -373,21 +346,19 @@ public class XiaomiPermissionManager {
return notificationGranted && xiaomiGranted;
}
- /**
- * Get a summary of current permission status
- */
+
public String getPermissionStatusSummary() {
StringBuilder summary = new StringBuilder();
summary.append("Permission Status Summary:\n");
- // Notification permission
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
summary.append("• POST_NOTIFICATIONS: ").append(isNotificationPermissionGranted() ? "GRANTED" : "DENIED").append("\n");
} else {
summary.append("• POST_NOTIFICATIONS: NOT_REQUIRED (Android < 12)\n");
}
- // Xiaomi permissions
+
if (isXiaomiDevice()) {
summary.append("• Xiaomi Autostart: ").append(isXiaomiBackgroundPermissionGranted() ? "GRANTED" : "DENIED").append("\n");
summary.append("• Xiaomi Battery Optimization: ").append(isXiaomiBackgroundPermissionGranted() ? "DISABLED" : "ENABLED").append("\n");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackage.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackage.java
index 3841fcd..4ffcc08 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackage.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackage.java
@@ -22,14 +22,7 @@ import java.util.ArrayList;
import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 4/21/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BPackage implements Parcelable {
public ArrayList activities = new ArrayList(0);
public ArrayList receivers = new ArrayList(0);
@@ -54,9 +47,9 @@ public class BPackage implements Parcelable {
public String baseCodePath;
public int mSharedUserLabel;
- // Applications hardware preferences
+
public ArrayList configPreferences = null;
- // Applications requested features
+
public ArrayList reqFeatures = null;
public InstallOption installOption;
@@ -131,7 +124,7 @@ public class BPackage implements Parcelable {
this.mSignatures = aPackage.mSignatures;
}
this.mAppMetaData = aPackage.mAppMetaData;
- // this.mExtras = new BPackageSettings((PackageSetting) aPackage.mExtras);
+
this.packageName = aPackage.packageName;
this.mPreferredOrder = aPackage.mPreferredOrder;
this.mSharedUserId = aPackage.mSharedUserId;
@@ -221,7 +214,7 @@ public class BPackage implements Parcelable {
}
this.mSignatures = in.createTypedArray(Signature.CREATOR);
this.mAppMetaData = in.readBundle(Bundle.class.getClassLoader());
-// this.mExtras = in.readParcelable(BPackageSettings.class.getClassLoader());
+
this.packageName = in.readString();
this.mPreferredOrder = in.readInt();
this.mSharedUserId = in.readString();
@@ -711,7 +704,7 @@ public class BPackage implements Parcelable {
}
dest.writeTypedArray(this.mSignatures, flags);
dest.writeBundle(this.mAppMetaData);
-// dest.writeParcelable(this.mExtras, flags);
+
dest.writeString(this.packageName);
dest.writeInt(this.mPreferredOrder);
dest.writeString(this.mSharedUserId);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageInstallerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageInstallerService.java
index 50d07e3..2454921 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageInstallerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageInstallerService.java
@@ -13,14 +13,7 @@ import top.niunaijun.blackbox.core.system.pm.installer.RemoveUserExecutor;
import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/21/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BPackageInstallerService extends IBPackageInstallerService.Stub implements ISystemService {
private static final BPackageInstallerService sService = new BPackageInstallerService();
@@ -33,11 +26,11 @@ public class BPackageInstallerService extends IBPackageInstallerService.Stub imp
@Override
public int installPackageAsUser(BPackageSettings ps, int userId) {
List executors = new ArrayList<>();
- // 创建用户环境相关操作
+
executors.add(new CreateUserExecutor());
- // 创建应用环境相关操作
+
executors.add(new CreatePackageExecutor());
- // 拷贝应用相关文件
+
executors.add(new CopyExecutor());
InstallOption option = ps.installOption;
for (Executor executor : executors) {
@@ -54,10 +47,10 @@ public class BPackageInstallerService extends IBPackageInstallerService.Stub imp
public int uninstallPackageAsUser(BPackageSettings ps, boolean removeApp, int userId) {
List executors = new ArrayList<>();
if (removeApp) {
- // 移除App
+
executors.add(new RemoveAppExecutor());
}
- // 移除用户相关目录
+
executors.add(new RemoveUserExecutor());
InstallOption option = ps.installOption;
for (Executor executor : executors) {
@@ -73,9 +66,9 @@ public class BPackageInstallerService extends IBPackageInstallerService.Stub imp
@Override
public int clearPackage(BPackageSettings ps, int userId) {
List executors = new ArrayList<>();
- // 移除用户相关目录
+
executors.add(new RemoveUserExecutor());
- // 创建用户环境相关操作
+
executors.add(new CreateUserExecutor());
InstallOption option = ps.installOption;
for (Executor executor : executors) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageManagerService.java
index 950687f..d5d0a05 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageManagerService.java
@@ -49,14 +49,7 @@ import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-/**
- * updated by alex5402 on 4/1/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BPackageManagerService extends IBPackageManagerService.Stub implements ISystemService {
public static final String TAG = "BPackageManagerService";
public static BPackageManagerService sService = new BPackageManagerService();
@@ -106,9 +99,9 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
return null;
}
flags = updateFlags(flags, userId);
- // reader
+
synchronized (mPackages) {
- // Normalize package name to handle renamed packages and static libs
+
BPackageSettings ps = mPackages.get(packageName);
if (ps != null) {
BPackage p = ps.pkg;
@@ -125,8 +118,8 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
intent, resolvedType, flags, userId);
if (query != null) {
if (query.size() >= 1) {
- // If there is more than one service with the same priority,
- // just arbitrarily pick the first one.
+
+
return query.get(0);
}
}
@@ -145,10 +138,10 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
final List list = new ArrayList<>(1);
final ServiceInfo si = getServiceInfo(comp, flags, userId);
if (si != null) {
- // When specifying an explicit component, we prevent the service from being
- // used when either 1) the service is in an instant application and the
- // caller is not the same instant application or 2) the calling package is
- // ephemeral and the activity is not visible to ephemeral applications.
+
+
+
+
final ResolveInfo ri = new ResolveInfo();
ri.serviceInfo = si;
list.add(ri);
@@ -156,7 +149,7 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
return list;
}
- // reader
+
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName != null) {
@@ -200,12 +193,12 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
if (N == 1) {
return query.get(0);
} else if (N > 1) {
- // If there is more than one activity with the same priority,
- // then let the user decide between them.
+
+
ResolveInfo r0 = query.get(0);
ResolveInfo r1 = query.get(1);
- // If the first activity has a higher priority, or a different
- // default, then it is always desirable to pick it.
+
+
if (r0.priority != r1.priority
|| r0.preferredOrder != r1.preferredOrder
|| r0.isDefault != r1.isDefault) {
@@ -230,10 +223,10 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
final List list = new ArrayList<>(1);
final ActivityInfo ai = getActivity(comp, flags, userId);
if (ai != null) {
- // When specifying an explicit component, we prevent the activity from being
- // used when either 1) the calling package is normal and the activity is within
- // an ephemeral application or 2) the calling package is ephemeral and the
- // activity is not visible to ephemeral applications.
+
+
+
+
final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
@@ -241,7 +234,7 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
}
}
- // reader
+
synchronized (mPackages) {
return mComponentResolver.queryActivities(intent, resolvedType, flags, userId);
}
@@ -283,9 +276,9 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
flags = updateFlags(flags, userId);
BPackageSettings ps = null;
- // reader
+
synchronized (mPackages) {
- // Normalize package name to handle renamed packages and static libs
+
ps = mPackages.get(packageName);
}
if (ps != null) {
@@ -363,22 +356,22 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
@Override
public List getInstalledPackages(int flags, int userId) {
final int callingUid = Binder.getCallingUid();
-// if (getInstantAppPackageName(callingUid) != null) {
-// return ParceledListSlice.emptyList();
-// }
+
+
+
if (!sUserManager.exists(userId)) return Collections.emptyList();
- // writer
+
synchronized (mPackages) {
ArrayList list;
list = new ArrayList<>(mPackages.size());
for (BPackageSettings ps : mPackages.values()) {
-// if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
-// continue;
-// }
-// if (filterAppAccessLPr(ps, callingUid, userId)) {
-// continue;
-// }
+
+
+
+
+
+
PackageInfo pi = getPackageInfo(ps.pkg.packageName, flags, userId);
if (pi != null) {
list.add(pi);
@@ -392,20 +385,20 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
int callingUid) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- // writer
+
synchronized (mPackages) {
ArrayList list;
list = new ArrayList<>(mPackages.size());
Collection packageSettings = mPackages.values();
for (BPackageSettings ps : packageSettings) {
-// if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
-// continue;
-// }
-// if (filterAppAccessLPr(ps, callingUid, userId)) {
-// continue;
-// }
-// if (GmsCore.isGoogleAppOrService(ps.pkg.packageName))
-// continue;
+
+
+
+
+
+
+
+
ApplicationInfo ai = PackageManagerCompat.generateApplicationInfo(ps.pkg, flags,
ps.readUserState(userId), userId);
if (ai != null) {
@@ -432,10 +425,10 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
final List list = new ArrayList<>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if (ai != null) {
- // When specifying an explicit component, we prevent the activity from being
- // used when either 1) the calling package is normal and the activity is within
- // an ephemeral application or 2) the calling package is ephemeral and the
- // activity is not visible to ephemeral applications.
+
+
+
+
final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
@@ -443,7 +436,7 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
return list;
}
- // reader
+
List result;
synchronized (mPackages) {
if (pkgName != null) {
@@ -456,8 +449,8 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
intent, resolvedType, flags, pkg.activities, userId);
}
if (result == null || result.size() == 0) {
- // the caller wants to resolve for a particular package; however, there
- // were no installed results, so, try to find an ephemeral result
+
+
if (result == null) {
result = new ArrayList<>();
}
@@ -483,10 +476,10 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
final List list = new ArrayList<>(1);
final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
if (ai != null) {
- // When specifying an explicit component, we prevent the activity from being
- // used when either 1) the calling package is normal and the activity is within
- // an instant application or 2) the calling package is ephemeral and the
- // activity is not visible to instant applications.
+
+
+
+
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
@@ -494,7 +487,7 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
return list;
}
- // reader
+
synchronized (mPackages) {
String pkgName = intent.getPackage();
BPackageSettings bPackageSettings = mPackages.get(pkgName);
@@ -541,7 +534,7 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
BProcessManagerService.get().killPackageAsUser(packageName, userId);
int i = BPackageInstallerService.get().uninstallPackageAsUser(ps, removeApp, userId);
if (i < 0) {
- // todo
+
}
if (removeApp) {
@@ -675,17 +668,17 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
return result.installError("getPackageArchiveInfo error.Please check whether APK is normal.");
}
- // Prevent cloning BlackBox app from within BlackBox
+
String packageName = packageArchiveInfo.packageName;
String hostPackageName = BlackBoxCore.getHostPkg();
if (packageName.equals(hostPackageName)) {
return result.installError("Cannot clone BlackBox app from within BlackBox. This would create infinite recursion and is not allowed for security reasons.");
}
- // Also check for common BlackBox-related package names to prevent cloning
+
if (packageName.contains("blackbox") || packageName.contains("niunaijun") ||
packageName.contains("vspace") || packageName.contains("virtual")) {
- // Allow this but log a warning
+
Slog.w(TAG, "Installing potentially BlackBox-related app: " + packageName + ". Proceed with caution.");
}
@@ -706,7 +699,7 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
}
BPackageSettings bPackageSettings = mSettings.getPackageLPw(aPackage.packageName, aPackage, option);
- // stop pkg
+
BProcessManagerService.get().killPackageAsUser(aPackage.packageName, userId);
int i = BPackageInstallerService.get().installPackageAsUser(bPackageSettings, userId);
@@ -752,17 +745,15 @@ public class BPackageManagerService extends IBPackageManagerService.Stub impleme
return processName;
}
- /**
- * Update given flags based on encryption status of current user.
- */
+
private int updateFlags(int flags, int userId) {
if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
- // Caller expressed an explicit opinion about what encryption
- // aware/unaware components they want to see, so fall through and
- // give them what they want
+
+
+
} else {
- // Caller expressed no opinion, so match based on user state
+
flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
}
return flags;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageSettings.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageSettings.java
index c4571be..1c1f704 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageSettings.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageSettings.java
@@ -16,14 +16,7 @@ import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.CloseUtils;
import top.niunaijun.blackbox.utils.FileUtils;
-/**
- * updated by alex5402 on 4/21/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BPackageSettings implements Parcelable {
public BPackage pkg;
public int appId;
@@ -76,7 +69,7 @@ public class BPackageSettings implements Parcelable {
state = new BPackageUserState();
}
state = new BPackageUserState(state);
- // xp模块所有用户可见、如果开启的话
+
if (userId == BUserHandle.USER_ALL) {
state.installed = true;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageUserState.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageUserState.java
index e5f593b..ddcb5e5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageUserState.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/BPackageUserState.java
@@ -3,14 +3,7 @@ package top.niunaijun.blackbox.core.system.pm;
import android.os.Parcel;
import android.os.Parcelable;
-/**
- * updated by alex5402 on 4/27/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BPackageUserState implements Parcelable {
public boolean installed;
public boolean stopped;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/ComponentResolver.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/ComponentResolver.java
index 84f8385..a42a377 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/ComponentResolver.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/ComponentResolver.java
@@ -15,41 +15,24 @@ import java.util.List;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/14/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ComponentResolver {
public static final String TAG = "ComponentResolver";
private final Object mLock = new Object();
- /**
- * All available activities, for your resolving pleasure.
- */
+
private final ActivityIntentResolver mActivities = new ActivityIntentResolver();
- /**
- * All available providers, for your resolving pleasure.
- */
+
private final ProviderIntentResolver mProviders = new ProviderIntentResolver();
- /**
- * All available receivers, for your resolving pleasure.
- */
+
private final ActivityIntentResolver mReceivers = new ActivityIntentResolver();
- /**
- * All available services, for your resolving pleasure.
- */
+
private final ServiceIntentResolver mServices = new ServiceIntentResolver();
- /**
- * Mapping from provider authority [first directory in content URI codePath) to provider.
- */
+
private final ArrayMap mProvidersByAuthority = new ArrayMap<>();
public ComponentResolver() {
@@ -88,9 +71,9 @@ public class ComponentResolver {
BPackage.Provider p = pkg.providers.get(i);
mProviders.removeProvider(p);
if (p.info.authority == null) {
- // Another content provider with this authority existed when this app was
- // installed, so this authority is null. Ignore it as we don't have to
- // unregister the provider.
+
+
+
continue;
}
String[] names = p.info.authority.split(";");
@@ -184,36 +167,28 @@ public class ComponentResolver {
}
- /**
- * Returns the given activity
- */
+
BPackage.Activity getActivity(ComponentName component) {
synchronized (mLock) {
return mActivities.mActivities.get(component);
}
}
- /**
- * Returns the given provider
- */
+
BPackage.Provider getProvider(ComponentName component) {
synchronized (mLock) {
return mProviders.mProviders.get(component);
}
}
- /**
- * Returns the given receiver
- */
+
BPackage.Activity getReceiver(ComponentName component) {
synchronized (mLock) {
return mReceivers.mActivities.get(component);
}
}
- /**
- * Returns the given service
- */
+
BPackage.Service getService(ComponentName component) {
synchronized (mLock) {
return mServices.mServices.get(component);
@@ -263,7 +238,7 @@ public class ComponentResolver {
if (processName != null && (!p.info.processName.equals(processName))) {
continue;
}
- // See PM.queryContentProviders()'s javadoc for why we have the metaData parameter.
+
if (metaDataKey != null
&& (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
continue;
@@ -272,9 +247,9 @@ public class ComponentResolver {
if (info == null) {
continue;
}
-// if (providerList == null) {
-// providerList = new ArrayList<>(i + 1);
-// }
+
+
+
providerList.add(info);
}
}
@@ -415,7 +390,7 @@ public class ComponentResolver {
return res;
}
- // Keys are String (activity class name), values are Activity.
+
private final ArrayMap mServices = new ArrayMap<>();
private int mFlags;
}
@@ -511,8 +486,8 @@ public class ComponentResolver {
}
res.priority = info.intentFilter.getPriority();
res.preferredOrder = activity.owner.mPreferredOrder;
- //System.out.println("Result: " + res.activityInfo.className +
- // " = " + res.priority);
+
+
res.match = match;
res.isDefault = info.hasDefault;
res.labelRes = info.labelRes;
@@ -521,7 +496,7 @@ public class ComponentResolver {
return res;
}
- // Keys are String (activity class name), values are Activity.
+
private final ArrayMap mActivities =
new ArrayMap<>();
private int mFlags;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/FastImmutableArraySet.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/FastImmutableArraySet.java
index 1744f12..f07f451 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/FastImmutableArraySet.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/FastImmutableArraySet.java
@@ -1,32 +1,11 @@
-/*
- * Copyright (C) 2011 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 top.niunaijun.blackbox.core.system.pm;
import java.util.AbstractSet;
import java.util.Iterator;
-/**
- * A fast immutable set wrapper for an array that is optimized for non-concurrent iteration.
- * The same iterator instance is reused each time to avoid creating lots of garbage.
- * Iterating over an array in this fashion is 2.5x faster than iterating over a {@link HashSet}
- * so it is worth copying the contents of the set to an array when iterating over it
- * hundreds of times.
- * @hide
- */
+
public final class FastImmutableArraySet extends AbstractSet {
FastIterator mIterator;
T[] mContents;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/IntentResolver.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/IntentResolver.java
index c823eed..d003ab7 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/IntentResolver.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/IntentResolver.java
@@ -1,18 +1,4 @@
-/*
- * 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 top.niunaijun.blackbox.core.system.pm;
@@ -38,9 +24,7 @@ import java.util.Set;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * {@hide}
- */
+
public abstract class IntentResolver {
final private static String TAG = "IntentResolver";
final private static boolean DEBUG = false;
@@ -128,14 +112,14 @@ public abstract class IntentResolver findFilters(IntentFilter matching) {
if (matching.countDataSchemes() == 1) {
- // Fast case.
+
return collectFilters(mSchemeToFilter.get(matching.getDataScheme(0)), matching);
} else if (matching.countDataTypes() != 0 && matching.countActions() == 1) {
- // Another fast case.
+
return collectFilters(mTypedActionToFilter.get(matching.getAction(0)), matching);
} else if (matching.countDataTypes() == 0 && matching.countDataSchemes() == 0
&& matching.countActions() == 1) {
- // Last fast case.
+
return collectFilters(mActionToFilter.get(matching.getAction(0)), matching);
} else {
ArrayList res = null;
@@ -267,16 +251,12 @@ public abstract class IntentResolver filterIterator() {
return new IteratorWrapper(mFilters.iterator());
}
- /**
- * Returns a read-only set of the filters.
- */
+
public Set filterSet() {
return Collections.unmodifiableSet(mFilters);
}
@@ -296,7 +276,7 @@ public abstract class IntentResolver 0) {
@@ -327,46 +307,46 @@ public abstract class IntentResolver dest) {
return true;
}
- /**
- * Returns whether the object associated with the given filter is
- * "stopped", that is whether it should not be included in the result
- * if the intent requests to excluded stopped objects.
- */
+
protected boolean isFilterStopped(F filter, int userId) {
return false;
}
- /**
- * Returns whether this filter is owned by this package. This must be
- * implemented to provide correct filtering of Intents that have
- * specified a package name they are to be delivered to.
- */
+
protected abstract boolean isPackageForFilter(String packageName, F filter);
protected abstract F[] newArray(int size);
@@ -438,9 +406,7 @@ public abstract class IntentResolver results) {
}
@@ -615,7 +581,7 @@ public abstract class IntentResolver mFilters = new HashSet<>();
- /**
- * All of the MIME types that have been registered, such as "image/jpeg",
- * "image/*", or "{@literal *}/*".
- */
+
private final ArrayMap mTypeToFilter = new ArrayMap();
- /**
- * The base names of all of all fully qualified MIME types that have been
- * registered, such as "image" or "*". Wild card MIME types such as
- * "image/*" will not be here.
- */
+
private final ArrayMap mBaseTypeToFilter = new ArrayMap();
- /**
- * The base names of all of the MIME types with a sub-type wildcard that
- * have been registered. For example, a filter with "image/*" will be
- * included here as "image" but one with "image/jpeg" will not be
- * included here. This also includes the "*" for the "{@literal *}/*"
- * MIME type.
- */
+
private final ArrayMap mWildTypeToFilter = new ArrayMap();
- /**
- * All of the URI schemes (such as http) that have been registered.
- */
+
private final ArrayMap mSchemeToFilter = new ArrayMap();
- /**
- * All of the actions that have been registered, but only those that did
- * not specify data.
- */
+
private final ArrayMap mActionToFilter = new ArrayMap();
- /**
- * All of the actions that have been registered and specified a MIME type.
- */
+
private final ArrayMap mTypedActionToFilter = new ArrayMap();
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageManagerCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageManagerCompat.java
index c610180..ab9983b 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageManagerCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageManagerCompat.java
@@ -33,14 +33,7 @@ import top.niunaijun.blackbox.utils.ArrayUtils;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 4/15/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@SuppressLint({"SdCardPath", "NewApi"})
public class PackageManagerCompat {
@@ -130,7 +123,7 @@ public class PackageManagerCompat {
final ServiceInfo[] res = new ServiceInfo[N];
for (int i = 0; i < N; i++) {
final BPackage.Service s = p.services.get(i);
- //res[num++] = generateServiceInfo(s, flags, state, userId);
+
ServiceInfo serviceInfo = generateServiceInfo(s, flags, state, userId);
if(serviceInfo == null) continue;
if ((flags & PackageManager.GET_META_DATA) != 0) {
@@ -188,11 +181,11 @@ public class PackageManagerCompat {
for (int i = 0; i < N; i++) {
final String perm = p.requestedPermissions.get(i);
pi.requestedPermissions[i] = perm;
- // The notion of required permissions is deprecated but for compatibility.
-// pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
-// if (grantedPermissions != null && grantedPermissions.contains(perm)) {
-// pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
-// }
+
+
+
+
+
}
}
}
@@ -226,7 +219,7 @@ public class PackageManagerCompat {
if (!checkUseInstalledOrHidden(flags, state, a.info.applicationInfo)) {
return null;
}
- // Make shallow copies so we can store the metadata safely
+
ActivityInfo ai = new ActivityInfo(a.info);
ai.metaData = a.metaData;
ai.processName = BPackageManagerService.fixProcessName(ai.packageName, ai.processName);
@@ -238,7 +231,7 @@ public class PackageManagerCompat {
if (!checkUseInstalledOrHidden(flags, state, s.info.applicationInfo)) {
return null;
}
- // Make shallow copies so we can store the metadata safely
+
ServiceInfo si = new ServiceInfo(s.info);
si.metaData = s.metaData;
si.processName = BPackageManagerService.fixProcessName(si.packageName, si.processName);
@@ -250,7 +243,7 @@ public class PackageManagerCompat {
if (!checkUseInstalledOrHidden(flags, state, p.info.applicationInfo)) {
return null;
}
- // Make shallow copies so we can store the metadata safely
+
ProviderInfo pi = new ProviderInfo(p.info);
if (pi.authority == null)
return null;
@@ -312,7 +305,7 @@ public class PackageManagerCompat {
ai.publicSourceDir = sourceDir;
ai.sourceDir = sourceDir;
ai.uid = p.mExtras.appId;
-// ai.uid = baseApplication.uid;
+
if (BuildCompat.isL()) {
BRApplicationInfoL.get(ai)._set_primaryCpuAbi(Build.CPU_ABI);
@@ -343,7 +336,7 @@ public class PackageManagerCompat {
ApplicationInfo appInfo) {
if (AppSystemEnv.isBlackPackage(appInfo.packageName))
return false;
- // Returns false if the package is hidden system app until installed.
+
if (!state.installed || state.hidden) {
return false;
}
@@ -363,11 +356,11 @@ public class PackageManagerCompat {
} else {
sharedLibraryFileList.add(APACHE_LEGACY_JAR);
}
-// if (BXposedManagerService.get().isXPEnable()) {
-// ApplicationInfo base = BlackBoxCore.getContext().getApplicationInfo();
-// sharedLibraryFileList.add(base.sourceDir);
-// }
-// sharedLibraryFileList.add(BEnvironment.JUNIT_JAR.getAbsolutePath());
+
+
+
+
+
info.sharedLibraryFiles = sharedLibraryFileList.toArray(new String[]{});
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageMonitor.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageMonitor.java
index 54cc532..1cb84af 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageMonitor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/PackageMonitor.java
@@ -1,13 +1,6 @@
package top.niunaijun.blackbox.core.system.pm;
-/**
- * updated by alex5402 on 5/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public interface PackageMonitor {
void onPackageUninstalled(String packageName, boolean isRemove, int userId);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/Settings.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/Settings.java
index 2b49db8..33edc28 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/Settings.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/Settings.java
@@ -24,15 +24,8 @@ import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
-/**
- * updated by alex5402 on 4/13/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
-/*public*/ class Settings {
+
+ class Settings {
public static final String TAG = "Settings";
final ArrayMap mPackages = new ArrayMap<>();
@@ -87,15 +80,15 @@ import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
Slog.d(TAG, p.pkg.packageName + " sharedUserId = " + sharedUserId + ", setAppId = " + p.appId);
}
if (p.appId == 0) {
- // Assign new user ID
+
p.appId = acquireAndRegisterNewAppIdLPw(p);
}
if (p.appId < 0) {
createdNew = false;
-// PackageManagerService.reportSettingsProblem(Log.WARN,
-// "Package " + p.name + " could not be assigned a valid UID");
-// throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-// "Package " + p.name + " could not be assigned a valid UID");
+
+
+
+
} else {
createdNew = true;
}
@@ -105,7 +98,7 @@ import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
}
private int acquireAndRegisterNewAppIdLPw(BPackageSettings obj) {
- // Let's be stupidly inefficient for now...
+
Integer integer = mAppIds.get(obj.pkg.packageName);
if (integer != null)
return integer;
@@ -148,7 +141,7 @@ import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
try {
byte[] uidBytes = FileUtils.toByteArray(BEnvironment.getUidConf());
if (uidBytes == null || uidBytes.length == 0) {
- // No data to load, start fresh
+
return;
}
@@ -162,15 +155,15 @@ import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
mAppIds.putAll(hashMap);
}
} catch (Exception e) {
- // If loading fails, clear the corrupted data and start fresh
+
try {
- // Delete the corrupted file
+
BEnvironment.getUidConf().delete();
} catch (Exception deleteException) {
- // Ignore delete errors
+
}
- // Reset to default values
+
mCurrUid = 0;
synchronized (mAppIds) {
mAppIds.clear();
@@ -216,7 +209,7 @@ import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
PackageInfo packageInfo = BlackBoxCore.getPackageManager().getPackageInfo(packageName, PackageManager.GET_META_DATA);
String currPackageSourcePath = packageInfo.applicationInfo.sourceDir;
if (!currPackageSourcePath.equals(bPackageSettings.pkg.baseCodePath)) {
- // update baseCodePath And Re install
+
BProcessManagerService.get().killAllByPackageName(bPackageSettings.pkg.packageName);
BPackageSettings newPkg = reInstallBySystem(packageInfo, bPackageSettings.installOption);
bPackageSettings.pkg = newPkg.pkg;
@@ -229,7 +222,7 @@ import top.niunaijun.blackbox.utils.compat.PackageParserCompat;
Slog.d(TAG, "loaded Package: " + packageName);
} catch (Throwable e) {
e.printStackTrace();
- // bad package
+
FileUtils.deleteDir(app);
removePackage(packageName);
BProcessManagerService.get().killAllByPackageName(packageName);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/SharedUserSetting.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/SharedUserSetting.java
index d94d634..59aab5c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/SharedUserSetting.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/SharedUserSetting.java
@@ -1,18 +1,4 @@
-/*
- * Copyright (C) 2011 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 top.niunaijun.blackbox.core.system.pm;
@@ -28,9 +14,7 @@ import top.niunaijun.blackbox.core.env.BEnvironment;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Settings data for a particular shared user ID we know about.
- */
+
public final class SharedUserSetting implements Parcelable {
public static final String TAG = "SharedUserSetting";
public static final Map sSharedUsers = new HashMap<>();
@@ -38,8 +22,8 @@ public final class SharedUserSetting implements Parcelable {
String name;
int userId;
- // The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so
- // that all apps within the sharedUser run in the same selinux context.
+
+
int seInfoTargetSdkVersion;
SharedUserSetting(String _name) {
@@ -47,7 +31,7 @@ public final class SharedUserSetting implements Parcelable {
}
SharedUserSetting() {
- // Default constructor for Parcelable
+
}
@Override
@@ -79,13 +63,13 @@ public final class SharedUserSetting implements Parcelable {
try {
byte[] sharedUsersBytes = FileUtils.toByteArray(BEnvironment.getSharedUserConf());
if (sharedUsersBytes == null || sharedUsersBytes.length == 0) {
- // No data to load, start fresh
+
return;
}
- // Check if this is old format data (before seInfoTargetSdkVersion was added)
- // If the data is too small, it's likely the old format
- if (sharedUsersBytes.length < 100) { // Arbitrary threshold for old format
+
+
+ if (sharedUsersBytes.length < 100) {
Slog.w(TAG, "Detected old format SharedUserSetting data, clearing for fresh start");
BEnvironment.getSharedUserConf().delete();
synchronized (sSharedUsers) {
@@ -103,15 +87,15 @@ public final class SharedUserSetting implements Parcelable {
sSharedUsers.putAll(hashMap);
}
} catch (Exception e) {
- // If loading fails, clear the corrupted data and start fresh
+
try {
- // Delete the corrupted file
+
BEnvironment.getSharedUserConf().delete();
} catch (Exception deleteException) {
- // Ignore delete errors
+
}
- // Clear the shared users map to start fresh
+
synchronized (sSharedUsers) {
sSharedUsers.clear();
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CopyExecutor.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CopyExecutor.java
index 2fccc00..b8325a2 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CopyExecutor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CopyExecutor.java
@@ -10,15 +10,7 @@ import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.FileUtils;
import top.niunaijun.blackbox.utils.NativeUtils;
-/**
- * updated by alex5402 on 4/24/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- * 拷贝文件相关
- */
+
public class CopyExecutor implements Executor {
@Override
@@ -32,7 +24,7 @@ public class CopyExecutor implements Executor {
return -1;
}
if (option.isFlag(InstallOption.FLAG_STORAGE)) {
- // 外部安装
+
File origFile = new File(ps.pkg.baseCodePath);
File newFile = BEnvironment.getBaseApkDir(ps.pkg.packageName);
try {
@@ -45,14 +37,14 @@ public class CopyExecutor implements Executor {
FileUtils.copyFile(origFile, newFile);
}
newFile.setReadOnly();
- // update baseCodePath
+
ps.pkg.baseCodePath = newFile.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
return -1;
}
} else if (option.isFlag(InstallOption.FLAG_SYSTEM)) {
- // 系统安装
+
}
return 0;
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreatePackageExecutor.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreatePackageExecutor.java
index 6614d46..fc5375e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreatePackageExecutor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreatePackageExecutor.java
@@ -5,22 +5,14 @@ import top.niunaijun.blackbox.core.system.pm.BPackageSettings;
import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.FileUtils;
-/**
- * updated by alex5402 on 4/24/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- * 创建包相关的信息
- */
+
public class CreatePackageExecutor implements Executor {
@Override
public int exec(BPackageSettings ps, InstallOption option, int userId) {
FileUtils.deleteDir(BEnvironment.getAppDir(ps.pkg.packageName));
- // create app dir
+
FileUtils.mkdirs(BEnvironment.getAppDir(ps.pkg.packageName));
FileUtils.mkdirs(BEnvironment.getAppLibDir(ps.pkg.packageName));
return 0;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreateUserExecutor.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreateUserExecutor.java
index 2bc7ca7..7aa74f5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreateUserExecutor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/CreateUserExecutor.java
@@ -5,15 +5,7 @@ import top.niunaijun.blackbox.core.system.pm.BPackageSettings;
import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.FileUtils;
-/**
- * updated by alex5402 on 4/24/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- * 创建用户相关
- */
+
public class CreateUserExecutor implements Executor {
@Override
@@ -21,20 +13,20 @@ public class CreateUserExecutor implements Executor {
String packageName = ps.pkg.packageName;
FileUtils.deleteDir(BEnvironment.getDataLibDir(packageName, userId));
- // create user dir
+
FileUtils.mkdirs(BEnvironment.getDataDir(packageName, userId));
FileUtils.mkdirs(BEnvironment.getDataCacheDir(packageName, userId));
FileUtils.mkdirs(BEnvironment.getDataFilesDir(packageName, userId));
FileUtils.mkdirs(BEnvironment.getDataDatabasesDir(packageName, userId));
FileUtils.mkdirs(BEnvironment.getDeDataDir(packageName, userId));
-// try {
-// // /data/data/xx/lib -> /data/app/xx/lib
-// FileUtils.createSymlink(BEnvironment.getAppLibDir(ps.pkg.packageName).getAbsolutePath(), BEnvironment.getDataLibDir(packageName, userId).getAbsolutePath());
-// } catch (Exception e) {
-// e.printStackTrace();
-// return -1;
-// }
+
+
+
+
+
+
+
return 0;
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/Executor.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/Executor.java
index 5201b29..4c69384 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/Executor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/Executor.java
@@ -3,14 +3,7 @@ package top.niunaijun.blackbox.core.system.pm.installer;
import top.niunaijun.blackbox.core.system.pm.BPackageSettings;
import top.niunaijun.blackbox.entity.pm.InstallOption;
-/**
- * updated by alex5402 on 4/24/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public interface Executor {
public static final String TAG = "InstallExecutor";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveAppExecutor.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveAppExecutor.java
index 355f97b..e13111b 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveAppExecutor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveAppExecutor.java
@@ -5,14 +5,7 @@ import top.niunaijun.blackbox.core.system.pm.BPackageSettings;
import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.FileUtils;
-/**
- * updated by alex5402 on 4/27/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class RemoveAppExecutor implements Executor {
@Override
public int exec(BPackageSettings ps, InstallOption option, int userId) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveUserExecutor.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveUserExecutor.java
index 58cb87c..2a8aace 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveUserExecutor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/pm/installer/RemoveUserExecutor.java
@@ -5,21 +5,13 @@ import top.niunaijun.blackbox.core.system.pm.BPackageSettings;
import top.niunaijun.blackbox.entity.pm.InstallOption;
import top.niunaijun.blackbox.utils.FileUtils;
-/**
- * updated by alex5402 on 4/24/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- * 创建用户相关
- */
+
public class RemoveUserExecutor implements Executor {
@Override
public int exec(BPackageSettings ps, InstallOption option, int userId) {
String packageName = ps.pkg.packageName;
- // delete user dir
+
FileUtils.deleteDir(BEnvironment.getDataDir(packageName, userId));
FileUtils.deleteDir(BEnvironment.getDeDataDir(packageName, userId));
FileUtils.deleteDir(BEnvironment.getExternalDataDir(packageName, userId));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserHandle.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserHandle.java
index beadd4d..72cf572 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserHandle.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserHandle.java
@@ -1,18 +1,4 @@
-/*
- * Copyright (C) 2011 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 top.niunaijun.blackbox.core.system.user;
@@ -21,152 +7,83 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
-/**
- * Representation of a user on the device.
- */
-public final class BUserHandle implements Parcelable {
- // NOTE: keep logic in sync with system/core/libcutils/multiuser.c
- /**
- * @hide Range of uids allocated for a user.
- */
+public final class BUserHandle implements Parcelable {
+
+
+
public static final int PER_USER_RANGE = 100000;
- /**
- * @hide A user id to indicate all users on the device
- */
+
public static final int USER_ALL = -1;
- /**
- * @hide A user handle to indicate all users on the device
- */
+
public static final BUserHandle ALL = new BUserHandle(USER_ALL);
- /**
- * @hide A user id to indicate the currently active user
- */
+
public static final int USER_CURRENT = -2;
- /**
- * @hide A user handle to indicate the current user of the device
- */
+
public static final BUserHandle CURRENT = new BUserHandle(USER_CURRENT);
- /**
- * @hide A user id to indicate that we would like to send to the current
- * user, but if this is calling from a user process then we will send it
- * to the caller's user instead of failing with a security exception
- */
+
public static final int USER_CURRENT_OR_SELF = -3;
- /**
- * @hide A user handle to indicate that we would like to send to the current
- * user, but if this is calling from a user process then we will send it
- * to the caller's user instead of failing with a security exception
- */
+
public static final BUserHandle CURRENT_OR_SELF = new BUserHandle(USER_CURRENT_OR_SELF);
- /**
- * @hide An undefined user id
- */
+
public static final int USER_NULL = -10000;
- /**
- * @hide A user id constant to indicate the "owner" user of the device
- * @deprecated Consider using either {@link BUserHandle#USER_SYSTEM} constant or
- * check the target user's flag {@link }.
- */
+
@Deprecated
public static final int USER_OWNER = 0;
- /**
- * @hide A user handle to indicate the primary/owner user of the device
- * @deprecated Consider using either {@link BUserHandle#SYSTEM} constant or
- * check the target user's flag {@link }.
- */
+
@Deprecated
public static final BUserHandle OWNER = new BUserHandle(USER_OWNER);
- /**
- * @hide A user id constant to indicate the "system" user of the device
- */
+
public static final int USER_SYSTEM = 0;
- /**
- * @hide A user serial constant to indicate the "system" user of the device
- */
+
public static final int USER_SERIAL_SYSTEM = 0;
- /**
- * @hide A user handle to indicate the "system" user of the device
- */
+
public static final BUserHandle SYSTEM = new BUserHandle(USER_SYSTEM);
- /**
- * @hide Enable multi-user related side effects. Set this to false if
- * there are problems with single user use-cases.
- */
+
public static final boolean MU_ENABLED = true;
- /**
- * @hide
- */
+
public static final int ERR_GID = -1;
- /**
- * @hide
- */
+
public static final int AID_ROOT = 0;
- /**
- * @hide
- */
+
public static final int AID_APP_START = android.os.Process.FIRST_APPLICATION_UID;
- /**
- * @hide
- */
+
public static final int AID_APP_END = android.os.Process.LAST_APPLICATION_UID;
- /**
- * @hide
- */
+
public static final int AID_SHARED_GID_START = 50000;
- /**
- * @hide
- */
+
public static final int AID_CACHE_GID_START = 20000;
final int mHandle;
- /**
- * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
- * user.
- *
- * @hide
- */
+
public static boolean isSameUser(int uid1, int uid2) {
return getUserId(uid1) == getUserId(uid2);
}
- /**
- * Checks to see if both uids are referring to the same app id, ignoring the user id part of the
- * uids.
- *
- * @param uid1 uid to compare
- * @param uid2 other uid to compare
- * @return whether the appId is the same for both uids
- * @hide
- */
+
public static boolean isSameApp(int uid1, int uid2) {
return getAppId(uid1) == getAppId(uid2);
}
- /**
- * Whether a UID belongs to a regular app. *Note* "Not a regular app" does not mean
- * "it's system", because of isolated UIDs. Use {@link #isCore} for that.
- *
- * @hide
- */
+
public static boolean isApp(int uid) {
if (uid > 0) {
final int appId = getAppId(uid);
@@ -176,11 +93,7 @@ public final class BUserHandle implements Parcelable {
}
}
- /**
- * Whether a UID belongs to a system core component or not.
- *
- * @hide
- */
+
public static boolean isCore(int uid) {
if (uid >= 0) {
final int appId = getAppId(uid);
@@ -190,21 +103,12 @@ public final class BUserHandle implements Parcelable {
}
}
- /**
- * Returns the user for a given uid.
- *
- * @param uid A uid for an application running in a particular user.
- * @return A {@link BUserHandle} for that user.
- */
+
public static BUserHandle getUserHandleForUid(int uid) {
return of(getUserId(uid));
}
- /**
- * Returns the user id for a given uid.
- *
- * @hide
- */
+
public static int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
@@ -213,32 +117,22 @@ public final class BUserHandle implements Parcelable {
}
}
- /**
- * @hide
- */
+
public static int getCallingUserId() {
return getUserId(Binder.getCallingUid());
}
- /**
- * @hide
- */
+
public static int getCallingAppId() {
return getAppId(Binder.getCallingUid());
}
- /**
- * @hide
- */
+
public static BUserHandle of(int userId) {
return userId == USER_SYSTEM ? SYSTEM : new BUserHandle(userId);
}
- /**
- * Returns the uid that is composed from the userId and the appId.
- *
- * @hide
- */
+
public static int getUid(int userId, int appId) {
if (MU_ENABLED) {
return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
@@ -247,34 +141,22 @@ public final class BUserHandle implements Parcelable {
}
}
- /**
- * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
- *
- * @hide
- */
+
public static int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
- /**
- * Returns the gid shared between all apps with this userId.
- *
- * @hide
- */
+
public static int getUserGid(int userId) {
- return getUid(userId, 9997 /*Process.SHARED_USER_GID*/);
+ return getUid(userId, 9997 );
}
- /**
- * @hide
- */
+
public static int getSharedAppGid(int uid) {
return getSharedAppGid(getUserId(uid), getAppId(uid));
}
- /**
- * @hide
- */
+
public static int getSharedAppGid(int userId, int appId) {
if (appId >= AID_APP_START && appId <= AID_APP_END) {
return (appId - AID_APP_START) + AID_SHARED_GID_START;
@@ -285,29 +167,22 @@ public final class BUserHandle implements Parcelable {
}
}
- /**
- * Returns the app id for a given shared app gid. Returns -1 if the ID is invalid.
- * @hide
- */
-// public static int getAppIdFromSharedAppGid(int gid) {
-// final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID
-// - Process.FIRST_SHARED_APPLICATION_GID;
-// if (appId < 0 || appId >= Process.FIRST_SHARED_APPLICATION_GID) {
-// return -1;
-// }
-// return appId;
-// }
+
- /**
- * @hide
- */
+
+
+
+
+
+
+
+
+
public static int getCacheAppGid(int uid) {
return getCacheAppGid(getUserId(uid), getAppId(uid));
}
- /**
- * @hide
- */
+
public static int getCacheAppGid(int userId, int appId) {
if (appId >= AID_APP_START && appId <= AID_APP_END) {
return getUid(userId, (appId - AID_APP_START) + AID_CACHE_GID_START);
@@ -316,9 +191,7 @@ public final class BUserHandle implements Parcelable {
}
}
- /**
- * @hide
- */
+
public static int parseUserArg(String arg) {
int userId;
if ("all".equals(arg)) {
@@ -335,48 +208,28 @@ public final class BUserHandle implements Parcelable {
return userId;
}
- /**
- * Returns the user id of the current process
- *
- * @return user id of the current process
- * @hide
- */
+
public static int myUserId() {
return getUserId(Process.myUid());
}
- /**
- * Returns true if this UserHandle refers to the owner user; false otherwise.
- *
- * @return true if this UserHandle refers to the owner user; false otherwise.
- * @hide
- * @deprecated please use {@link #isSystem()} or check for
- */
+
@Deprecated
public boolean isOwner() {
return this.equals(OWNER);
}
- /**
- * @return true if this UserHandle refers to the system user; false otherwise.
- * @hide
- */
+
public boolean isSystem() {
return this.equals(SYSTEM);
}
- /**
- * @hide
- */
+
public BUserHandle(int h) {
mHandle = h;
}
- /**
- * Returns the userId stored in this UserHandle.
- *
- * @hide
- */
+
public int getIdentifier() {
return mHandle;
}
@@ -411,14 +264,7 @@ public final class BUserHandle implements Parcelable {
out.writeInt(mHandle);
}
- /**
- * Write a UserHandle to a Parcel, handling null pointers. Must be
- * read with {@link #readFromParcel(Parcel)}.
- *
- * @param h The UserHandle to be written.
- * @param out The Parcel in which the UserHandle will be placed.
- * @see #readFromParcel(Parcel)
- */
+
public static void writeToParcel(BUserHandle h, Parcel out) {
if (h != null) {
h.writeToParcel(out, 0);
@@ -427,16 +273,7 @@ public final class BUserHandle implements Parcelable {
}
}
- /**
- * Read a UserHandle from a Parcel that was previously written
- * with {@link #writeToParcel(BUserHandle, Parcel)}, returning either
- * a null or new object as appropriate.
- *
- * @param in The Parcel from which to read the UserHandle
- * @return Returns a new UserHandle matching the previously written
- * object, or null if a null had been written.
- * @see #writeToParcel(BUserHandle, Parcel)
- */
+
public static BUserHandle readFromParcel(Parcel in) {
int h = in.readInt();
return h != USER_NULL ? new BUserHandle(h) : null;
@@ -453,16 +290,7 @@ public final class BUserHandle implements Parcelable {
}
};
- /**
- * Instantiate a new UserHandle from the data in a Parcel that was
- * previously written with {@link #writeToParcel(Parcel, int)}. Note that you
- * must not use this with data written by
- * {@link #writeToParcel(BUserHandle, Parcel)} since it is not possible
- * to handle a null UserHandle here.
- *
- * @param in The Parcel containing the previously written UserHandle,
- * positioned at the location in the buffer where it was written.
- */
+
public BUserHandle(Parcel in) {
mHandle = in.readInt();
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserInfo.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserInfo.java
index 87ba6ec..1e17573 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserInfo.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserInfo.java
@@ -3,14 +3,7 @@ package top.niunaijun.blackbox.core.system.user;
import android.os.Parcel;
import android.os.Parcelable;
-/**
- * updated by alex5402 on 4/22/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BUserInfo implements Parcelable {
public int id;
public BUserStatus status;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserManagerService.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserManagerService.java
index 8c10ba5..4a256a1 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserManagerService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserManagerService.java
@@ -20,14 +20,7 @@ import top.niunaijun.blackbox.core.system.pm.BPackageManagerService;
import top.niunaijun.blackbox.utils.CloseUtils;
import top.niunaijun.blackbox.utils.FileUtils;
-/**
- * updated by alex5402 on 4/22/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BUserManagerService extends IBUserManagerService.Stub implements ISystemService {
private static BUserManagerService sService = new BUserManagerService();
public final HashMap mUsers = new HashMap<>();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserStatus.java b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserStatus.java
index 4550ca8..cda5c59 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserStatus.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/core/system/user/BUserStatus.java
@@ -1,13 +1,6 @@
package top.niunaijun.blackbox.core.system.user;
-/**
- * updated by alex5402 on 4/22/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public enum BUserStatus {
ENABLE, DISABLE
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/AppConfig.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/AppConfig.java
index 2356d86..9c4d225 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/AppConfig.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/AppConfig.java
@@ -5,14 +5,7 @@ import android.os.Parcel;
import android.os.Parcelable;
-/**
- * updated by alex5402 on 4/1/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class AppConfig implements Parcelable {
public static final String KEY = "BlackBox_client_config";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/JobRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/JobRecord.java
index 002d950..1d055b7 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/JobRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/JobRecord.java
@@ -7,14 +7,7 @@ import android.os.Parcel;
import android.os.Parcelable;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class JobRecord implements Parcelable {
public JobInfo mJobInfo;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/ServiceRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/ServiceRecord.java
index ede2a15..c93fd3d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/ServiceRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/ServiceRecord.java
@@ -9,14 +9,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
-/**
- * updated by alex5402 on 4/7/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ServiceRecord {
private Service mService;
private Map mBounds = new HashMap<>();
@@ -103,7 +96,7 @@ public class ServiceRecord {
return true;
int i = boundInfo.decrementAndGetBindCount();
if (i <= 0) {
-// mBounds.remove(filterComparison);
+
return true;
}
return false;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/UnbindRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/UnbindRecord.java
index ecf48e2..d8a880d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/UnbindRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/UnbindRecord.java
@@ -4,14 +4,7 @@ import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
-/**
- * updated by alex5402 on 4/7/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class UnbindRecord implements Parcelable {
private int mBindCount;
private int mStartId;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/PendingResultData.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/PendingResultData.java
index f988f04..3d6dc85 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/PendingResultData.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/PendingResultData.java
@@ -14,9 +14,7 @@ import black.android.content.BroadcastReceiverPendingResultContext;
import black.android.content.BroadcastReceiverPendingResultMContext;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Created by BlackBox on 2022/2/28.
- */
+
public class PendingResultData implements Parcelable {
public int mType;
public boolean mOrderedHint;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/ReceiverData.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/ReceiverData.java
index 2bea000..a550a3e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/ReceiverData.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/ReceiverData.java
@@ -5,9 +5,7 @@ import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
-/**
- * Created by BlackBox on 2022/2/28.
- */
+
public class ReceiverData implements Parcelable {
public Intent intent;
public ActivityInfo activityInfo;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningAppProcessInfo.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningAppProcessInfo.java
index cff3a9a..c1b9d17 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningAppProcessInfo.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningAppProcessInfo.java
@@ -7,9 +7,7 @@ import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
-/**
- * Created by BlackBox on 2022/2/25.
- */
+
public class RunningAppProcessInfo implements Parcelable {
public List mAppProcessInfoList;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningServiceInfo.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningServiceInfo.java
index d8f3233..253268f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningServiceInfo.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/am/RunningServiceInfo.java
@@ -7,9 +7,7 @@ import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
-/**
- * Created by BlackBox on 2022/2/25.
- */
+
public class RunningServiceInfo implements Parcelable {
public List mRunningServiceInfoList;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BCell.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BCell.java
index 7e4523e..5d16e8c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BCell.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BCell.java
@@ -2,23 +2,9 @@ package top.niunaijun.blackbox.entity.location;
import android.os.Parcel;
import android.os.Parcelable;
-/*
- * created by BlackBoxing at 2022/03/06
- * */
+
public class BCell implements Parcelable {
- /**
- * mnc : 1
- * lac : 41093
- * ci : 3865320
- * acc : 1177
- * location : {"lon":116.343278,"lat":39.531734}
- * reference blog: https://liuschen.top/2016/09/15/BLocation.html
- * MCC,Mobile Country Code,移动国家代码(中国的为460);
- * MNC,Mobile Network Code,移动网络号码(00移动 01联通 11电信4G);
- * LAC/TAC(1~65535),Location Area Code,位置区域码;
- * CID/CI( 2G(1~65535), 3G/4G(1~268435455)),Cell Identity,基站编号;
- * TYPE: Cdma/Lte/Gsm/Wcdma
- */
+
public int MCC;
public int MNC;
@@ -26,32 +12,25 @@ public class BCell implements Parcelable {
public int CID;
public int TYPE;
public static final int NETWORK_TYPE_UNKNOWN = 0;
- /** Current network is GPRS */
+
public static final int NETWORK_TYPE_GPRS = 1;
- /** Current network is EDGE */
+
public static final int NETWORK_TYPE_EDGE = 2;
- /** Current network is UMTS */
+
public static final int NETWORK_TYPE_UMTS = 3;
- /** Current network is CDMA: Either IS95A or IS95B*/
+
public static final int NETWORK_TYPE_CDMA = 4;
- /** Current network is EVDO revision 0*/
+
public static final int NETWORK_TYPE_EVDO_0 = 5;
- /** Current network is EVDO revision A*/
+
public static final int NETWORK_TYPE_EVDO_A = 6;
- /** Current network is 1xRTT*/
+
public static final int NETWORK_TYPE_1xRTT = 7;
- /**
- * No phone module
- *
- */
+
public static final int PHONE_TYPE_NONE = 0;
- /**
- * GSM phone
- */
+
public static final int PHONE_TYPE_GSM = 1;
- /**
- * CDMA phone
- */
+
public static final int PHONE_TYPE_CDMA = 2;
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocation.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocation.java
index 83755f9..2bac571 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocation.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocation.java
@@ -1,18 +1,4 @@
-/*
- * Copyright (C) 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 top.niunaijun.blackbox.entity.location;
import android.location.Location;
@@ -21,9 +7,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-/*
- * created by BlackBoxing at 2022/03/05
- * */
+
public class BLocation implements Parcelable {
private double mLatitude = 0.0;
@@ -32,10 +16,10 @@ public class BLocation implements Parcelable {
private float mSpeed = 0.0f;
private float mBearing = 0.0f;
private float mAccuracy = 0.0f;
-// private float mHorizontalAccuracyMeters = 0.0f;
-// private float mVerticalAccuracyMeters = 0.0f;
-// private float mSpeedAccuracyMetersPerSecond = 0.0f;
-// private float mBearingAccuracyDegrees = 0.0f;
+
+
+
+
@Override
public int describeContents() {
@@ -114,7 +98,7 @@ public class BLocation implements Parcelable {
location.setAccuracy(40f);
location.setTime(System.currentTimeMillis());
Bundle extraBundle = new Bundle();
- // GPS satellite number
+
int satelliteCount = 10;
extraBundle.putInt("satellites", satelliteCount);
extraBundle.putInt("satellitesvalue", satelliteCount);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocationConfig.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocationConfig.java
index 2798d7d..44ee02f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocationConfig.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/location/BLocationConfig.java
@@ -5,9 +5,7 @@ import android.os.Parcelable;
import java.util.List;
-/**
- * Created by BlackBoxing on 3/8/22.
- **/
+
public class BLocationConfig implements Parcelable {
public int pattern;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallOption.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallOption.java
index e7db4bd..f27b12a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallOption.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallOption.java
@@ -3,14 +3,7 @@ package top.niunaijun.blackbox.entity.pm;
import android.os.Parcel;
import android.os.Parcelable;
-/**
- * updated by alex5402 on 4/21/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class InstallOption implements Parcelable {
public static final int FLAG_SYSTEM = 1;
public static final int FLAG_STORAGE = 1 << 1;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallResult.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallResult.java
index 59c2dce..847ff73 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallResult.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstallResult.java
@@ -5,14 +5,7 @@ import android.os.Parcelable;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/20/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class InstallResult implements Parcelable {
public static final String TAG = "InstallResult";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstalledPackage.java b/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstalledPackage.java
index 047f0ba..2aebd5f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstalledPackage.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/entity/pm/InstalledPackage.java
@@ -10,14 +10,7 @@ import java.util.Objects;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * updated by alex5402 on 4/20/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class InstalledPackage implements Parcelable {
public int userId;
public String packageName;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/FakeCore.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/FakeCore.java
index cd618e6..8d13e1e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/FakeCore.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/FakeCore.java
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.fake;
import top.niunaijun.jnihook.ReflectCore;
-/**
- * updated by alex5402 on 2021/5/7.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class FakeCore {
public static void init() {
ReflectCore.set(android.app.ActivityThread.class);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/BaseInstrumentationDelegate.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/BaseInstrumentationDelegate.java
index 997e510..88aaddd 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/BaseInstrumentationDelegate.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/BaseInstrumentationDelegate.java
@@ -60,17 +60,17 @@ public class BaseInstrumentationDelegate extends Instrumentation {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mBaseInstrumentation.addResults(results);
} else {
- // For Android versions below API 26 (Oreo), implement alternative result handling
+
try {
- // Store results in a way that's compatible with older Android versions
+
if (results != null && !results.isEmpty()) {
- // Use sendStatus to send results (available on all Android versions)
+
mBaseInstrumentation.sendStatus(0, results);
- // Alternative: Store results in a static map for later retrieval
+
storeResultsForOlderVersions(results);
- // Alternative: Use SharedPreferences to store results
+
storeResultsInPreferences(results);
}
} catch (Exception e) {
@@ -79,16 +79,14 @@ public class BaseInstrumentationDelegate extends Instrumentation {
}
}
- /**
- * Store results in a static map for older Android versions
- */
+
private void storeResultsForOlderVersions(Bundle results) {
try {
- // Use reflection to access a static results storage
+
Class> resultsStorageClass = Class.forName("top.niunaijun.blackbox.utils.ResultsStorage");
java.lang.reflect.Method storeMethod = resultsStorageClass.getMethod("storeResults", String.class, Bundle.class);
- // Generate a unique key for these results
+
String resultKey = "results_" + System.currentTimeMillis() + "_" + android.os.Process.myPid();
storeMethod.invoke(null, resultKey, results);
@@ -98,9 +96,7 @@ public class BaseInstrumentationDelegate extends Instrumentation {
}
}
- /**
- * Store results in SharedPreferences for older Android versions
- */
+
private void storeResultsInPreferences(Bundle results) {
try {
Context context = getContext();
@@ -108,7 +104,7 @@ public class BaseInstrumentationDelegate extends Instrumentation {
android.content.SharedPreferences prefs = context.getSharedPreferences("instrumentation_results", Context.MODE_PRIVATE);
android.content.SharedPreferences.Editor editor = prefs.edit();
- // Convert Bundle to key-value pairs and store in preferences
+
for (String key : results.keySet()) {
Object value = results.get(key);
if (value instanceof String) {
@@ -124,7 +120,7 @@ public class BaseInstrumentationDelegate extends Instrumentation {
}
}
- // Add timestamp for result identification
+
editor.putLong("timestamp", System.currentTimeMillis());
editor.putInt("pid", android.os.Process.myPid());
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ContentProviderDelegate.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ContentProviderDelegate.java
index a553cf0..5e4a27d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ContentProviderDelegate.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ContentProviderDelegate.java
@@ -24,14 +24,7 @@ import top.niunaijun.blackbox.fake.service.context.providers.ContentProviderStub
import top.niunaijun.blackbox.fake.service.context.providers.SystemProviderStub;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ContentProviderDelegate {
public static final String TAG = "ContentProviderDelegate";
private static Set sInjected = new HashSet<>();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/InnerReceiverDelegate.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/InnerReceiverDelegate.java
index 8535d9b..3f8c57e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/InnerReceiverDelegate.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/InnerReceiverDelegate.java
@@ -15,14 +15,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.proxy.record.ProxyBroadcastRecord;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class InnerReceiverDelegate extends IIntentReceiver.Stub {
public static final String TAG = "InnerReceiverDelegate";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ServiceConnectionDelegate.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ServiceConnectionDelegate.java
index 2075598..3da6bdb 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ServiceConnectionDelegate.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/delegate/ServiceConnectionDelegate.java
@@ -12,14 +12,7 @@ import java.util.Map;
import black.android.app.BRIServiceConnectionO;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ServiceConnectionDelegate extends IServiceConnection.Stub {
private static final Map sServiceConnectDelegate = new HashMap<>();
private final IServiceConnection mConn;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BAccountManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BAccountManager.java
index f6f93de..9ad0198 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BAccountManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BAccountManager.java
@@ -12,9 +12,7 @@ import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.core.system.ServiceManager;
import top.niunaijun.blackbox.core.system.accounts.IBAccountManagerService;
-/**
- * Created by BlackBox on 2022/3/3.
- */
+
public class BAccountManager extends BlackManager {
private static final BAccountManager sBAccountManager = new BAccountManager();
@@ -269,7 +267,7 @@ public class BAccountManager extends BlackManager {
}
}
- /* Returns Map from package name to visibility with all values stored for given account */
+
public Map getPackagesAndVisibilityForAccount(Account account) {
try {
return getService().getPackagesAndVisibilityForAccount(account, BActivityThread.getUserId());
@@ -304,11 +302,11 @@ public class BAccountManager extends BlackManager {
} catch (RemoteException e) {
e.printStackTrace();
}
- // AccountManager.VISIBILITY_NOT_VISIBLE
+
return 3;
}
- /* Type may be null returns Map */
+
public Map getAccountsAndVisibilityForPackage(String packageName, String accountType) {
try {
return getService().getAccountsAndVisibilityForPackage(packageName, accountType, BActivityThread.getUserId());
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BActivityManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BActivityManager.java
index c204ca5..5cffce0 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BActivityManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BActivityManager.java
@@ -19,14 +19,7 @@ import top.niunaijun.blackbox.entity.am.RunningAppProcessInfo;
import top.niunaijun.blackbox.entity.am.RunningServiceInfo;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/14/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BActivityManager extends BlackManager {
private static final String TAG = "BActivityManager";
private static final BActivityManager sActivityManager = new BActivityManager();
@@ -100,12 +93,12 @@ public class BActivityManager extends BlackManager {
IBActivityManagerService service = getService();
if (service != null) {
service.startActivity(intent, userId);
- return; // Success, exit
+ return;
} else {
Slog.w(TAG, "ActivityManager service is null, retry " + (retryCount + 1) + "/" + maxRetries);
- // Wait a bit longer for service to become available
+
try {
- Thread.sleep(200 * (retryCount + 1)); // Progressive delay
+ Thread.sleep(200 * (retryCount + 1));
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
@@ -113,16 +106,16 @@ public class BActivityManager extends BlackManager {
}
} catch (DeadObjectException e) {
Slog.w(TAG, "ActivityManager service died, clearing cache and retrying " + (retryCount + 1) + "/" + maxRetries);
- clearServiceCache(); // Clear the dead service
+ clearServiceCache();
try {
- Thread.sleep(100); // Brief pause before retry
+ Thread.sleep(100);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException in startActivity", e);
- break; // Don't retry for other RemoteExceptions
+ break;
} catch (Exception e) {
Slog.e(TAG, "Unexpected error in startActivity", e);
break;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BJobManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BJobManager.java
index 29af5f7..a97ee4e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BJobManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BJobManager.java
@@ -8,14 +8,7 @@ import top.niunaijun.blackbox.core.system.ServiceManager;
import top.niunaijun.blackbox.core.system.am.IBJobManagerService;
import top.niunaijun.blackbox.entity.JobRecord;
-/**
- * updated by alex5402 on 4/14/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BJobManager extends BlackManager {
private static final BJobManager sJobManager = new BJobManager();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BLocationManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BLocationManager.java
index fd22b33..1e52777 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BLocationManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BLocationManager.java
@@ -12,9 +12,7 @@ import top.niunaijun.blackbox.core.system.location.IBLocationManagerService;
import top.niunaijun.blackbox.entity.location.BCell;
import top.niunaijun.blackbox.entity.location.BLocation;
-/**
- * Created by BlackBoxing on 3/8/22.
- **/
+
public class BLocationManager extends BlackManager {
private static final BLocationManager sLocationManager = new BLocationManager();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BNotificationManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BNotificationManager.java
index 017592b..398d24e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BNotificationManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BNotificationManager.java
@@ -12,9 +12,7 @@ import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.core.system.ServiceManager;
import top.niunaijun.blackbox.core.system.notification.IBNotificationManagerService;
-/**
- * Created by BlackBox on 2022/3/18.
- */
+
public class BNotificationManager extends BlackManager {
private static final BNotificationManager sNotificationManager = new BNotificationManager();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java
index ecf42ee..bfeaa90 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BPackageManager.java
@@ -26,47 +26,34 @@ import top.niunaijun.blackbox.entity.pm.InstallResult;
import top.niunaijun.blackbox.entity.pm.InstalledPackage;
import top.niunaijun.blackbox.utils.TransactionThrottler;
-/**
- * updated by alex5402 on 4/14/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BPackageManager extends BlackManager {
private static final BPackageManager sPackageManager = new BPackageManager();
private final TransactionThrottler transactionThrottler = new TransactionThrottler();
- private static volatile boolean sIsFindingApkPath = false; // Flag to prevent recursion
+ private static volatile boolean sIsFindingApkPath = false;
public static BPackageManager get() {
return sPackageManager;
}
- /**
- * Reset the transaction throttler - call this when the app is restarted or when you want to clear failure state
- */
+
public void resetTransactionThrottler() {
transactionThrottler.reset();
Log.d(TAG, "Transaction throttler reset");
}
- /**
- * Check if we should use fallback mode due to service health issues
- */
+
private boolean shouldUseFallbackMode() {
return transactionThrottler.getFailureCount() >= 2 || !isServiceHealthy();
}
- /**
- * Force reinitialize the service - useful when the service becomes null
- */
+
public void forceReinitialize() {
Log.d(TAG, "Force reinitializing PackageManager service");
clearServiceCache();
resetTransactionThrottler();
- // Try to get the service again
+
try {
IBPackageManagerService service = getService();
if (service != null) {
@@ -79,9 +66,7 @@ public class BPackageManager extends BlackManager {
}
}
- /**
- * Get service with fallback - if service is null, try to reinitialize
- */
+
public IBPackageManagerService getServiceWithFallback() {
IBPackageManagerService service = getService();
if (service == null) {
@@ -98,7 +83,7 @@ public class BPackageManager extends BlackManager {
}
public Intent getLaunchIntentForPackage(String packageName, int userId) {
- // If we've had too many failures, try a simple fallback approach
+
if (shouldUseFallbackMode()) {
Log.w(TAG, "Using fallback launch intent for " + packageName + " due to service failures");
return createFallbackLaunchIntent(packageName);
@@ -112,9 +97,9 @@ public class BPackageManager extends BlackManager {
intentToResolve.resolveTypeIfNeeded(BlackBoxCore.getContext().getContentResolver()),
userId);
- // Otherwise, try to find a main launcher activity.
+
if (ris == null || ris.size() <= 0) {
- // reuse the intent instance
+
intentToResolve.removeCategory(Intent.CATEGORY_INFO);
intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
intentToResolve.setPackage(packageName);
@@ -133,12 +118,10 @@ public class BPackageManager extends BlackManager {
return intent;
}
- /**
- * Create a simple fallback launch intent when the service is unavailable
- */
+
private Intent createFallbackLaunchIntent(String packageName) {
try {
- // Try to get the launch intent from the system PackageManager as fallback
+
Intent intent = BlackBoxCore.getContext().getPackageManager().getLaunchIntentForPackage(packageName);
if (intent != null) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -148,7 +131,7 @@ public class BPackageManager extends BlackManager {
Log.w(TAG, "Fallback launch intent failed for " + packageName, e);
}
- // Last resort: create a generic intent
+
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setPackage(packageName);
@@ -157,7 +140,7 @@ public class BPackageManager extends BlackManager {
}
public ResolveInfo resolveService(Intent intent, int flags, String resolvedType, int userId) {
- // Check if we should throttle due to too many recent failures
+
if (transactionThrottler.shouldThrottle()) {
Log.w(TAG, "Throttling resolveService due to recent failures");
return null;
@@ -167,7 +150,7 @@ public class BPackageManager extends BlackManager {
IBPackageManagerService service = getService();
if (service != null) {
ResolveInfo result = service.resolveService(intent, flags, resolvedType, userId);
- // Reset throttler on success
+
transactionThrottler.reset();
return result;
} else {
@@ -176,14 +159,14 @@ public class BPackageManager extends BlackManager {
} catch (android.os.DeadObjectException e) {
Log.w(TAG, "PackageManager service died during resolveService, clearing service and retrying", e);
transactionThrottler.recordFailure();
- // Clear the service so it gets recreated on next call
+
clearServiceCache();
- // Try one more time
+
try {
IBPackageManagerService service = getService();
if (service != null) {
ResolveInfo result = service.resolveService(intent, flags, resolvedType, userId);
- transactionThrottler.reset(); // Reset on successful retry
+ transactionThrottler.reset();
return result;
}
} catch (Exception retryException) {
@@ -201,7 +184,7 @@ public class BPackageManager extends BlackManager {
}
public ResolveInfo resolveActivity(Intent intent, int flags, String resolvedType, int userId) {
- // Check if we should throttle due to too many recent failures
+
if (transactionThrottler.shouldThrottle()) {
Log.w(TAG, "Throttling resolveActivity due to recent failures");
return null;
@@ -211,7 +194,7 @@ public class BPackageManager extends BlackManager {
IBPackageManagerService service = getService();
if (service != null) {
ResolveInfo result = service.resolveActivity(intent, flags, resolvedType, userId);
- // Reset throttler on success
+
transactionThrottler.reset();
return result;
} else {
@@ -220,14 +203,14 @@ public class BPackageManager extends BlackManager {
} catch (android.os.DeadObjectException e) {
Log.w(TAG, "PackageManager service died during resolveActivity, clearing service and retrying", e);
transactionThrottler.recordFailure();
- // Clear the service so it gets recreated on next call
+
clearServiceCache();
- // Try one more time
+
try {
IBPackageManagerService service = getService();
if (service != null) {
ResolveInfo result = service.resolveActivity(intent, flags, resolvedType, userId);
- transactionThrottler.reset(); // Reset on successful retry
+ transactionThrottler.reset();
return result;
}
} catch (Exception retryException) {
@@ -245,7 +228,7 @@ public class BPackageManager extends BlackManager {
}
public ProviderInfo resolveContentProvider(String authority, int flags, int userId) {
- // Check if we should throttle due to too many recent failures
+
if (transactionThrottler.shouldThrottle()) {
Log.w(TAG, "Throttling resolveContentProvider due to recent failures");
return null;
@@ -255,7 +238,7 @@ public class BPackageManager extends BlackManager {
IBPackageManagerService service = getService();
if (service != null) {
ProviderInfo result = service.resolveContentProvider(authority, flags, userId);
- // Reset throttler on success
+
transactionThrottler.reset();
return result;
} else {
@@ -264,14 +247,14 @@ public class BPackageManager extends BlackManager {
} catch (android.os.DeadObjectException e) {
Log.w(TAG, "PackageManager service died during resolveContentProvider, clearing service and retrying", e);
transactionThrottler.recordFailure();
- // Clear the service so it gets recreated on next call
+
clearServiceCache();
- // Try one more time
+
try {
IBPackageManagerService service = getService();
if (service != null) {
ProviderInfo result = service.resolveContentProvider(authority, flags, userId);
- transactionThrottler.reset(); // Reset on successful retry
+ transactionThrottler.reset();
return result;
}
} catch (Exception retryException) {
@@ -400,13 +383,13 @@ public class BPackageManager extends BlackManager {
}
public List queryIntentActivities(Intent intent, int flags, String resolvedType, int userId) {
- // Check if we should throttle due to too many recent failures
+
if (transactionThrottler.shouldThrottle()) {
Log.w(TAG, "Throttling queryIntentActivities due to recent failures");
return Collections.emptyList();
}
- // If we've had too many failures, don't even try
+
if (transactionThrottler.getFailureCount() >= 2) {
Log.w(TAG, "Too many failures, returning empty list for queryIntentActivities");
return Collections.emptyList();
@@ -416,7 +399,7 @@ public class BPackageManager extends BlackManager {
IBPackageManagerService service = getService();
if (service != null) {
List result = service.queryIntentActivities(intent, flags, resolvedType, userId);
- // Reset throttler on success
+
transactionThrottler.reset();
return result;
} else {
@@ -426,16 +409,16 @@ public class BPackageManager extends BlackManager {
} catch (android.os.DeadObjectException e) {
Log.w(TAG, "PackageManager service died during queryIntentActivities, clearing cache and retrying", e);
transactionThrottler.recordFailure();
- clearServiceCache(); // Clear cached service
+ clearServiceCache();
+
- // Only retry if we haven't had too many failures
if (transactionThrottler.getFailureCount() < 3) {
try {
- // Retry once with fresh service
+
IBPackageManagerService service = getService();
if (service != null) {
List result = service.queryIntentActivities(intent, flags, resolvedType, userId);
- transactionThrottler.reset(); // Reset on successful retry
+ transactionThrottler.reset();
return result;
}
} catch (Exception retryException) {
@@ -465,9 +448,9 @@ public class BPackageManager extends BlackManager {
}
} catch (android.os.DeadObjectException e) {
Log.w(TAG, "PackageManager service died during queryBroadcastReceivers, clearing cache and retrying", e);
- clearServiceCache(); // Clear cached service
+ clearServiceCache();
try {
- // Retry once with fresh service
+
IBPackageManagerService service = getService();
if (service != null) {
return service.queryBroadcastReceivers(intent, flags, resolvedType, userId);
@@ -494,9 +477,9 @@ public class BPackageManager extends BlackManager {
}
} catch (android.os.DeadObjectException e) {
Log.w(TAG, "PackageManager service died during queryContentProviders, clearing cache and retrying", e);
- clearServiceCache(); // Clear cached service
+ clearServiceCache();
try {
- // Retry once with fresh service
+
IBPackageManagerService service = getService();
if (service != null) {
return service.queryContentProviders(processName, uid, flags, userId);
@@ -514,10 +497,10 @@ public class BPackageManager extends BlackManager {
public InstallResult installPackageAsUser(String file, InstallOption option, int userId) {
try {
- // Additional check to prevent cloning BlackBox app
+
if (file != null && !file.isEmpty()) {
try {
- // Try to check if this is a BlackBox app
+
PackageInfo packageInfo = BlackBoxCore.getPackageManager().getPackageArchiveInfo(file, 0);
if (packageInfo != null) {
String packageName = packageInfo.packageName;
@@ -590,7 +573,7 @@ public class BPackageManager extends BlackManager {
}
public boolean isInstalled(String packageName, int userId) {
- // Check if we should use fallback mode
+
if (shouldUseFallbackMode()) {
Log.w(TAG, "Using fallback isInstalled check for " + packageName + " due to service failures");
return isInstalledFallback(packageName);
@@ -600,7 +583,7 @@ public class BPackageManager extends BlackManager {
IBPackageManagerService service = getService();
if (service != null) {
boolean result = service.isInstalled(packageName, userId);
- transactionThrottler.reset(); // Reset on success
+ transactionThrottler.reset();
return result;
} else {
Log.w(TAG, "PackageManager service is null, returning false for isInstalled check");
@@ -608,14 +591,14 @@ public class BPackageManager extends BlackManager {
} catch (android.os.DeadObjectException e) {
Log.w(TAG, "PackageManager service died during isInstalled check, clearing service and retrying", e);
transactionThrottler.recordFailure();
- // Clear the service so it gets recreated on next call
+
clearServiceCache();
- // Try one more time
+
try {
IBPackageManagerService service = getService();
if (service != null) {
boolean result = service.isInstalled(packageName, userId);
- transactionThrottler.reset(); // Reset on successful retry
+ transactionThrottler.reset();
return result;
}
} catch (Exception retryException) {
@@ -632,17 +615,15 @@ public class BPackageManager extends BlackManager {
return false;
}
- /**
- * Fallback method for checking if a package is installed
- */
+
private boolean isInstalledFallback(String packageName) {
try {
- // Try to get package info from system PackageManager as fallback
+
BlackBoxCore.getContext().getPackageManager().getPackageInfo(packageName, 0);
return true;
} catch (Exception e) {
Log.d(TAG, "Fallback isInstalled check failed for " + packageName + ", assuming not installed");
- // For known apps that should be available, return true even if fallback fails
+
if (packageName != null && (packageName.equals("com.media.bestrecorder.audiorecorder") ||
packageName.startsWith("top.niunaijun.blackbox"))) {
Log.w(TAG, "Returning true for known app " + packageName + " despite fallback failure");
@@ -679,19 +660,19 @@ public class BPackageManager extends BlackManager {
ApplicationInfo info = new ApplicationInfo();
info.packageName = packageName;
info.flags = flags;
- info.uid = 0; // Placeholder, actual UID would require more context
+ info.uid = 0;
+
+
- // Use more realistic paths that are less likely to cause issues
- // Try to find the actual APK path first, fallback to system paths
String apkPath = findActualApkPath(packageName);
if (apkPath != null) {
info.sourceDir = apkPath;
info.publicSourceDir = apkPath;
} else {
- // If no APK exists, use null or existing system paths to prevent I/O errors
+
Log.w(TAG, "No APK found for " + packageName + ", using null paths to prevent I/O errors");
- info.sourceDir = null; // Use null instead of fake path
- info.publicSourceDir = null; // Use null instead of fake path
+ info.sourceDir = null;
+ info.publicSourceDir = null;
}
info.dataDir = "/data/data/" + packageName;
@@ -699,16 +680,14 @@ public class BPackageManager extends BlackManager {
info.metaData = new Bundle();
info.splitNames = new String[]{};
- // Set some basic flags to make it look more realistic
+
info.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
info.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
return info;
}
- /**
- * Try to find the actual APK path for a package
- */
+
private String findActualApkPath(String packageName) {
if (sIsFindingApkPath) {
Log.w(TAG, "findActualApkPath called recursively, returning null to prevent infinite loop.");
@@ -716,22 +695,22 @@ public class BPackageManager extends BlackManager {
}
sIsFindingApkPath = true;
try {
- // Skip PackageManager call to prevent infinite recursion
- // The PackageManager is hooked and would cause infinite loops
+
+
Log.d(TAG, "Skipping PackageManager call to prevent recursion for " + packageName);
- // Try common paths including real-world hash-based paths
+
String[] commonPaths = {
- // Real-world hash-based paths (most common)
+
"/data/app/~~*/" + packageName + "-*/base.apk",
"/data/app/~~*/" + packageName + "*/base.apk",
- // Legacy paths
+
"/data/app/" + packageName + "-1/base.apk",
"/data/app/" + packageName + "-2/base.apk",
"/data/app/" + packageName + "/base.apk",
- // System paths
+
"/system/app/" + packageName + ".apk",
"/system/priv-app/" + packageName + ".apk",
"/system_ext/app/" + packageName + ".apk",
@@ -739,7 +718,7 @@ public class BPackageManager extends BlackManager {
"/vendor/app/" + packageName + ".apk"
};
- // First try exact path matching
+
for (String path : commonPaths) {
if (isValidApkPath(path)) {
Log.d(TAG, "Found existing APK at: " + path);
@@ -747,7 +726,7 @@ public class BPackageManager extends BlackManager {
}
}
- // If exact paths don't work, try to find hash-based paths dynamically
+
String hashBasedPath = findHashBasedApkPath(packageName);
if (hashBasedPath != null) {
Log.d(TAG, "Found hash-based APK at: " + hashBasedPath);
@@ -757,13 +736,11 @@ public class BPackageManager extends BlackManager {
Log.w(TAG, "No existing APK found for " + packageName + ", using null path");
return null;
} finally {
- sIsFindingApkPath = false; // Reset flag
+ sIsFindingApkPath = false;
}
}
- /**
- * Find APK path using hash-based directory structure
- */
+
private String findHashBasedApkPath(String packageName) {
try {
File dataAppDir = new File("/data/app");
@@ -771,7 +748,7 @@ public class BPackageManager extends BlackManager {
return null;
}
- // Look for hash directories (~~hash==)
+
File[] hashDirs = dataAppDir.listFiles((dir, name) -> name.startsWith("~~") && name.endsWith("=="));
if (hashDirs == null) {
return null;
@@ -782,7 +759,7 @@ public class BPackageManager extends BlackManager {
continue;
}
- // Look for package directories within hash directories
+
File[] packageDirs = hashDir.listFiles((dir, name) -> name.startsWith(packageName));
if (packageDirs == null) {
continue;
@@ -793,7 +770,7 @@ public class BPackageManager extends BlackManager {
continue;
}
- // Look for base.apk within package directory
+
File baseApk = new File(packageDir, "base.apk");
if (isValidApkPath(baseApk.getAbsolutePath())) {
return baseApk.getAbsolutePath();
@@ -807,12 +784,10 @@ public class BPackageManager extends BlackManager {
return null;
}
- /**
- * Check if an APK path is valid and accessible
- */
+
private boolean isValidApkPath(String path) {
try {
- // Skip wildcard patterns - they need to be resolved first
+
if (path.contains("*")) {
return false;
}
@@ -822,14 +797,14 @@ public class BPackageManager extends BlackManager {
return false;
}
- // Additional validation: check if it's readable and has reasonable size
+
if (!apkFile.canRead()) {
Log.d(TAG, "APK file not readable: " + path);
return false;
}
long fileSize = apkFile.length();
- if (fileSize < 1024) { // Less than 1KB is probably not a valid APK
+ if (fileSize < 1024) {
Log.d(TAG, "APK file too small: " + path + " (size: " + fileSize + ")");
return false;
}
@@ -845,15 +820,15 @@ public class BPackageManager extends BlackManager {
Log.w(TAG, "Creating fallback PackageInfo for " + packageName);
PackageInfo info = new PackageInfo();
info.packageName = packageName;
- info.versionCode = 1; // Placeholder
- info.versionName = "1.0"; // Placeholder
+ info.versionCode = 1;
+ info.versionName = "1.0";
info.applicationInfo = createFallbackApplicationInfo(packageName, flags, userId);
- info.firstInstallTime = System.currentTimeMillis(); // Placeholder
- info.lastUpdateTime = System.currentTimeMillis(); // Placeholder
- info.installLocation = 0; // Placeholder
- info.gids = new int[]{}; // Placeholder
- info.splitNames = new String[]{}; // Placeholder
- info.signatures = new Signature[]{}; // Placeholder
+ info.firstInstallTime = System.currentTimeMillis();
+ info.lastUpdateTime = System.currentTimeMillis();
+ info.installLocation = 0;
+ info.gids = new int[]{};
+ info.splitNames = new String[]{};
+ info.signatures = new Signature[]{};
return info;
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BResourcesManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BResourcesManager.java
index 079f338..e0f232a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BResourcesManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BResourcesManager.java
@@ -17,49 +17,44 @@ import top.niunaijun.blackbox.fake.hook.IInjectHook;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * Utility class to handle resource loading issues in virtual environment
- * This provides safe resource loading methods to prevent crashes from missing system resources
- */
+
public class BResourcesManager implements IInjectHook {
private static final String TAG = "BResourcesManager";
@Override
public void injectHook() {
- // This hook is not needed for the current approach
- // The resource loading issues are handled at the application level
+
+
Log.d(TAG, "BResourcesManager hook initialized");
}
@Override
public boolean isBadEnv() {
- return false; // Don't always inject this hook
+ return false;
}
- /**
- * Safely load app label with fallback to package name
- */
+
public static String safeLoadAppLabel(Object applicationInfo) {
if (applicationInfo == null) {
return "Unknown App";
}
- // Try multiple approaches to get the package name
+
String packageName = getPackageNameSafely(applicationInfo);
- // If we have a package name, use it as the label to avoid resource loading
+
if (packageName != null && !packageName.isEmpty()) {
return packageName;
}
- // Try to get the label from the application info directly without triggering resource loading
+
try {
- // Try to get the label from the application info's labelRes field first
+
Method getLabelResMethod = applicationInfo.getClass().getMethod("getLabelRes");
Integer labelRes = (Integer) getLabelResMethod.invoke(applicationInfo);
if (labelRes != null && labelRes != 0) {
- // If we have a label resource, try to get it from the package manager
+
Object packageManager = getPackageManager();
if (packageManager != null) {
Method getTextMethod = packageManager.getClass().getMethod("getText", String.class, int.class, android.content.pm.ApplicationInfo.class);
@@ -70,7 +65,7 @@ public class BResourcesManager implements IInjectHook {
}
}
- // Fallback to loadLabel method
+
Method loadLabelMethod = applicationInfo.getClass().getMethod("loadLabel", android.content.pm.PackageManager.class);
Object packageManager = getPackageManager();
if (packageManager != null) {
@@ -86,11 +81,9 @@ public class BResourcesManager implements IInjectHook {
return "Unknown App";
}
- /**
- * Get package name safely using multiple approaches
- */
+
private static String getPackageNameSafely(Object applicationInfo) {
- // Try direct field access first
+
try {
Field packageNameField = applicationInfo.getClass().getDeclaredField("packageName");
packageNameField.setAccessible(true);
@@ -102,7 +95,7 @@ public class BResourcesManager implements IInjectHook {
Log.w(TAG, "Failed to get package name via field: " + e.getMessage());
}
- // Try getPackageName method
+
try {
Method getPackageNameMethod = applicationInfo.getClass().getMethod("getPackageName");
Object packageName = getPackageNameMethod.invoke(applicationInfo);
@@ -113,7 +106,7 @@ public class BResourcesManager implements IInjectHook {
Log.w(TAG, "Failed to get package name via method: " + e.getMessage());
}
- // Try toString method to see if it contains package info
+
try {
String toString = applicationInfo.toString();
if (toString.contains("packageName=")) {
@@ -129,18 +122,16 @@ public class BResourcesManager implements IInjectHook {
return null;
}
- /**
- * Safely load app icon with fallback to null
- */
+
public static Object safeLoadAppIcon(Object applicationInfo) {
try {
if (applicationInfo != null) {
- // First try to get the icon resource ID directly
+
Method getIconMethod = applicationInfo.getClass().getMethod("getIcon");
Integer iconRes = (Integer) getIconMethod.invoke(applicationInfo);
if (iconRes != null && iconRes != 0) {
- // Try to load the icon using the resource ID directly
+
Object packageManager = getPackageManager();
if (packageManager != null) {
try {
@@ -155,7 +146,7 @@ public class BResourcesManager implements IInjectHook {
}
}
- // Fallback to loadIcon method
+
Method loadIconMethod = applicationInfo.getClass().getMethod("loadIcon", android.content.pm.PackageManager.class);
Object packageManager = getPackageManager();
if (packageManager != null) {
@@ -168,17 +159,13 @@ public class BResourcesManager implements IInjectHook {
return null;
}
- /**
- * Get package name from application info
- */
+
private static String getPackageName(Object applicationInfo) {
String packageName = getPackageNameSafely(applicationInfo);
return packageName != null ? packageName : "";
}
- /**
- * Get PackageManager safely
- */
+
private static Object getPackageManager() {
try {
Class> blackBoxCoreClass = Class.forName("top.niunaijun.blackbox.BlackBoxCore");
@@ -190,16 +177,14 @@ public class BResourcesManager implements IInjectHook {
}
}
- /**
- * Create a safe resource manager that doesn't load problematic overlays
- */
+
public static Object createSafeResourceManager(Context context) {
try {
- // Create a custom resource manager that skips problematic overlays
+
Class> resourcesManagerClass = Class.forName("android.app.ResourcesManager");
Object resourcesManager = resourcesManagerClass.newInstance();
- // Set a flag to disable overlay loading
+
try {
Field disableOverlayField = resourcesManagerClass.getDeclaredField("mDisableOverlayLoading");
disableOverlayField.setAccessible(true);
@@ -215,9 +200,7 @@ public class BResourcesManager implements IInjectHook {
}
}
- /**
- * Check if a path is a problematic overlay path
- */
+
public static boolean isProblematicOverlayPath(String path) {
return path != null && path.contains("/data/resource-cache/") && path.contains(".frro");
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BStorageManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BStorageManager.java
index 0b367a6..e218544 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BStorageManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BStorageManager.java
@@ -7,14 +7,7 @@ import android.os.storage.StorageVolume;
import top.niunaijun.blackbox.core.system.ServiceManager;
import top.niunaijun.blackbox.core.system.os.IBStorageManagerService;
-/**
- * updated by alex5402 on 4/14/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BStorageManager extends BlackManager {
private static final BStorageManager sStorageManager = new BStorageManager();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BUserManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BUserManager.java
index b382297..1963c3e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BUserManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BUserManager.java
@@ -12,14 +12,7 @@ import top.niunaijun.blackbox.core.system.user.BUserInfo;
import top.niunaijun.blackbox.core.system.user.IBUserManagerService;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/28/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class BUserManager extends BlackManager {
private static final String TAG = "BUserManager";
private static final BUserManager sUserManager = new BUserManager();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BlackManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BlackManager.java
index d1bd20a..9142a06 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BlackManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/frameworks/BlackManager.java
@@ -11,9 +11,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.utils.Reflector;
-/**
- * Created by BlackBox on 2022/3/23.
- */
+
public abstract class BlackManager {
public static final String TAG = "BlackManager";
@@ -21,25 +19,25 @@ public abstract class BlackManager {
private final AtomicBoolean mServiceCreationFailed = new AtomicBoolean(false);
private long mLastRetryTime = 0;
private long mLastServiceCreationTime = 0;
- private static final long RETRY_TIMEOUT_MS = 2000; // Shorter timeout
- private static final long MIN_SERVICE_CREATION_INTERVAL_MS = 50; // Shorter interval
+ private static final long RETRY_TIMEOUT_MS = 2000;
+ private static final long MIN_SERVICE_CREATION_INTERVAL_MS = 50;
+
- // Global service failure tracking to prevent cascade failures
private static final AtomicInteger globalServiceFailureCount = new AtomicInteger(0);
- private static final long GLOBAL_FAILURE_RESET_INTERVAL_MS = 30000; // 30 seconds
+ private static final long GLOBAL_FAILURE_RESET_INTERVAL_MS = 30000;
private static long lastGlobalFailureReset = 0;
protected abstract String getServiceName();
public Service getService() {
- // If service creation previously failed and we're within retry timeout, return null
+
if (mServiceCreationFailed.get()) {
long currentTime = System.currentTimeMillis();
if (currentTime - mLastRetryTime < RETRY_TIMEOUT_MS) {
Log.d(TAG, "Skipping service creation for " + getServiceName() + " due to recent failure");
return null;
}
- // Reset the flag after timeout
+
mServiceCreationFailed.set(false);
}
@@ -47,11 +45,11 @@ public abstract class BlackManager {
return mService;
}
- // Rate limiting: don't create services too frequently
+
long currentTime = System.currentTimeMillis();
if (currentTime - mLastServiceCreationTime < MIN_SERVICE_CREATION_INTERVAL_MS) {
Log.d(TAG, "Rate limiting service creation for " + getServiceName());
- return mService; // Return existing service (might be null)
+ return mService;
}
try {
@@ -62,7 +60,7 @@ public abstract class BlackManager {
return null;
}
- // Check if binder is alive before proceeding
+
if (!binder.isBinderAlive()) {
Log.w(TAG, "Binder is not alive for service: " + getServiceName());
markServiceCreationFailed();
@@ -76,7 +74,7 @@ public abstract class BlackManager {
.call(binder);
if (mService != null) {
- // Additional health check
+
try {
if (!mService.asBinder().isBinderAlive()) {
Log.w(TAG, "Service binder is not alive after creation: " + getServiceName());
@@ -91,7 +89,7 @@ public abstract class BlackManager {
return null;
}
- final Service serviceRef = mService; // Capture reference for death recipient
+ final Service serviceRef = mService;
try {
serviceRef.asBinder().linkToDeath(new IBinder.DeathRecipient() {
@Override
@@ -109,12 +107,12 @@ public abstract class BlackManager {
}, 0);
} catch (Exception e) {
Log.w(TAG, "Error linking death recipient for " + getServiceName(), e);
- // Continue anyway, the service might still work
+
}
Log.d(TAG, "Successfully created service: " + getServiceName());
- mServiceCreationFailed.set(false); // Reset failure flag on success
- mLastServiceCreationTime = currentTime; // Update creation time
+ mServiceCreationFailed.set(false);
+ mLastServiceCreationTime = currentTime;
} else {
Log.w(TAG, "Failed to create service instance for: " + getServiceName());
markServiceCreationFailed();
@@ -133,17 +131,13 @@ public abstract class BlackManager {
mLastRetryTime = System.currentTimeMillis();
}
- /**
- * Clear the cached service - call this when the service dies
- */
+
public void clearServiceCache() {
mService = null;
Log.d(TAG, "Cleared service cache for " + getServiceName());
}
- /**
- * Check if the service is healthy and available
- */
+
public boolean isServiceHealthy() {
if (mService == null) {
return false;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/BinderInvocationStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/BinderInvocationStub.java
index f54480d..1bbdc36 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/BinderInvocationStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/BinderInvocationStub.java
@@ -13,14 +13,7 @@ import java.util.Map;
import black.android.os.BRServiceManager;
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public abstract class BinderInvocationStub extends ClassInvocationStub implements IBinder {
private IBinder mBaseBinder;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java
index a5da868..6c72178 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java
@@ -11,14 +11,7 @@ import java.util.Map;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public abstract class ClassInvocationStub implements InvocationHandler, IInjectHook {
public static final String TAG = ClassInvocationStub.class.getSimpleName();
@@ -50,7 +43,7 @@ public abstract class ClassInvocationStub implements InvocationHandler, IInjectH
@Override
public void injectHook() {
mBase = getWho();
- // Skip hook if service doesn't exist on this Android version
+
if (mBase == null) {
return;
}
@@ -109,16 +102,16 @@ public abstract class ClassInvocationStub implements InvocationHandler, IInjectH
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-// for debug
-// if(method.getName().contains("finish")){
-// Log.d(TAG,"finishAAAAAAAAAAAAAAA:" + method.getName());
-// Thread currentThread = Thread.currentThread();
-// StackTraceElement[] stackTraceElements = currentThread.getStackTrace();
-// for (StackTraceElement element : stackTraceElements) {
-// // 打印调用栈信息
-// Log.d(TAG,element.toString());
-// }
-// }
+
+
+
+
+
+
+
+
+
+
MethodHook methodHook = mMethodHookMap.get(method.getName());
if (methodHook == null || !methodHook.isEnable()) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java
index 67eb09f..7950901 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java
@@ -91,16 +91,9 @@ import top.niunaijun.blackbox.utils.compat.BuildCompat;
import top.niunaijun.blackbox.fake.service.ISettingsProviderProxy;
import top.niunaijun.blackbox.fake.service.FeatureFlagUtilsProxy;
import top.niunaijun.blackbox.fake.service.WorkManagerProxy;
-// Removed IInputMethodManagerProxy - causes ClassCastException on Android 15
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
+
public class HookManager {
public static final String TAG = "HookManager";
@@ -169,7 +162,7 @@ public class HookManager {
addInjector(new ISettingsSystemProxy());
addInjector(new ISystemSensorManagerProxy());
- // Xiaomi-specific proxies to prevent crashes on MIUI devices
+
addInjector(new IXiaomiAttributionSourceProxy());
addInjector(new IXiaomiSettingsProxy());
addInjector(new IXiaomiMiuiServicesProxy());
@@ -177,60 +170,56 @@ public class HookManager {
addInjector(new IMediaRouterServiceProxy());
addInjector(new IPowerManagerProxy());
addInjector(new IContextHubServiceProxy());
- // Removed IInputMethodManagerProxy - causes ClassCastException on Android 15 due to queryLocalInterface returning non-IInterface proxy
+
addInjector(new IVibratorServiceProxy());
addInjector(new IPersistentDataBlockServiceProxy());
addInjector(AppInstrumentation.get());
- /*
- * It takes time to test and enhance the compatibility of WifiManager
- * (only tested in Android 10).
- * commented by BlackBoxing at 2022/03/08
- * */
+
addInjector(new IWifiManagerProxy());
addInjector(new IWifiScannerProxy());
addInjector(new ApkAssetsProxy());
addInjector(new ResourcesManagerProxy());
- // 12.0
+
if (BuildCompat.isS()) {
addInjector(new IActivityClientProxy(null));
addInjector(new IVpnManagerProxy());
}
- // 14.0 (Safe to try on S+, will skip if service missing)
+
if (BuildCompat.isS()) {
addInjector(new ISensitiveContentProtectionManagerProxy());
}
- // 11.0
+
if (BuildCompat.isR()) {
addInjector(new IPermissionManagerProxy());
}
- // 10.0
+
if (BuildCompat.isQ()) {
addInjector(new IActivityTaskManagerProxy());
}
- // 9.0
+
if (BuildCompat.isPie()) {
addInjector(new ISystemUpdateProxy());
}
- // 8.0
+
if (BuildCompat.isOreo()) {
addInjector(new IAutofillManagerProxy());
addInjector(new IDeviceIdentifiersPolicyProxy());
addInjector(new IStorageStatsManagerProxy());
}
- // 7.1
+
if (BuildCompat.isN_MR1()) {
addInjector(new IShortcutManagerProxy());
}
- // 7.0
+
if (BuildCompat.isN()) {
addInjector(new INetworkManagementServiceProxy());
}
- // 6.0
+
if (BuildCompat.isM()) {
addInjector(new IFingerprintManagerProxy());
addInjector(new IGraphicsStatsProxy());
}
- // 5.0
+
if (BuildCompat.isL()) {
addInjector(new IJobServiceProxy());
}
@@ -267,22 +256,20 @@ public class HookManager {
value.injectHook();
} catch (Exception e) {
Slog.d(TAG, "hook error: " + value);
- // Enhanced error handling for critical hooks
+
handleHookError(value, e);
}
}
}
- /**
- * Enhanced error handling for hook failures
- */
+
private void handleHookError(IInjectHook hook, Exception e) {
String hookName = hook.getClass().getSimpleName();
- // Log the error with more details
+
Slog.e(TAG, "Hook failed: " + hookName + " - " + e.getMessage(), e);
- // Special handling for critical hooks that could cause crashes
+
if (hookName.contains("ActivityManager") ||
hookName.contains("PackageManager") ||
hookName.contains("WebView") ||
@@ -291,7 +278,7 @@ public class HookManager {
Slog.w(TAG, "Critical hook failed: " + hookName + ", attempting recovery");
try {
- // Try to recover by re-initializing the hook
+
if (hook.isBadEnv()) {
Slog.d(TAG, "Attempting to recover hook: " + hookName);
hook.injectHook();
@@ -302,9 +289,7 @@ public class HookManager {
}
}
- /**
- * Check if all critical hooks are properly installed
- */
+
public boolean areCriticalHooksInstalled() {
String[] criticalHooks = {
"IActivityManagerProxy",
@@ -331,16 +316,14 @@ public class HookManager {
return true;
}
- /**
- * Force re-initialization of all hooks
- */
+
public void reinitializeHooks() {
Slog.d(TAG, "Reinitializing all hooks");
- // Clear existing injectors
+
mInjectors.clear();
- // Re-initialize
+
init();
Slog.d(TAG, "Hook reinitialization completed");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/IInjectHook.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/IInjectHook.java
index 46d0880..6e6d3d6 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/IInjectHook.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/IInjectHook.java
@@ -1,13 +1,6 @@
package top.niunaijun.blackbox.fake.hook;
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public interface IInjectHook {
void injectHook();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/MethodHook.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/MethodHook.java
index 0e4ee82..2bb3953 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/MethodHook.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/MethodHook.java
@@ -4,14 +4,7 @@ import java.lang.reflect.Method;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public abstract class MethodHook {
protected String getMethodName() {
return null;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethod.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethod.java
index 76324a4..ad7ca6d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethod.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethod.java
@@ -5,14 +5,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-/**
- * updated by alex5402 on 2021/5/9.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProxyMethod {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethods.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethods.java
index 2df6130..1ffb330 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethods.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ProxyMethods.java
@@ -5,14 +5,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-/**
- * updated by alex5402 on 2021/5/9.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProxyMethods {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ScanClass.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ScanClass.java
index 8816ae4..69b0124 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ScanClass.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ScanClass.java
@@ -5,14 +5,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-/**
- * updated by alex5402 on 2021/5/9.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ScanClass {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProvider.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProvider.java
index c2c8ecf..53cb4eb 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProvider.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProvider.java
@@ -30,14 +30,7 @@ import java.util.Map;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
-/**
- * updated by alex5402 on 4/18/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class FileProvider extends ContentProvider {
private static final String[] COLUMNS = {
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE };
@@ -62,27 +55,18 @@ public class FileProvider extends ContentProvider {
private PathStrategy mStrategy;
- /**
- * The default FileProvider implementation does not need to be initialized. If you want to
- * override this method, you must provide your own subclass of
- */
+
@Override
public boolean onCreate() {
return true;
}
- /**
- * After the FileProvider is instantiated, this method is called to provide the system with
- * information about the provider.
- *
- * @param context A {@link Context} for the current component.
- * @param info A {@link ProviderInfo} for the new provider.
- */
+
@Override
public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info);
- // Sanity check our security
+
if (info.exported) {
throw new SecurityException("Provider must not be exported");
}
@@ -93,26 +77,7 @@ public class FileProvider extends ContentProvider {
mStrategy = getPathStrategy(context, info.authority);
}
- /**
- * Return a content URI for a given {@link File}. Specific temporary
- * permissions for the content URI can be set with
- * {@link Context#grantUriPermission(String, Uri, int)}, or added
- * to an {@link Intent} by calling {@link Intent#setData(Uri) setData()} and then
- * {@link Intent#setFlags(int) setFlags()}; in both cases, the applicable flags are
- * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and
- * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}. A FileProvider can only return a
- * content {@link Uri} for file paths defined in their <paths>
- * meta-data element. See the Class Overview for more information.
- *
- * @param context A {@link Context} for the current component.
- * @param authority The authority of a {@link FileProvider} defined in a
- * {@code } element in your app's manifest.
- * @param file A {@link File} pointing to the filename for which you want a
- * content {@link Uri}.
- * @return A content URI for the file.
- * @throws IllegalArgumentException When the given {@link File} is outside
- * the paths supported by the provider.
- */
+
public static Uri getUriForFile(Context context, String authority,
File file) {
final PathStrategy strategy = getPathStrategy(context, authority);
@@ -125,39 +90,12 @@ public class FileProvider extends ContentProvider {
return strategy.getFileForUri(uri);
}
- /**
- * Use a content URI returned by
- * {@link #getUriForFile(Context, String, File) getUriForFile()} to get information about a file
- * managed by the
- * FileProvider reports the column names defined in {@link android.provider.OpenableColumns}:
- *
- * - {@link android.provider.OpenableColumns#DISPLAY_NAME}
- * - {@link android.provider.OpenableColumns#SIZE}
- *
- * For more information, see
- * {@link ContentProvider#query(Uri, String[], String, String[], String)
- * ContentProvider.query()}.
- *
- * @param uri A content URI returned by {@link #getUriForFile}.
- * @param projection The list of columns to put into the {@link Cursor}. If null all columns are
- * included.
- * @param selection Selection criteria to apply. If null then all data that matches the content
- * URI is returned.
- * @param selectionArgs An array of {@link java.lang.String}, containing arguments to bind to
- * the selection parameter. The query method scans selection from left to
- * right and iterates through selectionArgs, replacing the current "?" character in
- * selection with the value at the current position in selectionArgs. The
- * values are bound to selection as {@link java.lang.String} values.
- * @param sortOrder A {@link java.lang.String} containing the column name(s) on which to sort
- * the resulting {@link Cursor}.
- * @return A {@link Cursor} containing the results of the query.
- *
- */
+
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs,
String sortOrder) {
- // ContentProvider has already checked granted permissions
+
final File file = mStrategy.getFileForUri(uri);
if (projection == null) {
@@ -185,18 +123,10 @@ public class FileProvider extends ContentProvider {
return cursor;
}
- /**
- * Returns the MIME type of a content URI returned by
- * {@link #getUriForFile(Context, String, File) getUriForFile()}.
- *
- * @param uri A content URI returned by
- * {@link #getUriForFile(Context, String, File) getUriForFile()}.
- * @return If the associated file has an extension, the MIME type associated with that
- * extension; otherwise application/octet-stream.
- */
+
@Override
public String getType(Uri uri) {
- // ContentProvider has already checked granted permissions
+
final File file = mStrategy.getFileForUri(uri);
final int lastDot = file.getName().lastIndexOf('.');
@@ -211,72 +141,39 @@ public class FileProvider extends ContentProvider {
return "application/octet-stream";
}
- /**
- * By default, this method throws an {@link java.lang.UnsupportedOperationException}. You must
- * subclass FileProvider if you want to provide different functionality.
- */
+
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException("No external inserts");
}
- /**
- * By default, this method throws an {@link java.lang.UnsupportedOperationException}. You must
- * subclass FileProvider if you want to provide different functionality.
- */
+
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException("No external updates");
}
- /**
- * Deletes the file associated with the specified content URI, as
- * returned by {@link #getUriForFile(Context, String, File) getUriForFile()}. Notice that this
- * method does not throw an {@link java.io.IOException}; you must check its return value.
- *
- * @param uri A content URI for a file, as returned by
- * {@link #getUriForFile(Context, String, File) getUriForFile()}.
- * @param selection Ignored. Set to {@code null}.
- * @param selectionArgs Ignored. Set to {@code null}.
- * @return 1 if the delete succeeds; otherwise, 0.
- */
+
@Override
public int delete(Uri uri, String selection,
String[] selectionArgs) {
- // ContentProvider has already checked granted permissions
+
final File file = mStrategy.getFileForUri(uri);
return file.delete() ? 1 : 0;
}
- /**
- * By default, FileProvider automatically returns the
- * {@link ParcelFileDescriptor} for a file associated with a content://
- * {@link Uri}. To get the {@link ParcelFileDescriptor}, call
- * {@link android.content.ContentResolver#openFileDescriptor(Uri, String)
- * ContentResolver.openFileDescriptor}.
- *
- * To override this method, you must provide your own subclass of
- *
- * @param uri A content URI associated with a file, as returned by
- * {@link #getUriForFile(Context, String, File) getUriForFile()}.
- * @param mode Access mode for the file. May be "r" for read-only access, "rw" for read and
- * write access, or "rwt" for read and write access that truncates any existing file.
- * @return A new {@link ParcelFileDescriptor} with which you can access the file.
- */
+
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
- // ContentProvider has already checked granted permissions
+
final File file = mStrategy.getFileForUri(uri);
final int fileMode = modeToMode(mode);
return ParcelFileDescriptor.open(file, fileMode);
}
- /**
- * Return {@link PathStrategy} for given authority, either by parsing or
- * returning from cache.
- */
+
private static PathStrategy getPathStrategy(Context context, String authority) {
PathStrategy strat;
synchronized (sCache) {
@@ -297,12 +194,7 @@ public class FileProvider extends ContentProvider {
return strat;
}
- /**
- * Parse and return {@link PathStrategy} for given authority as defined in
- * {@link #META_DATA_FILE_PROVIDER_PATHS} {@code }.
- *
- * @see #getPathStrategy(Context, String)
- */
+
private static PathStrategy parsePathStrategy(Context context, String authority)
throws IOException, XmlPullParserException {
final SimplePathStrategy strat = new SimplePathStrategy(authority);
@@ -337,7 +229,7 @@ public class FileProvider extends ContentProvider {
} else if (TAG_CACHE_PATH.equals(tag)) {
target = context.getCacheDir();
} else if (TAG_EXTERNAL.equals(tag)) {
- // Use getExternalFilesDir(null) instead of deprecated getExternalStorageDirectory()
+
target = context.getExternalFilesDir(null);
} else if (TAG_EXTERNAL_FILES.equals(tag)) {
File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
@@ -366,41 +258,16 @@ public class FileProvider extends ContentProvider {
return strat;
}
- /**
- * Strategy for mapping between {@link File} and {@link Uri}.
- *
- * Strategies must be symmetric so that mapping a {@link File} to a
- * {@link Uri} and then back to a {@link File} points at the original
- * target.
- *
- * Strategies must remain consistent across app launches, and not rely on
- * dynamic state. This ensures that any generated {@link Uri} can still be
- * resolved if your process is killed and later restarted.
- *
- * @see SimplePathStrategy
- */
+
interface PathStrategy {
- /**
- * Return a {@link Uri} that represents the given {@link File}.
- */
+
Uri getUriForFile(File file);
- /**
- * Return a {@link File} that represents the given {@link Uri}.
- */
+
File getFileForUri(Uri uri);
}
- /**
- * Strategy that provides access to files living under a narrow whitelist of
- * filesystem roots. It will throw {@link SecurityException} if callers try
- * accessing files outside the configured roots.
- *
- * For example, if configured with
- * {@code addRoot("myfiles", context.getFilesDir())}, then
- * {@code context.getFileStreamPath("foo.txt")} would map to
- * {@code content://myauthority/myfiles/foo.txt}.
- */
+
static class SimplePathStrategy implements PathStrategy {
private final String mAuthority;
private final HashMap mRoots = new HashMap();
@@ -409,17 +276,14 @@ public class FileProvider extends ContentProvider {
mAuthority = authority;
}
- /**
- * Add a mapping from a name to a filesystem root. The provider only offers
- * access to files that live under configured roots.
- */
+
void addRoot(String name, File root) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name must not be empty");
}
try {
- // Resolve to canonical path to keep path checking fast
+
root = root.getCanonicalFile();
} catch (IOException e) {
throw new IllegalArgumentException(
@@ -438,7 +302,7 @@ public class FileProvider extends ContentProvider {
throw new IllegalArgumentException("Failed to resolve canonical path for " + file);
}
- // Find the most-specific root path
+
Map.Entry mostSpecific = null;
for (Map.Entry root : mRoots.entrySet()) {
final String rootPath = root.getValue().getPath();
@@ -453,7 +317,7 @@ public class FileProvider extends ContentProvider {
"Failed to find configured root that contains " + path);
}
- // Start at first char of path under root
+
final String rootPath = mostSpecific.getValue().getPath();
if (rootPath.endsWith("/")) {
path = path.substring(rootPath.length());
@@ -461,7 +325,7 @@ public class FileProvider extends ContentProvider {
path = path.substring(rootPath.length() + 1);
}
- // Encode the tag and path separately
+
path = Uri.encode(mostSpecific.getKey()) + '/' + Uri.encode(path, "/");
return new Uri.Builder().scheme("content")
.authority(mAuthority).encodedPath(path).build();
@@ -495,9 +359,7 @@ public class FileProvider extends ContentProvider {
}
}
- /**
- * Copied from ContentResolver.java
- */
+
private static int modeToMode(String mode) {
int modeBits;
if ("r".equals(mode)) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProviderHandler.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProviderHandler.java
index a460421..a3cf90b 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProviderHandler.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/provider/FileProviderHandler.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 4/18/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class FileProviderHandler {
public static Uri convertFileUri(Context context, Uri uri) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ActivityManagerCommonProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ActivityManagerCommonProxy.java
index 3cbc3d8..259fdee 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ActivityManagerCommonProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ActivityManagerCommonProxy.java
@@ -24,14 +24,7 @@ import top.niunaijun.blackbox.utils.compat.StartActivityCompat;
import static android.content.pm.PackageManager.GET_META_DATA;
-/**
- * updated by alex5402 on 4/21/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ActivityManagerCommonProxy {
public static final String TAG = "CommonStub";
@@ -43,15 +36,15 @@ public class ActivityManagerCommonProxy {
Intent intent = getIntent(args);
Slog.d(TAG, "Hook in : " + intent);
assert intent != null;
- // Allow PermissionController to run so apps receive onRequestPermissionsResult
- // (granting is still handled by our Package/AppOps hooks).
+
+
if (intent.getParcelableExtra("_B_|_target_") != null) {
return method.invoke(who, args);
}
if (ComponentUtils.isRequestInstall(intent)) {
File file = FileProviderHandler.convertFile(BActivityThread.getApplication(), intent.getData());
- // Check if this is an attempt to install BlackBox app
+
if (file != null && file.exists()) {
try {
PackageInfo packageInfo = BlackBoxCore.getPackageManager().getPackageArchiveInfo(file.getAbsolutePath(), 0);
@@ -60,7 +53,7 @@ public class ActivityManagerCommonProxy {
String hostPackageName = BlackBoxCore.getHostPkg();
if (packageName.equals(hostPackageName)) {
Slog.w(TAG, "Blocked attempt to install BlackBox app from within BlackBox: " + packageName);
- // Return success but don't actually install
+
return 0;
}
}
@@ -145,7 +138,7 @@ public class ActivityManagerCommonProxy {
String[] resolvedTypes = (String[]) args[index++];
IBinder resultTo = (IBinder) args[index++];
Bundle options = (Bundle) args[index];
- // todo ??
+
if (!ComponentUtils.isSelf(intents)) {
return method.invoke(who, args);
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AndroidIdProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AndroidIdProxy.java
index b26644a..853d560 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AndroidIdProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AndroidIdProxy.java
@@ -7,9 +7,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Android ID proxy to handle Android ID retrieval issues that cause problems with Google Play Store.
- */
+
public class AndroidIdProxy extends ClassInvocationStub {
public static final String TAG = "AndroidIdProxy";
@@ -58,7 +56,7 @@ public class AndroidIdProxy extends ClassInvocationStub {
Slog.d(TAG, "AndroidId: Handling getString call");
Object result = method.invoke(who, args);
- // Check if this is an Android ID related string
+
if (args != null && args.length > 0 && args[0] instanceof String) {
String key = (String) args[0];
if (key.contains("android_id") || key.contains("ANDROID_ID") ||
@@ -85,7 +83,7 @@ public class AndroidIdProxy extends ClassInvocationStub {
Slog.d(TAG, "AndroidId: Handling getLong call");
Object result = method.invoke(who, args);
- // Check if this is an Android ID related long value
+
if (args != null && args.length > 0 && args[0] instanceof String) {
String key = (String) args[0];
if (key.contains("android_id") || key.contains("ANDROID_ID") ||
@@ -112,7 +110,7 @@ public class AndroidIdProxy extends ClassInvocationStub {
Slog.d(TAG, "AndroidId: Handling get call");
Object result = method.invoke(who, args);
- // Check if this is an Android ID related get
+
if (args != null && args.length > 0 && args[0] instanceof String) {
String key = (String) args[0];
if (key.contains("android_id") || key.contains("ANDROID_ID") ||
@@ -139,7 +137,7 @@ public class AndroidIdProxy extends ClassInvocationStub {
Slog.d(TAG, "AndroidId: Handling read call");
Object result = method.invoke(who, args);
- // Check if this is an Android ID related read
+
if (args != null && args.length > 0 && args[0] instanceof String) {
String key = (String) args[0];
if (key.contains("android_id") || key.contains("ANDROID_ID") ||
@@ -158,9 +156,9 @@ public class AndroidIdProxy extends ClassInvocationStub {
}
}
- // Helper methods to generate mock Android IDs
+
private static String generateMockAndroidId() {
- // Generate a 16-character hex string that looks like a real Android ID
+
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++) {
sb.append(Integer.toHexString((int) (Math.random() * 16)));
@@ -171,7 +169,7 @@ public class AndroidIdProxy extends ClassInvocationStub {
}
private static Long generateMockAndroidIdLong() {
- // Generate a long value that represents a valid Android ID
+
long mockId = (long) (Math.random() * Long.MAX_VALUE);
Slog.d(TAG, "AndroidId: Generated mock Android ID long: " + mockId);
return mockId;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ApkAssetsProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ApkAssetsProxy.java
index d49c758..ee02be1 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ApkAssetsProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ApkAssetsProxy.java
@@ -8,9 +8,7 @@ import top.niunaijun.blackbox.fake.hook.ClassInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * Proxy for ApkAssets to block problematic resource loading
- */
+
public class ApkAssetsProxy extends ClassInvocationStub {
public static final String TAG = "ApkAssetsProxy";
@@ -26,12 +24,12 @@ public class ApkAssetsProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // This is a static hook, not an instance hook
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // This is a static hook, no injection needed
+
}
@Override
@@ -50,7 +48,7 @@ public class ApkAssetsProxy extends ClassInvocationStub {
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String path = (String) args[0];
- // Block problematic resource paths
+
if (path != null && (path.contains("resource-cache") ||
path.contains("@idmap") ||
path.contains(".frro") ||
@@ -60,7 +58,7 @@ public class ApkAssetsProxy extends ClassInvocationStub {
throw new RuntimeException("Blocked problematic overlay path: " + path);
}
- // For non-problematic paths, proceed normally
+
return method.invoke(who, args);
}
}
@@ -71,7 +69,7 @@ public class ApkAssetsProxy extends ClassInvocationStub {
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String path = (String) args[0];
- // Block problematic resource paths
+
if (path != null && (path.contains("resource-cache") ||
path.contains("@idmap") ||
path.contains(".frro") ||
@@ -81,7 +79,7 @@ public class ApkAssetsProxy extends ClassInvocationStub {
throw new RuntimeException("Blocked problematic native load path: " + path);
}
- // For non-problematic paths, proceed normally
+
return method.invoke(who, args);
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioPermissionProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioPermissionProxy.java
index d115917..786748b 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioPermissionProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioPermissionProxy.java
@@ -12,9 +12,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Comprehensive audio permission proxy to handle all audio-related permission issues.
- */
+
public class AudioPermissionProxy extends BinderInvocationStub {
public static final String TAG = "AudioPermissionProxy";
@@ -31,7 +29,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
try {
- // Try to get the audio service interface
+
Class> stubClass = Class.forName("android.media.IAudioService$Stub");
Method asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class);
Object iface = asInterfaceMethod.invoke(null, binder);
@@ -59,7 +57,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
return false;
}
- // Force microphone to be unmuted
+
@ProxyMethod("isMicrophoneMuted")
public static class IsMicrophoneMuted extends MethodHook {
@Override
@@ -69,21 +67,21 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Force microphone to be unmuted
+
@ProxyMethod("setMicrophoneMute")
public static class SetMicrophoneMute extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "AudioPermission: setMicrophoneMute called, forcing unmute");
- // Force microphone to be unmuted
+
if (args != null && args.length > 0) {
- args[0] = false; // Force unmute
+ args[0] = false;
}
return method.invoke(who, args);
}
}
- // Force microphone to be unmuted for user
+
@ProxyMethod("isMicrophoneMutedForUser")
public static class IsMicrophoneMutedForUser extends MethodHook {
@Override
@@ -93,21 +91,21 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Force microphone to be unmuted for user
+
@ProxyMethod("setMicrophoneMuteForUser")
public static class SetMicrophoneMuteForUser extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "AudioPermission: setMicrophoneMuteForUser called, forcing unmute");
- // Force microphone to be unmuted
+
if (args != null && args.length > 1) {
- args[1] = false; // Force unmute
+ args[1] = false;
}
return method.invoke(who, args);
}
}
- // Allow audio recording operations
+
@ProxyMethod("startRecording")
public static class StartRecording extends MethodHook {
@Override
@@ -117,7 +115,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio recording operations
+
@ProxyMethod("stopRecording")
public static class StopRecording extends MethodHook {
@Override
@@ -127,7 +125,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio recording operations
+
@ProxyMethod("isRecordingActive")
public static class IsRecordingActive extends MethodHook {
@Override
@@ -137,7 +135,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio recording operations
+
@ProxyMethod("getRecordingState")
public static class GetRecordingState extends MethodHook {
@Override
@@ -147,7 +145,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio recording state queries
+
@ProxyMethod("getRecordingStateForUser")
public static class GetRecordingStateForUser extends MethodHook {
@Override
@@ -157,7 +155,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio focus requests
+
@ProxyMethod("requestAudioFocus")
public static class RequestAudioFocus extends MethodHook {
@Override
@@ -167,7 +165,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio focus client registration
+
@ProxyMethod("registerAudioFocusClient")
public static class RegisterAudioFocusClient extends MethodHook {
@Override
@@ -177,7 +175,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio focus client unregistration
+
@ProxyMethod("unregisterAudioFocusClient")
public static class UnregisterAudioFocusClient extends MethodHook {
@Override
@@ -187,7 +185,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio focus abandonment
+
@ProxyMethod("abandonAudioFocus")
public static class AbandonAudioFocus extends MethodHook {
@Override
@@ -197,7 +195,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio mode changes
+
@ProxyMethod("setMode")
public static class SetMode extends MethodHook {
@Override
@@ -207,7 +205,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio mode queries
+
@ProxyMethod("getMode")
public static class GetMode extends MethodHook {
@Override
@@ -217,7 +215,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio stream volume changes
+
@ProxyMethod("setStreamVolume")
public static class SetStreamVolume extends MethodHook {
@Override
@@ -227,7 +225,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio stream volume queries
+
@ProxyMethod("getStreamVolume")
public static class GetStreamVolume extends MethodHook {
@Override
@@ -237,7 +235,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio stream max volume queries
+
@ProxyMethod("getStreamMaxVolume")
public static class GetStreamMaxVolume extends MethodHook {
@Override
@@ -247,7 +245,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio stream mute operations
+
@ProxyMethod("setStreamMute")
public static class SetStreamMute extends MethodHook {
@Override
@@ -257,7 +255,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio stream mute queries
+
@ProxyMethod("isStreamMute")
public static class IsStreamMute extends MethodHook {
@Override
@@ -267,7 +265,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio routing operations
+
@ProxyMethod("setSpeakerphoneOn")
public static class SetSpeakerphoneOn extends MethodHook {
@Override
@@ -277,7 +275,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow audio routing queries
+
@ProxyMethod("isSpeakerphoneOn")
public static class IsSpeakerphoneOn extends MethodHook {
@Override
@@ -287,7 +285,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow bluetooth audio operations
+
@ProxyMethod("setBluetoothScoOn")
public static class SetBluetoothScoOn extends MethodHook {
@Override
@@ -297,7 +295,7 @@ public class AudioPermissionProxy extends BinderInvocationStub {
}
}
- // Allow bluetooth audio queries
+
@ProxyMethod("isBluetoothScoOn")
public static class IsBluetoothScoOn extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioRecordProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioRecordProxy.java
index b7d3ca6..60869d2 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioRecordProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AudioRecordProxy.java
@@ -9,9 +9,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * AudioRecord proxy to handle low-level audio recording in sandboxed apps.
- */
+
public class AudioRecordProxy extends ClassInvocationStub {
public static final String TAG = "AudioRecordProxy";
@@ -21,12 +19,12 @@ public class AudioRecordProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook AudioRecord class methods directly
+
}
@Override
@@ -34,7 +32,7 @@ public class AudioRecordProxy extends ClassInvocationStub {
return false;
}
- // Hook AudioRecord constructor
+
@ProxyMethod("")
public static class Constructor extends MethodHook {
@Override
@@ -44,7 +42,7 @@ public class AudioRecordProxy extends ClassInvocationStub {
}
}
- // Hook startRecording
+
@ProxyMethod("startRecording")
public static class StartRecording extends MethodHook {
@Override
@@ -54,7 +52,7 @@ public class AudioRecordProxy extends ClassInvocationStub {
}
}
- // Hook stop
+
@ProxyMethod("stop")
public static class Stop extends MethodHook {
@Override
@@ -64,7 +62,7 @@ public class AudioRecordProxy extends ClassInvocationStub {
}
}
- // Hook read
+
@ProxyMethod("read")
public static class Read extends MethodHook {
@Override
@@ -74,7 +72,7 @@ public class AudioRecordProxy extends ClassInvocationStub {
}
}
- // Hook release
+
@ProxyMethod("release")
public static class Release extends MethodHook {
@Override
@@ -84,7 +82,7 @@ public class AudioRecordProxy extends ClassInvocationStub {
}
}
- // Hook getState
+
@ProxyMethod("getState")
public static class GetState extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AuthenticationProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AuthenticationProxy.java
index f147a45..02e44de 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AuthenticationProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/AuthenticationProxy.java
@@ -7,9 +7,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Authentication proxy to handle general authentication issues in sandboxed apps.
- */
+
public class AuthenticationProxy extends ClassInvocationStub {
public static final String TAG = "AuthenticationProxy";
@@ -171,7 +169,7 @@ public class AuthenticationProxy extends ClassInvocationStub {
}
}
- // Helper methods to create mock objects
+
private static Object createMockSignInResult() {
try {
Class> bundleClass = Class.forName("android.os.Bundle");
@@ -194,7 +192,7 @@ public class AuthenticationProxy extends ClassInvocationStub {
private static Object createMockUser() {
try {
- // Try to create a mock user object
+
Class> userClass = Class.forName("android.os.Bundle");
return userClass.newInstance();
} catch (Exception e) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/BrowserEngineProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/BrowserEngineProxy.java
index 6815d10..08fbfd1 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/BrowserEngineProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/BrowserEngineProxy.java
@@ -10,10 +10,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Proxy to handle browser-specific (GeckoView/Chromium) issues in virtualized environment.
- * Browsers use advanced sandboxing and multi-process architecture that can conflict with virtualization.
- */
+
public class BrowserEngineProxy extends ClassInvocationStub {
public static final String TAG = "BrowserEngineProxy";
@@ -28,7 +25,7 @@ public class BrowserEngineProxy extends ClassInvocationStub {
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Not needed for class method hooks
+
}
@Override
@@ -36,19 +33,16 @@ public class BrowserEngineProxy extends ClassInvocationStub {
return false;
}
- /**
- * Hook Process.start() to handle browser child process creation
- * Browsers (especially Gecko/Chromium) spawn isolated child processes for rendering
- */
+
@ProxyMethod("start")
public static class ProcessStart extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Let the process start normally
+
Object result = method.invoke(who, args);
- // Log for debugging
+
if (args != null && args.length > 0) {
Slog.d(TAG, "Process.start() called with args count: " + args.length);
}
@@ -56,15 +50,13 @@ public class BrowserEngineProxy extends ClassInvocationStub {
return result;
} catch (Exception e) {
Slog.e(TAG, "Process.start() failed: " + e.getMessage(), e);
- // Re-throw to let the app handle it
+
throw e;
}
}
}
- /**
- * Hook Process.setArgV0() which browsers use to rename child processes
- */
+
@ProxyMethod("setArgV0")
public static class SetArgV0 extends MethodHook {
@Override
@@ -77,9 +69,7 @@ public class BrowserEngineProxy extends ClassInvocationStub {
}
}
- /**
- * Hook Process.killProcess() to log unexpected terminations
- */
+
@ProxyMethod("killProcess")
public static class KillProcess extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ClassLoaderProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ClassLoaderProxy.java
index 76dbd02..65c5226 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ClassLoaderProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ClassLoaderProxy.java
@@ -25,20 +25,17 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.DexFileRecovery;
-/**
- * Comprehensive ClassLoader proxy to handle DEX file corruption and ClassLoader failures.
- * This fixes the "classes.dex: Entry not found" and ClassNotFoundException issues.
- */
+
public class ClassLoaderProxy extends ClassInvocationStub {
private static final String TAG = "ClassLoaderProxy";
- // Cache for successfully loaded classes to avoid repeated failures
+
private static final Map> sClassCache = new HashMap<>();
- // Cache for DEX file validation results
+
private static final Map sDexFileCache = new HashMap<>();
- // Fallback class loaders for different scenarios
+
private static final List sFallbackClassLoaders = new ArrayList<>();
public ClassLoaderProxy() {
@@ -48,12 +45,12 @@ public class ClassLoaderProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook ClassLoader class methods directly
+
Slog.d(TAG, "ClassLoader proxy injected for DEX file corruption prevention");
}
@@ -62,12 +59,10 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return false;
}
- /**
- * Initialize fallback class loaders for recovery scenarios
- */
+
private void initializeFallbackClassLoaders() {
try {
- // Add host app class loader as fallback
+
Context hostContext = BlackBoxCore.getContext();
if (hostContext != null) {
ClassLoader hostClassLoader = hostContext.getClassLoader();
@@ -77,14 +72,14 @@ public class ClassLoaderProxy extends ClassInvocationStub {
}
}
- // Add system class loader as fallback
+
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if (systemClassLoader != null) {
sFallbackClassLoaders.add(systemClassLoader);
Slog.d(TAG, "Added system class loader as fallback");
}
- // Add boot class loader as fallback
+
ClassLoader bootClassLoader = Object.class.getClassLoader();
if (bootClassLoader != null) {
sFallbackClassLoaders.add(bootClassLoader);
@@ -96,7 +91,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
}
}
- // Hook loadClass to handle missing classes gracefully
+
@ProxyMethod("loadClass")
public static class LoadClass extends MethodHook {
@Override
@@ -104,23 +99,23 @@ public class ClassLoaderProxy extends ClassInvocationStub {
String className = (String) args[0];
boolean resolve = args.length > 1 ? (Boolean) args[1] : false;
- // Check cache first
+
if (sClassCache.containsKey(className)) {
Slog.d(TAG, "ClassLoader: loadClass returning cached class: " + className);
return sClassCache.get(className);
}
- // Handle known problematic classes
+
if (isProblematicClass(className)) {
Slog.d(TAG, "ClassLoader: loadClass called for problematic class: " + className + ", returning null");
return null;
}
try {
- // Try original method first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Cache successful result
+
sClassCache.put(className, (Class>) result);
Slog.d(TAG, "ClassLoader: loadClass successful for: " + className);
return result;
@@ -129,7 +124,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
Slog.w(TAG, "ClassLoader: loadClass failed for " + className + ", trying fallbacks: " + e.getMessage());
}
- // Try fallback class loaders
+
Class> fallbackResult = tryFallbackClassLoaders(className);
if (fallbackResult != null) {
sClassCache.put(className, fallbackResult);
@@ -137,36 +132,36 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return fallbackResult;
}
- // If all else fails, try to create a stub class or return null
+
Slog.w(TAG, "ClassLoader: loadClass failed for " + className + ", returning null");
return null;
}
}
- // Hook findClass to handle missing classes gracefully
+
@ProxyMethod("findClass")
public static class FindClass extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String className = (String) args[0];
- // Check cache first
+
if (sClassCache.containsKey(className)) {
Slog.d(TAG, "ClassLoader: findClass returning cached class: " + className);
return sClassCache.get(className);
}
- // Handle known problematic classes
+
if (isProblematicClass(className)) {
Slog.d(TAG, "ClassLoader: findClass called for problematic class: " + className + ", returning null");
return null;
}
try {
- // Try original method first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Cache successful result
+
sClassCache.put(className, (Class>) result);
Slog.d(TAG, "ClassLoader: findClass successful for: " + className);
return result;
@@ -175,7 +170,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
Slog.w(TAG, "ClassLoader: findClass failed for " + className + ", trying fallbacks: " + e.getMessage());
}
- // Try fallback class loaders
+
Class> fallbackResult = tryFallbackClassLoaders(className);
if (fallbackResult != null) {
sClassCache.put(className, fallbackResult);
@@ -183,36 +178,36 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return fallbackResult;
}
- // If all else fails, try to create a stub class or return null
+
Slog.w(TAG, "ClassLoader: findClass failed for " + className + ", returning null");
return null;
}
}
- // Hook forName to handle missing classes gracefully
+
@ProxyMethod("forName")
public static class ForName extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String className = (String) args[0];
- // Check cache first
+
if (sClassCache.containsKey(className)) {
Slog.d(TAG, "ClassLoader: forName returning cached class: " + className);
return sClassCache.get(className);
}
- // Handle known problematic classes
+
if (isProblematicClass(className)) {
Slog.d(TAG, "ClassLoader: forName called for problematic class: " + className + ", returning null");
return null;
}
try {
- // Try original method first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Cache successful result
+
sClassCache.put(className, (Class>) result);
Slog.d(TAG, "ClassLoader: forName successful for: " + className);
return result;
@@ -221,7 +216,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
Slog.w(TAG, "ClassLoader: forName failed for " + className + ", trying fallbacks: " + e.getMessage());
}
- // Try fallback class loaders
+
Class> fallbackResult = tryFallbackClassLoaders(className);
if (fallbackResult != null) {
sClassCache.put(className, fallbackResult);
@@ -229,31 +224,31 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return fallbackResult;
}
- // If all else fails, try to create a stub class or return null
+
Slog.w(TAG, "ClassLoader: forName failed for " + className + ", returning null");
return null;
}
}
- // Hook DexFile operations to prevent crashes
+
@ProxyMethod("openDexFile")
public static class OpenDexFile extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String sourceFile = (String) args[0];
- // Validate DEX file before opening
+
if (!isValidDexFile(sourceFile)) {
Slog.w(TAG, "DexFile: Invalid DEX file detected: " + sourceFile + ", attempting recovery");
- // Try to recover or use fallback
+
String recoveredFile = recoverDexFile(sourceFile);
if (recoveredFile != null) {
args[0] = recoveredFile;
Slog.d(TAG, "DexFile: Using recovered DEX file: " + recoveredFile);
} else {
Slog.e(TAG, "DexFile: Could not recover DEX file: " + sourceFile);
- return null; // Return null to prevent crash
+ return null;
}
}
@@ -261,12 +256,12 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "DexFile: openDexFile failed for " + sourceFile + ", returning null: " + e.getMessage());
- return null; // Return null to prevent crash
+ return null;
}
}
}
- // Hook DexPathList operations to prevent crashes
+
@ProxyMethod("loadDexFile")
public static class LoadDexFile extends MethodHook {
@Override
@@ -278,13 +273,13 @@ public class ClassLoaderProxy extends ClassInvocationStub {
if (errorMessage != null && errorMessage.contains("classes.dex") && errorMessage.contains("Entry not found")) {
Slog.w(TAG, "DexPathList: classes.dex entry not found, attempting recovery");
- // Try to recover the DEX file using the comprehensive recovery utility
+
String corruptedFilePath = extractCorruptedFilePathFromError(e, who);
if (corruptedFilePath != null) {
DexFileRecovery.RecoveryResult recoveryResult = DexFileRecovery.recoverDexFile(corruptedFilePath);
if (recoveryResult.success) {
Slog.d(TAG, "DexPathList: Successfully recovered DEX file via " + recoveryResult.recoveryMethod);
- // Try to create a fallback DexPathList with the recovered file
+
Object recoveredResult = createFallbackDexPathList(who, recoveryResult.recoveredFilePath);
if (recoveredResult != null) {
return recoveredResult;
@@ -296,21 +291,19 @@ public class ClassLoaderProxy extends ClassInvocationStub {
}
Slog.w(TAG, "DexPathList: loadDexFile failed, returning null: " + e.getMessage());
- return null; // Return null to prevent crash
+ return null;
}
}
- /**
- * Extract the corrupted file path from the error message
- */
+
private String extractCorruptedFilePathFromError(Exception e, Object who) {
try {
- // Parse the error message to find the corrupted file path
+
String errorMessage = e.getMessage();
if (errorMessage != null) {
- // Look for file paths in the error message
+
if (errorMessage.contains("/data/app/")) {
- // Extract the path from the error
+
int startIndex = errorMessage.indexOf("/data/app/");
if (startIndex >= 0) {
int endIndex = errorMessage.indexOf(" ", startIndex);
@@ -322,7 +315,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
}
}
- // Try to get the path from the DexPathList object
+
try {
Field pathListField = who.getClass().getDeclaredField("pathList");
pathListField.setAccessible(true);
@@ -332,7 +325,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
dexElementsField.setAccessible(true);
Object[] dexElements = (Object[]) dexElementsField.get(pathList);
if (dexElements != null && dexElements.length > 0) {
- // Get the first dex element's path
+
Field pathField = dexElements[0].getClass().getDeclaredField("path");
pathField.setAccessible(true);
return (String) pathField.get(dexElements[0]);
@@ -350,9 +343,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
}
}
- /**
- * Try to load class using fallback class loaders
- */
+
private static Class> tryFallbackClassLoaders(String className) {
for (ClassLoader fallbackLoader : sFallbackClassLoaders) {
try {
@@ -362,19 +353,17 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return result;
}
} catch (Exception e) {
- // Continue to next fallback
+
}
}
return null;
}
- /**
- * Check if a DEX file is valid
- */
+
private static boolean isValidDexFile(String sourceFile) {
if (sourceFile == null) return false;
- // Check cache first
+
if (sDexFileCache.containsKey(sourceFile)) {
return sDexFileCache.get(sourceFile);
}
@@ -386,9 +375,9 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return false;
}
- // Check if it's a valid APK/ZIP file
+
if (sourceFile.endsWith(".apk") || sourceFile.endsWith(".zip")) {
- // Basic validation - check if file contains classes.dex
+
boolean isValid = validateApkFile(file);
sDexFileCache.put(sourceFile, isValid);
return isValid;
@@ -404,31 +393,27 @@ public class ClassLoaderProxy extends ClassInvocationStub {
}
}
- /**
- * Validate APK file structure
- */
+
private static boolean validateApkFile(File apkFile) {
try {
- // This is a simplified validation - in a real implementation,
- // you would use ZipFile to check for classes.dex entry
- return apkFile.length() > 1000; // Basic size check
+
+
+ return apkFile.length() > 1000;
} catch (Exception e) {
return false;
}
}
- /**
- * Attempt to recover a corrupted DEX file
- */
+
private static String recoverDexFile(String sourceFile) {
try {
- // Try to find alternative APK files
+
String alternativeFile = findAlternativeApkFile(sourceFile);
if (alternativeFile != null) {
return alternativeFile;
}
- // Try to use host app's APK as fallback
+
Context hostContext = BlackBoxCore.getContext();
if (hostContext != null) {
ApplicationInfo appInfo = hostContext.getApplicationInfo();
@@ -445,9 +430,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return null;
}
- /**
- * Find alternative APK file
- */
+
private static String findAlternativeApkFile(String originalFile) {
try {
File original = new File(originalFile);
@@ -456,7 +439,7 @@ public class ClassLoaderProxy extends ClassInvocationStub {
File[] files = parent.listFiles();
if (files != null) {
for (File file : files) {
- if (file.getName().endsWith(".apk") && file.length() > 1000000) { // > 1MB
+ if (file.getName().endsWith(".apk") && file.length() > 1000000) {
Slog.d(TAG, "Found alternative APK file: " + file.getAbsolutePath());
return file.getAbsolutePath();
}
@@ -469,17 +452,15 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return null;
}
- /**
- * Attempt to recover DexPathList
- */
+
private static Object recoverDexPathList(Object who, Object[] args) {
try {
- // Try to create a minimal DexPathList with fallback DEX files
+
Context hostContext = BlackBoxCore.getContext();
if (hostContext != null) {
ApplicationInfo appInfo = hostContext.getApplicationInfo();
if (appInfo != null && appInfo.sourceDir != null) {
- // Use host app's APK as fallback
+
Slog.d(TAG, "Recovering DexPathList using host APK: " + appInfo.sourceDir);
return createFallbackDexPathList(who, appInfo.sourceDir);
}
@@ -490,50 +471,48 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return null;
}
- /**
- * Create fallback DexPathList
- */
+
private static Object createFallbackDexPathList(Object who, String fallbackApk) {
try {
- // This is a simplified implementation
- // In a real scenario, you would need to properly construct a DexPathList
+
+
Slog.d(TAG, "Creating fallback DexPathList with: " + fallbackApk);
- return null; // Return null for now to prevent crash
+ return null;
} catch (Exception e) {
Slog.w(TAG, "Error creating fallback DexPathList: " + e.getMessage());
return null;
}
}
- // Helper method to identify problematic classes
+
private static boolean isProblematicClass(String className) {
if (className == null) return false;
- // Kotlin coroutines test classes
+
if (className.contains("kotlinx.coroutines.test")) {
return true;
}
- // MediaTek performance classes
+
if (className.contains("com.mediatek.perfservice") ||
className.contains("com.mediatek.powerhalmgr")) {
return true;
}
- // DataStore protobuf classes
+
if (className.contains("androidx.datastore.preferences.protobuf") ||
className.contains("NewInstanceSchemaFull") ||
className.contains("ExtensionSchemaFull")) {
return true;
}
- // Robolectric test framework
+
if (className.contains("org.robolectric") ||
className.contains("Robolectric")) {
return true;
}
- // Other known problematic classes
+
if (className.contains("TestMainDispatcherFactory") ||
className.contains("PerfServiceWrapper") ||
className.contains("PowerHalMgrFactory")) {
@@ -543,18 +522,14 @@ public class ClassLoaderProxy extends ClassInvocationStub {
return false;
}
- /**
- * Clear class cache (useful for debugging)
- */
+
public static void clearClassCache() {
sClassCache.clear();
sDexFileCache.clear();
Slog.d(TAG, "Class and DEX file caches cleared");
}
- /**
- * Get cache statistics
- */
+
public static String getCacheStats() {
return "Class Cache: " + sClassCache.size() + " entries, DEX Cache: " + sDexFileCache.size() + " entries";
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ContentResolverProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ContentResolverProxy.java
index 97f2fcd..27f6aba 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ContentResolverProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ContentResolverProxy.java
@@ -10,9 +10,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.fake.hook.ClassInvocationStub;
-/**
- * ContentResolver proxy to handle MediaStore audio queries in virtualized apps.
- */
+
public class ContentResolverProxy extends ClassInvocationStub {
public static final String TAG = "ContentResolverProxy";
@@ -22,13 +20,13 @@ public class ContentResolverProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return the ContentResolver from the context
+
return BlackBoxCore.getContext().getContentResolver();
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook ContentResolver class methods directly
+
}
@Override
@@ -36,7 +34,7 @@ public class ContentResolverProxy extends ClassInvocationStub {
return false;
}
- // Hook ContentResolver.query() for audio URIs
+
@ProxyMethod("query")
public static class Query extends MethodHook {
@Override
@@ -45,7 +43,7 @@ public class ContentResolverProxy extends ClassInvocationStub {
Uri uri = (Uri) args[0];
String uriString = uri.toString();
- // Check if this is an audio-related query
+
if (uriString.contains("audio") || uriString.contains("media") ||
uriString.contains("content://media/external/audio") ||
uriString.contains("content://media/internal/audio") ||
@@ -54,17 +52,17 @@ public class ContentResolverProxy extends ClassInvocationStub {
Slog.d(TAG, "ContentResolver: Allowing audio query: " + uriString);
- // Allow audio queries to proceed normally instead of returning empty cursor
+
return method.invoke(who, args);
}
}
- // For non-audio queries, proceed normally
+
return method.invoke(who, args);
}
}
- // Hook ContentResolver.query() with projection for audio URIs
+
@ProxyMethod("query")
public static class QueryWithProjection extends MethodHook {
@Override
@@ -73,7 +71,7 @@ public class ContentResolverProxy extends ClassInvocationStub {
Uri uri = (Uri) args[0];
String uriString = uri.toString();
- // Check if this is an audio-related query
+
if (uriString.contains("audio") || uriString.contains("media") ||
uriString.contains("content://media/external/audio") ||
uriString.contains("content://media/internal/audio") ||
@@ -82,17 +80,17 @@ public class ContentResolverProxy extends ClassInvocationStub {
Slog.d(TAG, "ContentResolver: Allowing audio query with projection: " + uriString);
- // Allow audio queries to proceed normally instead of returning empty cursor
+
return method.invoke(who, args);
}
}
- // For non-audio queries, proceed normally
+
return method.invoke(who, args);
}
}
- // Hook ContentResolver.insert() for audio URIs
+
@ProxyMethod("insert")
public static class Insert extends MethodHook {
@Override
@@ -110,7 +108,7 @@ public class ContentResolverProxy extends ClassInvocationStub {
}
}
- // Hook ContentResolver.update() for audio URIs
+
@ProxyMethod("update")
public static class Update extends MethodHook {
@Override
@@ -128,7 +126,7 @@ public class ContentResolverProxy extends ClassInvocationStub {
}
}
- // Hook ContentResolver.delete() for audio URIs
+
@ProxyMethod("delete")
public static class Delete extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/DeviceIdProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/DeviceIdProxy.java
index a44ae05..2b4386e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/DeviceIdProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/DeviceIdProxy.java
@@ -7,9 +7,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Device ID proxy to handle GMS device ID retrieval issues.
- */
+
public class DeviceIdProxy extends ClassInvocationStub {
public static final String TAG = "DeviceIdProxy";
@@ -19,12 +17,12 @@ public class DeviceIdProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook device ID related class methods directly
+
}
@Override
@@ -32,7 +30,7 @@ public class DeviceIdProxy extends ClassInvocationStub {
return false;
}
- // Hook device ID getter methods to prevent NullPointerException
+
@ProxyMethod("getDeviceId")
public static class GetDeviceId extends MethodHook {
@Override
@@ -50,7 +48,7 @@ public class DeviceIdProxy extends ClassInvocationStub {
}
}
- // Hook device ID setter methods
+
@ProxyMethod("setDeviceId")
public static class SetDeviceId extends MethodHook {
@Override
@@ -68,7 +66,7 @@ public class DeviceIdProxy extends ClassInvocationStub {
}
}
- // Hook device ID validation methods
+
@ProxyMethod("isValidDeviceId")
public static class IsValidDeviceId extends MethodHook {
@Override
@@ -86,7 +84,7 @@ public class DeviceIdProxy extends ClassInvocationStub {
}
}
- // Hook device ID generation methods
+
@ProxyMethod("generateDeviceId")
public static class GenerateDeviceId extends MethodHook {
@Override
@@ -100,7 +98,7 @@ public class DeviceIdProxy extends ClassInvocationStub {
}
}
- // Hook device ID storage methods
+
@ProxyMethod("storeDeviceId")
public static class StoreDeviceId extends MethodHook {
@Override
@@ -118,7 +116,7 @@ public class DeviceIdProxy extends ClassInvocationStub {
}
}
- // Hook device ID retrieval methods
+
@ProxyMethod("retrieveDeviceId")
public static class RetrieveDeviceId extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FeatureFlagUtilsProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FeatureFlagUtilsProxy.java
index dcc8e4f..8ca2388 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FeatureFlagUtilsProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FeatureFlagUtilsProxy.java
@@ -8,10 +8,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * FeatureFlagUtils proxy to handle UID mismatch issues
- * when virtual apps try to access feature flags
- */
+
public class FeatureFlagUtilsProxy extends ClassInvocationStub {
public static final String TAG = "FeatureFlagUtilsProxy";
@@ -38,13 +35,13 @@ public class FeatureFlagUtilsProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to call the original method first
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in FeatureFlagUtils.isEnabled, returning safe default: " + errorMsg);
- return true; // Return safe default for feature flags
+ return true;
}
throw e;
}
@@ -56,13 +53,13 @@ public class FeatureFlagUtilsProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to call the original method first
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in FeatureFlagUtils.getString, returning safe default: " + errorMsg);
- return "true"; // Return safe default for feature flags
+ return "true";
}
throw e;
}
@@ -74,13 +71,13 @@ public class FeatureFlagUtilsProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to call the original method first
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in FeatureFlagUtils.getInt, returning safe default: " + errorMsg);
- return 1; // Return safe default for feature flags
+ return 1;
}
throw e;
}
@@ -92,13 +89,13 @@ public class FeatureFlagUtilsProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to call the original method first
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in FeatureFlagUtils.getLong, returning safe default: " + errorMsg);
- return 1L; // Return safe default for feature flags
+ return 1L;
}
throw e;
}
@@ -110,13 +107,13 @@ public class FeatureFlagUtilsProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to call the original method first
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in FeatureFlagUtils.getFloat, returning safe default: " + errorMsg);
- return 1.0f; // Return safe default for feature flags
+ return 1.0f;
}
throw e;
}
@@ -128,13 +125,13 @@ public class FeatureFlagUtilsProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to call the original method first
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in FeatureFlagUtils.getBoolean, returning safe default: " + errorMsg);
- return true; // Return safe default for feature flags
+ return true;
}
throw e;
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FileSystemProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FileSystemProxy.java
index 17e854e..77cbcef 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FileSystemProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/FileSystemProxy.java
@@ -8,9 +8,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * FileSystem proxy to handle file and directory creation issues.
- */
+
public class FileSystemProxy extends ClassInvocationStub {
public static final String TAG = "FileSystemProxy";
@@ -20,12 +18,12 @@ public class FileSystemProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook File class methods directly
+
}
@Override
@@ -33,7 +31,7 @@ public class FileSystemProxy extends ClassInvocationStub {
return false;
}
- // Hook mkdirs to handle directory creation issues
+
@ProxyMethod("mkdirs")
public static class Mkdirs extends MethodHook {
@Override
@@ -42,21 +40,21 @@ public class FileSystemProxy extends ClassInvocationStub {
File file = (File) who;
String path = file.getAbsolutePath();
- // Handle Helium crash reporter paths
+
if (path.contains("Helium Crashpad") || path.contains("HeliumCrashReporter")) {
Slog.d(TAG, "FileSystem: mkdirs called for Helium crash path: " + path + ", returning true");
- return true; // Pretend directory was created successfully
+ return true;
}
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "FileSystem: mkdirs failed, returning true", e);
- return true; // Return success to prevent crashes
+ return true;
}
}
}
- // Hook mkdir to handle directory creation issues
+
@ProxyMethod("mkdir")
public static class Mkdir extends MethodHook {
@Override
@@ -65,21 +63,21 @@ public class FileSystemProxy extends ClassInvocationStub {
File file = (File) who;
String path = file.getAbsolutePath();
- // Handle Helium crash reporter paths
+
if (path.contains("Helium Crashpad") || path.contains("HeliumCrashReporter")) {
Slog.d(TAG, "FileSystem: mkdir called for Helium crash path: " + path + ", returning true");
- return true; // Pretend directory was created successfully
+ return true;
}
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "FileSystem: mkdir failed, returning true", e);
- return true; // Return success to prevent crashes
+ return true;
}
}
}
- // Hook isDirectory to handle directory check issues
+
@ProxyMethod("isDirectory")
public static class IsDirectory extends MethodHook {
@Override
@@ -88,16 +86,16 @@ public class FileSystemProxy extends ClassInvocationStub {
File file = (File) who;
String path = file.getAbsolutePath();
- // Handle Helium crash reporter paths
+
if (path.contains("Helium Crashpad") || path.contains("HeliumCrashReporter")) {
Slog.d(TAG, "FileSystem: isDirectory called for Helium crash path: " + path + ", returning true");
- return true; // Pretend it's a directory
+ return true;
}
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "FileSystem: isDirectory failed, returning false", e);
- return false; // Return false to prevent crashes
+ return false;
}
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GmsProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GmsProxy.java
index 4f0681d..e4c40cd 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GmsProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GmsProxy.java
@@ -12,9 +12,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * GMS proxy to handle GMS-specific issues like LevelDB locks, device ID problems, and authentication.
- */
+
public class GmsProxy extends BinderInvocationStub {
public static final String TAG = "GmsProxy";
@@ -56,17 +54,17 @@ public class GmsProxy extends BinderInvocationStub {
return false;
}
- // Hook getService to handle package name validation
+
@ProxyMethod("getService")
public static class GetService extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Check if this is a package name validation issue
+
if (args != null && args.length > 0) {
String callingPackage = (String) args[0];
if ("com.google.android.gms".equals(callingPackage)) {
- // Replace with the correct package name
+
args[0] = BlackBoxCore.getHostPkg();
Slog.d(TAG, "GmsProxy: Fixed calling package from com.google.android.gms to " + BlackBoxCore.getHostPkg());
}
@@ -74,13 +72,13 @@ public class GmsProxy extends BinderInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.e(TAG, "GmsProxy: Error in getService", e);
- // Return a mock service or null to prevent crashes
+
return null;
}
}
}
- // Hook getServiceBroker to handle service broker issues
+
@ProxyMethod("getServiceBroker")
public static class GetServiceBroker extends MethodHook {
@Override
@@ -89,13 +87,13 @@ public class GmsProxy extends BinderInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.e(TAG, "GmsProxy: Error in getServiceBroker", e);
- // Return null to prevent crashes
+
return null;
}
}
}
- // Hook authenticate to handle authentication issues
+
@ProxyMethod("authenticate")
public static class Authenticate extends MethodHook {
@Override
@@ -105,13 +103,13 @@ public class GmsProxy extends BinderInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "GmsProxy: Authentication error, returning success", e);
- // Return a mock successful authentication result
+
return createMockAuthResult();
}
}
}
- // Hook getAccount to handle account retrieval issues
+
@ProxyMethod("getAccount")
public static class GetAccount extends MethodHook {
@Override
@@ -126,7 +124,7 @@ public class GmsProxy extends BinderInvocationStub {
}
}
- // Hook getToken to handle token retrieval issues
+
@ProxyMethod("getToken")
public static class GetToken extends MethodHook {
@Override
@@ -141,7 +139,7 @@ public class GmsProxy extends BinderInvocationStub {
}
}
- // Hook invalidateToken to handle token invalidation
+
@ProxyMethod("invalidateToken")
public static class InvalidateToken extends MethodHook {
@Override
@@ -156,7 +154,7 @@ public class GmsProxy extends BinderInvocationStub {
}
}
- // Hook clearToken to handle token clearing
+
@ProxyMethod("clearToken")
public static class ClearToken extends MethodHook {
@Override
@@ -171,10 +169,10 @@ public class GmsProxy extends BinderInvocationStub {
}
}
- // Helper method to create a mock authentication result
+
private static Object createMockAuthResult() {
try {
- // Try to create a mock Bundle or similar object
+
Class> bundleClass = Class.forName("android.os.Bundle");
return bundleClass.newInstance();
} catch (Exception e) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GoogleAccountManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GoogleAccountManagerProxy.java
index d227d78..0f73a56 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GoogleAccountManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/GoogleAccountManagerProxy.java
@@ -16,10 +16,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.app.BActivityThread;
-/**
- * Google Account Manager proxy to handle authentication and account-related issues
- * in virtual environments. Provides mock Google accounts and authentication tokens.
- */
+
public class GoogleAccountManagerProxy extends ClassInvocationStub {
public static final String TAG = "GoogleAccountManagerProxy";
@@ -42,7 +39,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Not needed for class method hooks
+
}
@Override
@@ -57,7 +54,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "GoogleAccountManager: Handling getAccounts call");
- // Try to get real accounts first
+
Object result = method.invoke(who, args);
if (result != null && result instanceof Account[]) {
Account[] accounts = (Account[]) result;
@@ -67,7 +64,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
}
}
- // Return mock Google account if no real accounts found
+
Slog.d(TAG, "GoogleAccountManager: No real accounts found, returning mock account");
return createMockGoogleAccounts();
@@ -89,14 +86,14 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
String accountType = (String) args[0];
Slog.d(TAG, "GoogleAccountManager: Requesting accounts of type: " + accountType);
- // For Google accounts, return mock accounts
+
if ("com.google".equals(accountType)) {
Slog.d(TAG, "GoogleAccountManager: Returning mock Google accounts");
return createMockGoogleAccounts();
}
}
- // Try to get real accounts
+
return method.invoke(who, args);
} catch (Exception e) {
@@ -143,7 +140,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "GoogleAccountManager: AddAccount error, returning mock result", e);
- // Return a mock Bundle indicating success
+
Bundle result = new Bundle();
result.putString("authAccount", "mock@gmail.com");
result.putString("accountType", "com.google");
@@ -161,7 +158,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "GoogleAccountManager: RemoveAccount error, returning true", e);
- return true; // Assume removal was successful
+ return true;
}
}
}
@@ -175,7 +172,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "GoogleAccountManager: HasFeatures error, returning true", e);
- return true; // Assume all features are available
+ return true;
}
}
}
@@ -273,7 +270,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "GoogleAccountManager: IsAccountPresent error, returning true", e);
- return true; // Assume Google account is present
+ return true;
}
}
}
@@ -292,18 +289,16 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
}
}
- /**
- * Create mock Google accounts for virtual environment
- */
+
private static Account[] createMockGoogleAccounts() {
try {
List accounts = new ArrayList<>();
- // Create a primary mock Google account
+
Account primaryAccount = new Account("mock.user@gmail.com", "com.google");
accounts.add(primaryAccount);
- // Create a secondary mock Google account
+
Account secondaryAccount = new Account("virtual.user@gmail.com", "com.google");
accounts.add(secondaryAccount);
@@ -316,9 +311,7 @@ public class GoogleAccountManagerProxy extends ClassInvocationStub {
}
}
- /**
- * Check if the current package is a Google app
- */
+
private static boolean isGoogleApp() {
try {
Context context = BlackBoxCore.getContext();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/HCallbackProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/HCallbackProxy.java
index d38f7c7..0b7fa44 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/HCallbackProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/HCallbackProxy.java
@@ -37,14 +37,7 @@ import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class HCallbackProxy implements IInjectHook, Handler.Callback {
public static final String TAG = "HCallbackStub";
private Handler.Callback mOtherCallback;
@@ -126,10 +119,10 @@ public class HCallbackProxy implements IInjectHook, Handler.Callback {
private boolean handleLaunchActivity(Object client) {
Object r;
if (BuildCompat.isPie()) {
- // ClientTransaction
+
r = getLaunchActivityItem(client);
} else {
- // ActivityClientRecord
+
r = client;
}
if (r == null)
@@ -169,7 +162,7 @@ public class HCallbackProxy implements IInjectHook, Handler.Callback {
}
return true;
}
- // bind
+
if (!BActivityThread.currentActivityThread().isInit()) {
BActivityThread.currentActivityThread().bindApplication(activityInfo.packageName,
activityInfo.processName);
@@ -179,7 +172,7 @@ public class HCallbackProxy implements IInjectHook, Handler.Callback {
int taskId = BRIActivityManager.get(BRActivityManagerNative.get().getDefault()).getTaskForActivity(token, false);
BlackBoxCore.getBActivityManager().onActivityCreated(taskId, token, stubRecord.mActivityRecord);
- if(BuildCompat.isTiramisu()){//处理跟isPie一样流程
+ if(BuildCompat.isTiramisu()){
LaunchActivityItemContext launchActivityItemContext = BRLaunchActivityItem.get(r);
launchActivityItemContext._set_mIntent(stubRecord.mTarget);
launchActivityItemContext._set_mInfo(activityInfo);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccessibilityManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccessibilityManagerProxy.java
index cecbf8b..0e75e2a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccessibilityManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccessibilityManagerProxy.java
@@ -13,14 +13,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethods;
-/**
- * updated by alex5402 on 4/25/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IAccessibilityManagerProxy extends BinderInvocationStub {
public IAccessibilityManagerProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccountManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccountManagerProxy.java
index 482c752..830904e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccountManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAccountManagerProxy.java
@@ -16,14 +16,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 2022/2/14.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IAccountManagerProxy extends BinderInvocationStub {
public static final String TAG = "IAccountManagerProxy";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityClientProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityClientProxy.java
index c455a45..ad6f951 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityClientProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityClientProxy.java
@@ -14,9 +14,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.fake.hook.ScanClass;
import top.niunaijun.blackbox.utils.compat.TaskDescriptionCompat;
-/**
- * Created by BlackBox on 2022/2/22.
- */
+
@ScanClass(ActivityManagerCommonProxy.class)
public class IActivityClientProxy extends ClassInvocationStub {
public static final String TAG = "IActivityClientProxy";
@@ -88,7 +86,7 @@ public class IActivityClientProxy extends ClassInvocationStub {
}
}
- // for >= Android 12
+
@ProxyMethod("setTaskDescription")
public static class SetTaskDescription extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java
index 4a0a6ed..4f571d1 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityManagerProxy.java
@@ -61,14 +61,7 @@ import static android.content.Context.RECEIVER_NOT_EXPORTED;
import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@ScanClass(ActivityManagerCommonProxy.class)
public class IActivityManagerProxy extends ClassInvocationStub {
public static final String TAG = "ActivityManagerStub";
@@ -113,21 +106,21 @@ public class IActivityManagerProxy extends ClassInvocationStub {
try {
return super.invoke(proxy, method, args);
} catch (SecurityException e) {
- // Handle SecurityExceptions gracefully for all ActivityManager calls
+
String methodName = method.getName();
Slog.w(TAG, "ActivityManager invoke: SecurityException in " + methodName + ", returning safe default", e);
- // Return appropriate default values based on method
+
if (methodName.startsWith("set") || methodName.startsWith("update")) {
- return null; // For setter methods, return null (success)
+ return null;
} else if (methodName.startsWith("get") || methodName.startsWith("query")) {
- return null; // For getter methods, return null (empty result)
+ return null;
} else if (methodName.startsWith("start") || methodName.startsWith("bind")) {
- return false; // For start/bind methods, return false (not started)
+ return false;
} else if (methodName.startsWith("stop") || methodName.startsWith("unbind")) {
- return true; // For stop/unbind methods, return true (stopped)
+ return true;
} else {
- return null; // Default fallback
+ return null;
}
} catch (Exception e) {
Slog.e(TAG, "ActivityManager invoke: Unexpected error in " + method.getName(), e);
@@ -165,17 +158,17 @@ public class IActivityManagerProxy extends ClassInvocationStub {
ContentProviderDelegate.update(content, (String) auth);
return content;
} else {
- // Log.d(TAG, "hook getContentProvider: " + auth);
+
ProviderInfo providerInfo = BlackBoxCore.getBPackageManager()
.resolveContentProvider(
(String) auth, GET_META_DATA, BActivityThread.getUserId());
if (providerInfo == null) {
- // Fallback removed to avoid using original Google services
+
return null;
}
- // Log.d(TAG, "hook app: " + auth);
+
IBinder providerBinder = null;
if (BActivityThread.getAppPid() != -1) {
AppConfig appConfig = BlackBoxCore.getBActivityManager()
@@ -210,7 +203,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
protected int getAuthIndex() {
- // 10.0
+
if (BuildCompat.isQ()) {
return 2;
} else {
@@ -258,12 +251,12 @@ public class IActivityManagerProxy extends ClassInvocationStub {
Intent intent = (Intent) args[1];
String resolvedType = (String) args[2];
- // Check if the service belongs to the current app
+
if (intent != null && intent.getComponent() != null) {
String servicePackage = intent.getComponent().getPackageName();
String currentPackage = BActivityThread.getAppPackageName();
- // If trying to stop a service from a different package, return false instead of crashing
+
if (!servicePackage.equals(currentPackage)) {
Slog.w(TAG, "StopService: Attempting to stop service from different package: " +
servicePackage + " (current: " + currentPackage + "), returning false");
@@ -290,12 +283,12 @@ public class IActivityManagerProxy extends ClassInvocationStub {
ComponentName componentName = (ComponentName) args[0];
IBinder token = (IBinder) args[1];
- // Check if the service belongs to the current app
+
if (componentName != null) {
String servicePackage = componentName.getPackageName();
String currentPackage = BActivityThread.getAppPackageName();
- // If trying to stop a service from a different package, return true instead of crashing
+
if (!servicePackage.equals(currentPackage)) {
Slog.w(TAG, "StopServiceToken: Attempting to stop service from different package: " +
servicePackage + " (current: " + currentPackage + "), returning true");
@@ -320,27 +313,27 @@ public class IActivityManagerProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Check if the target package matches the current app
+
if (args != null && args.length >= 2) {
String targetPackage = (String) args[1];
String currentPackage = BActivityThread.getAppPackageName();
- // If trying to set locus context for a different package, return success instead of crashing
+
if (targetPackage != null && !targetPackage.equals(currentPackage)) {
Slog.w(TAG, "SetActivityLocusContext: Attempting to set locus context for different package: " +
targetPackage + " (current: " + currentPackage + "), returning success");
- return null; // Return null for success
+ return null;
}
}
- // Proceed with original call if package matches
+
return method.invoke(who, args);
} catch (SecurityException e) {
Slog.w(TAG, "SetActivityLocusContext: SecurityException caught, returning success", e);
- return null; // Return null for success
+ return null;
} catch (Exception e) {
Slog.e(TAG, "SetActivityLocusContext: Error setting locus context", e);
- return null; // Return null for success
+ return null;
}
}
}
@@ -351,13 +344,13 @@ public class IActivityManagerProxy extends ClassInvocationStub {
String resolvedType = (String) args[3];
IServiceConnection connection = (IServiceConnection) args[4];
- // Check for null intent
+
if (intent == null) {
Slog.w(TAG, "BindServiceCommon: Intent is null, proceeding with original call");
return method.invoke(who, args);
}
- //int flags = MethodParameterUtils.toInt(args[5]);
+
int userId = intent.getIntExtra("_B_|_UserId", -1);
userId = userId == -1 ? BActivityThread.getUserId() : userId;
@@ -380,7 +373,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- //Log.d(TAG,"Intent:" + intent + "-->" + "proxyIntent:" + proxyIntent + ",flag:" + intent.getFlags() + "proxyFlag:" + proxyIntent.getFlags());
+
if (proxyIntent != null && proxyIntent.getComponent() != null &&
proxyIntent.getComponent().getPackageName().equals(BlackBoxCore.getHostPkg())){
int flagsIndex = getFlagsIndex(args);
@@ -405,7 +398,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
private static int getFlagsIndex(Object[] args) {
- // Heuristic: flags is the first Number after IServiceConnection position (index 4)
+
for (int i = 5; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof Integer || arg instanceof Long) {
@@ -428,7 +421,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- // android 14 add
+
@ProxyMethod("bindServiceInstance")
public static class bindServiceInstance extends MethodHook {
@Override
@@ -442,12 +435,12 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- // 10.0
+
@ProxyMethod("bindIsolatedService")
public static class BindIsolatedService extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // instanceName
+
args[6] = null;
return BindServiceCommon(who,method,args,7);
}
@@ -589,7 +582,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
ProxyBroadcastRecord.saveStub(proxyIntent, intent, BActivityThread.getUserId());
args[intentIndex] = proxyIntent;
}
- // ignore permission
+
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if (o instanceof String[]) {
@@ -650,7 +643,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- // todo
+
@ProxyMethod("sendIntentSender")
public static class SendIntentSender extends MethodHook {
@@ -660,7 +653,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- // android 11 add
+
@ProxyMethod("registerReceiverWithFeature")
public static class RegisterReceiverWithFeature extends MethodHook{
@Override
@@ -678,7 +671,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
args[receiverIndex] = proxy;
}
- // ignore permission
+
if (args[getPermissionIndex()] != null) {
args[getPermissionIndex()] = null;
}
@@ -710,7 +703,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- //maxTargetSdk=29
+
@ProxyMethod("registerReceiver")
public static class RegisterReceiver extends MethodHook {
@@ -730,7 +723,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
args[receiverIndex] = proxy;
}
int permissionIndex = 4;
- // ignore permission
+
if (args[permissionIndex] != null) {
args[permissionIndex] = null;
}
@@ -751,11 +744,11 @@ public class IActivityManagerProxy extends ClassInvocationStub {
public static class setServiceForeground extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Allow foreground service promotion to proceed, and neutralize service type enforcement on Android 14+
- // Find an int argument that represents foregroundServiceType and zero it out
+
+
for (int i = args.length - 1; i >= 0; i--) {
if (args[i] instanceof Integer) {
- args[i] = 0; // remove service type requirements (e.g., MICROPHONE)
+ args[i] = 0;
break;
}
}
@@ -791,13 +784,13 @@ public class IActivityManagerProxy extends ClassInvocationStub {
return PackageManager.PERMISSION_GRANTED;
}
- // Handle all audio-related permissions comprehensively
+
if (isAudioPermission(permission)) {
Slog.d(TAG, "ActivityManager checkPermission: Granting audio permission: " + permission);
return PackageManager.PERMISSION_GRANTED;
}
- // Handle storage/media read permissions so apps can query MediaStore
+
if (isStorageOrMediaPermission(permission)) {
Slog.d(TAG, "ActivityManager checkPermission: Granting storage/media permission: " + permission);
return PackageManager.PERMISSION_GRANTED;
@@ -807,7 +800,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- // Keep in sync with IPackageManagerProxy helper
+
private static boolean isAudioPermission(String permission) {
if (permission == null) return false;
return permission.equals(Manifest.permission.RECORD_AUDIO)
@@ -833,7 +826,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
}
}
- // Keep in sync with IPackageManagerProxy helper
+
private static boolean isStorageOrMediaPermission(String permission) {
if (permission == null) return false;
if (permission.equals(Manifest.permission.READ_EXTERNAL_STORAGE)
@@ -858,7 +851,7 @@ public class IActivityManagerProxy extends ClassInvocationStub {
return false;
}
- // for < Android 10
+
@ProxyMethod("setTaskDescription")
public static class SetTaskDescription extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityTaskManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityTaskManagerProxy.java
index b0fcc81..27f3fc7 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityTaskManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IActivityTaskManagerProxy.java
@@ -14,14 +14,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.fake.hook.ScanClass;
import top.niunaijun.blackbox.utils.compat.TaskDescriptionCompat;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@ScanClass(ActivityManagerCommonProxy.class)
public class IActivityTaskManagerProxy extends BinderInvocationStub {
public static final String TAG = "ActivityTaskManager";
@@ -48,7 +41,7 @@ public class IActivityTaskManagerProxy extends BinderInvocationStub {
return false;
}
- // for >= Android 10 && < Android 12
+
@ProxyMethod("setTaskDescription")
public static class SetTaskDescription extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAlarmManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAlarmManagerProxy.java
index c279ea9..b822735 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAlarmManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAlarmManagerProxy.java
@@ -10,14 +10,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/3/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IAlarmManagerProxy extends BinderInvocationStub {
public IAlarmManagerProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppOpsManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppOpsManagerProxy.java
index 9124e5a..5f56c4f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppOpsManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppOpsManagerProxy.java
@@ -16,14 +16,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IAppOpsManagerProxy extends BinderInvocationStub {
public IAppOpsManagerProxy() {
super(BRServiceManager.get().getService(Context.APP_OPS_SERVICE));
@@ -52,8 +45,8 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
- // For all check, note, and start operations, return MODE_ALLOWED directly
- // without calling the system to avoid UID mismatch errors
+
+
if (methodName.startsWith("check") ||
methodName.startsWith("note") ||
methodName.startsWith("start")) {
@@ -61,24 +54,24 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
return AppOpsManager.MODE_ALLOWED;
}
- // For finish operations, just return null without calling system
+
if (methodName.startsWith("finish")) {
Slog.d(TAG, "AppOps invoke: Bypassing system for " + methodName);
return null;
}
- // For other operations, try to call system with error handling
+
try {
MethodParameterUtils.replaceFirstAppPkg(args);
MethodParameterUtils.replaceLastUid(args);
return super.invoke(proxy, method, args);
} catch (SecurityException e) {
- // Handle SecurityException for UID/package mismatches
+
Slog.w(TAG, "AppOps invoke: SecurityException caught for " + methodName + ", allowing operation", e);
return AppOpsManager.MODE_ALLOWED;
} catch (Exception e) {
Slog.e(TAG, "AppOps invoke: Error in method " + methodName, e);
- // Return MODE_ALLOWED as fallback to prevent crashes
+
return AppOpsManager.MODE_ALLOWED;
}
}
@@ -100,7 +93,7 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
public static class CheckPackage extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // todo
+
return AppOpsManager.MODE_ALLOWED;
}
}
@@ -109,19 +102,19 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
public static class CheckOperation extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always return MODE_ALLOWED to bypass UID mismatch errors
- // The system's checkOperation causes SecurityException when package/uid don't match
+
+
Slog.d(TAG, "AppOps CheckOperation: Bypassing system check, allowing operation");
return AppOpsManager.MODE_ALLOWED;
}
}
- // Hook for checkOperationForDevice - this is called on Android 12+ and shown in stack trace
+
@ProxyMethod("checkOperationForDevice")
public static class CheckOperationForDevice extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always return MODE_ALLOWED to bypass UID mismatch errors
+
Slog.d(TAG, "AppOps CheckOperationForDevice: Bypassing system check, allowing operation");
return AppOpsManager.MODE_ALLOWED;
}
@@ -131,7 +124,7 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
public static class NoteOperation extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always return MODE_ALLOWED to bypass UID mismatch errors
+
Slog.d(TAG, "AppOps NoteOperation: Bypassing system check, allowing operation");
return AppOpsManager.MODE_ALLOWED;
}
@@ -141,18 +134,18 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
public static class CheckOpNoThrow extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always return MODE_ALLOWED to bypass UID mismatch errors
+
Slog.d(TAG, "AppOps CheckOpNoThrow: Bypassing system check, allowing operation");
return AppOpsManager.MODE_ALLOWED;
}
}
- // Android 12+: startOp/startOpNoThrow gate long-running operations like recording
+
@ProxyMethod("startOp")
public static class StartOp extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always return MODE_ALLOWED to bypass UID mismatch errors
+
Slog.d(TAG, "AppOps StartOp: Bypassing system check, allowing operation");
return AppOpsManager.MODE_ALLOWED;
}
@@ -162,13 +155,13 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
public static class StartOpNoThrow extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always return MODE_ALLOWED to bypass UID mismatch errors
+
Slog.d(TAG, "AppOps StartOpNoThrow: Bypassing system check, allowing operation");
return AppOpsManager.MODE_ALLOWED;
}
}
- // No-op finish so recording sessions don't error out
+
@ProxyMethod("finishOp")
public static class FinishOp extends MethodHook {
@Override
@@ -185,7 +178,7 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
}
}
- // Specific handler for RECORD_AUDIO operations
+
@ProxyMethod("noteOp")
public static class NoteOp extends MethodHook {
@Override
@@ -203,7 +196,7 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
}
}
- // Specific handler for RECORD_AUDIO operations with package name
+
@ProxyMethod("noteOpNoThrow")
public static class NoteOpNoThrow extends MethodHook {
@Override
@@ -223,7 +216,7 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
private static boolean isMediaStorageOrAudioOp(String opPublicNameOrStr) {
if (opPublicNameOrStr == null) return false;
- // Accept both public names and OPSTR strings
+
String n = opPublicNameOrStr.toUpperCase();
return n.contains("READ_MEDIA")
|| n.contains("READ_EXTERNAL_STORAGE")
@@ -248,7 +241,7 @@ public class IAppOpsManagerProxy extends BinderInvocationStub {
private static String getOpPublicName(int op) {
try {
- // AppOpsManager.opToPublicName was added in API 29
+
java.lang.reflect.Method m = AppOpsManager.class.getMethod("opToPublicName", int.class);
Object name = m.invoke(null, op);
return name != null ? name.toString() : null;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppWidgetManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppWidgetManagerProxy.java
index f64b9f0..0da1b20 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppWidgetManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAppWidgetManagerProxy.java
@@ -10,14 +10,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.service.base.ValueMethodProxy;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 4/5/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IAppWidgetManagerProxy extends BinderInvocationStub {
public IAppWidgetManagerProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAttributionSourceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAttributionSourceProxy.java
index 4c3d014..2a9deae 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAttributionSourceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAttributionSourceProxy.java
@@ -12,10 +12,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * AttributionSource Proxy to handle UID mismatch issues on Android 12+
- * This prevents crashes related to AttributionSource UID enforcement
- */
+
public class IAttributionSourceProxy extends ClassInvocationStub {
public static final String TAG = "IAttributionSourceProxy";
@@ -25,13 +22,13 @@ public class IAttributionSourceProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return null since this is a global hook, not a specific service
+
return null;
}
@Override
protected void inject(Object base, Object proxy) {
- // This proxy handles AttributionSource creation globally
+
Slog.d(TAG, "AttributionSource proxy initialized for UID mismatch prevention");
}
@@ -40,25 +37,25 @@ public class IAttributionSourceProxy extends ClassInvocationStub {
return false;
}
- // Hook for AttributionSource constructor to fix UID issues
+
@ProxyMethod("AttributionSource")
public static class AttributionSourceConstructor extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Always create AttributionSource with correct UID to prevent crashes
+
int uid = BlackBoxCore.getHostUid();
String packageName = BlackBoxCore.getHostPkg();
Slog.d(TAG, "Creating AttributionSource with UID: " + uid + ", package: " + packageName);
- // Create AttributionSource with proper UID
+
Object attributionSource = createSafeAttributionSource(uid, packageName);
if (attributionSource != null) {
return attributionSource;
}
- // Fallback to original method if creation fails
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error creating AttributionSource, using fallback: " + e.getMessage());
@@ -68,20 +65,20 @@ public class IAttributionSourceProxy extends ClassInvocationStub {
private Object createSafeAttributionSource(int uid, String packageName) {
try {
- // Use reflection to create AttributionSource with correct parameters
+
Class> attributionSourceClass = Class.forName("android.content.AttributionSource");
- // Try different constructor signatures
+
Constructor> constructor = null;
try {
- // Try constructor with uid, packageName, attributionTag
+
constructor = attributionSourceClass.getDeclaredConstructor(int.class, String.class, String.class);
} catch (NoSuchMethodException e) {
try {
- // Try constructor with uid, packageName
+
constructor = attributionSourceClass.getDeclaredConstructor(int.class, String.class);
} catch (NoSuchMethodException e2) {
- // Try default constructor
+
constructor = attributionSourceClass.getDeclaredConstructor();
}
}
@@ -106,15 +103,15 @@ public class IAttributionSourceProxy extends ClassInvocationStub {
}
}
- // Hook for AttributionSource.enforceCallingUid to prevent UID mismatch crashes
+
@ProxyMethod("enforceCallingUid")
public static class EnforceCallingUid extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Always allow the call to proceed to prevent UID mismatch crashes
+
Slog.d(TAG, "Intercepting enforceCallingUid to prevent UID mismatch crashes");
- return null; // Return null to indicate success
+ return null;
} catch (Exception e) {
Slog.w(TAG, "Error in enforceCallingUid hook: " + e.getMessage());
return null;
@@ -122,15 +119,15 @@ public class IAttributionSourceProxy extends ClassInvocationStub {
}
}
- // Hook for AttributionSource.enforceCallingUidAndPid to prevent UID mismatch crashes
+
@ProxyMethod("enforceCallingUidAndPid")
public static class EnforceCallingUidAndPid extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Always allow the call to proceed to prevent UID mismatch crashes
+
Slog.d(TAG, "Intercepting enforceCallingUidAndPid to prevent UID mismatch crashes");
- return null; // Return null to indicate success
+ return null;
} catch (Exception e) {
Slog.w(TAG, "Error in enforceCallingUidAndPid hook: " + e.getMessage());
return null;
@@ -138,21 +135,21 @@ public class IAttributionSourceProxy extends ClassInvocationStub {
}
}
- // Hook for AttributionSource.fromParcel to handle Parcel creation
+
@ProxyMethod("fromParcel")
public static class FromParcel extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Fix the UID in the created AttributionSource
+
fixAttributionSourceUid(result);
return result;
}
- // If original method fails, create a safe fallback
+
return createSafeAttributionSource(BlackBoxCore.getHostUid(), BlackBoxCore.getHostPkg());
} catch (Exception e) {
Slog.w(TAG, "Error in fromParcel, using fallback: " + e.getMessage());
@@ -162,7 +159,7 @@ public class IAttributionSourceProxy extends ClassInvocationStub {
private void fixAttributionSourceUid(Object attributionSource) {
try {
- // Use reflection to fix the UID
+
Class> attributionSourceClass = attributionSource.getClass();
Method setUidMethod = attributionSourceClass.getDeclaredMethod("setUid", int.class);
setUidMethod.setAccessible(true);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAudioServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAudioServiceProxy.java
index 130dcb3..ddebd8c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAudioServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAudioServiceProxy.java
@@ -14,9 +14,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Reflector;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Audio service proxy to avoid focus/mute related issues in virtualized apps.
- */
+
public class IAudioServiceProxy extends BinderInvocationStub {
public static final String TAG = "AudioServiceProxy";
@@ -33,22 +31,22 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
try {
- // Try multiple reflection paths for different Android versions
+
Object iface = null;
- // Android 16+ path
+
try {
iface = Reflector.on("android.media.IAudioService$Stub").call("asInterface", binder);
} catch (Exception e1) {
Slog.d(TAG, "Failed Android 16+ path, trying alternative: " + e1.getMessage());
- // Alternative path for older versions
+
try {
iface = Reflector.on("android.media.IAudioService").call("asInterface", binder);
} catch (Exception e2) {
Slog.d(TAG, "Failed alternative path: " + e2.getMessage());
- // Last resort: try direct interface casting
+
try {
Class> stubClass = Class.forName("android.media.IAudioService$Stub");
Method asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class);
@@ -84,7 +82,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
return false;
}
- // Always allow microphone to be unmuted in the virtual app
+
@ProxyMethod("isMicrophoneMuted")
public static class IsMicrophoneMuted extends MethodHook {
@Override
@@ -94,21 +92,21 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Ignore attempts to force microphone mute via AudioService
+
@ProxyMethod("setMicrophoneMute")
public static class SetMicrophoneMute extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "AudioService: setMicrophoneMute called, forcing unmute");
- // Force microphone to be unmuted
+
if (args != null && args.length > 0) {
- args[0] = false; // Force unmute
+ args[0] = false;
}
return method.invoke(who, args);
}
}
- // Allow audio recording operations
+
@ProxyMethod("startRecording")
public static class StartRecording extends MethodHook {
@Override
@@ -118,7 +116,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow audio recording operations
+
@ProxyMethod("stopRecording")
public static class StopRecording extends MethodHook {
@Override
@@ -128,7 +126,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow audio recording operations
+
@ProxyMethod("isRecordingActive")
public static class IsRecordingActive extends MethodHook {
@Override
@@ -138,7 +136,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow audio recording operations
+
@ProxyMethod("getRecordingState")
public static class GetRecordingState extends MethodHook {
@Override
@@ -148,7 +146,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow microphone access
+
@ProxyMethod("isMicrophoneMutedForUser")
public static class IsMicrophoneMutedForUser extends MethodHook {
@Override
@@ -158,21 +156,21 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow microphone access
+
@ProxyMethod("setMicrophoneMuteForUser")
public static class SetMicrophoneMuteForUser extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "AudioService: setMicrophoneMuteForUser called, forcing unmute");
- // Force microphone to be unmuted
+
if (args != null && args.length > 1) {
- args[1] = false; // Force unmute
+ args[1] = false;
}
return method.invoke(who, args);
}
}
- // Allow audio recording state queries
+
@ProxyMethod("getRecordingStateForUser")
public static class GetRecordingStateForUser extends MethodHook {
@Override
@@ -182,7 +180,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow audio focus requests
+
@ProxyMethod("requestAudioFocus")
public static class RequestAudioFocus extends MethodHook {
@Override
@@ -192,7 +190,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow audio focus client registration
+
@ProxyMethod("registerAudioFocusClient")
public static class RegisterAudioFocusClient extends MethodHook {
@Override
@@ -202,7 +200,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow audio focus client unregistration
+
@ProxyMethod("unregisterAudioFocusClient")
public static class UnregisterAudioFocusClient extends MethodHook {
@Override
@@ -212,7 +210,7 @@ public class IAudioServiceProxy extends BinderInvocationStub {
}
}
- // Allow audio focus abandonment
+
@ProxyMethod("abandonAudioFocus")
public static class AbandonAudioFocus extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAutofillManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAutofillManagerProxy.java
index 829e959..f2ebaca 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAutofillManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IAutofillManagerProxy.java
@@ -13,14 +13,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.proxy.ProxyManifest;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IAutofillManagerProxy extends BinderInvocationStub {
public static final String TAG = "AutofillManagerStub";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IConnectivityManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IConnectivityManagerProxy.java
index bff2cd3..1a0c97f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IConnectivityManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IConnectivityManagerProxy.java
@@ -21,14 +21,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 4/12/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@ScanClass(VpnCommonProxy.class)
public class IConnectivityManagerProxy extends BinderInvocationStub {
public static final String TAG = "IConnectivityManagerProxy";
@@ -52,18 +45,16 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
return false;
}
- /**
- * Universal method to create NetworkInfo objects that works on all API levels
- */
+
private static Object createNetworkInfo(int type, int subType, String typeName, String subTypeName) {
try {
if (android.os.Build.VERSION.SDK_INT >= 30) {
- // On API 30+, use the constructor directly
+
NetworkInfo networkInfo = new NetworkInfo(type, subType, typeName, subTypeName);
networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
return networkInfo;
} else {
- // On older API levels, use reflection
+
try {
Class> networkInfoClass = Class.forName("android.net.NetworkInfo");
Constructor> constructor = networkInfoClass.getDeclaredConstructor(int.class, int.class, String.class, String.class);
@@ -71,7 +62,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
Object networkInfo = constructor.newInstance(type, subType, typeName, subTypeName);
- // Set the detailed state using reflection
+
Method setDetailedStateMethod = networkInfoClass.getDeclaredMethod("setDetailedState",
NetworkInfo.DetailedState.class, String.class, String.class);
setDetailedStateMethod.invoke(networkInfo, NetworkInfo.DetailedState.CONNECTED, null, null);
@@ -88,36 +79,34 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- /**
- * Universal method to create NetworkInfo array that works on all API levels
- */
+
private static Object createNetworkInfoArray() {
try {
if (android.os.Build.VERSION.SDK_INT >= 30) {
- // On API 30+, use the constructor directly
+
NetworkInfo wifi = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
wifi.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
NetworkInfo mobile = new NetworkInfo(ConnectivityManager.TYPE_MOBILE, 0, "MOBILE", "");
mobile.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
return new NetworkInfo[] { wifi, mobile };
} else {
- // On older API levels, use reflection to create NetworkInfo array
+
try {
Class> networkInfoClass = Class.forName("android.net.NetworkInfo");
Constructor> constructor = networkInfoClass.getDeclaredConstructor(int.class, int.class, String.class, String.class);
constructor.setAccessible(true);
- // Create WiFi NetworkInfo
+
Object wifi = constructor.newInstance(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
Method setDetailedStateMethod = networkInfoClass.getDeclaredMethod("setDetailedState",
NetworkInfo.DetailedState.class, String.class, String.class);
setDetailedStateMethod.invoke(wifi, NetworkInfo.DetailedState.CONNECTED, null, null);
- // Create Mobile NetworkInfo
+
Object mobile = constructor.newInstance(ConnectivityManager.TYPE_MOBILE, 0, "MOBILE", "");
setDetailedStateMethod.invoke(mobile, NetworkInfo.DetailedState.CONNECTED, null, null);
- // Create array using reflection
+
Object[] networkInfoArray = (Object[]) java.lang.reflect.Array.newInstance(networkInfoClass, 2);
java.lang.reflect.Array.set(networkInfoArray, 0, wifi);
java.lang.reflect.Array.set(networkInfoArray, 1, mobile);
@@ -134,18 +123,16 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- /**
- * Create NetworkCapabilities using reflection for all API levels (21+)
- */
+
private static Object createNetworkCapabilities() {
try {
- // Use reflection for constructor to ensure compatibility across all API levels
+
Class> networkCapabilitiesClass = Class.forName("android.net.NetworkCapabilities");
Constructor> constructor = networkCapabilitiesClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object nc = constructor.newInstance();
- // Add transport types using reflection to ensure compatibility
+
try {
Method addTransportTypeMethod = nc.getClass().getMethod("addTransportType", int.class);
addTransportTypeMethod.invoke(nc, android.net.NetworkCapabilities.TRANSPORT_WIFI);
@@ -154,7 +141,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
Slog.w(TAG, "Could not add transport types: " + e.getMessage());
}
- // Add essential capabilities using reflection to ensure compatibility
+
try {
Method addCapabilityMethod = nc.getClass().getMethod("addCapability", int.class);
addCapabilityMethod.invoke(nc, android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET);
@@ -174,24 +161,22 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- /**
- * Create LinkProperties using reflection for all API levels (21+)
- */
+
private static Object createLinkProperties() {
try {
- // Use reflection for constructor to ensure compatibility across all API levels
+
Class> linkPropertiesClass = Class.forName("android.net.LinkProperties");
Constructor> constructor = linkPropertiesClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object linkProperties = constructor.newInstance();
- // Add DNS servers (Google DNS as fallback)
+
java.util.List dnsServers = new java.util.ArrayList<>();
try {
dnsServers.add(java.net.InetAddress.getByName("8.8.8.8"));
dnsServers.add(java.net.InetAddress.getByName("8.8.4.4"));
- // Set DNS servers using reflection to ensure compatibility
+
Method setDnsServersMethod = linkProperties.getClass().getMethod("setDnsServers", java.util.List.class);
setDnsServersMethod.invoke(linkProperties, dnsServers);
} catch (Exception e) {
@@ -212,13 +197,13 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for getNetworkInfo");
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
@@ -230,7 +215,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo: " + e.getMessage());
@@ -244,13 +229,13 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create basic NetworkInfo array
+
Slog.d(TAG, "Creating fallback NetworkInfo array for getAllNetworkInfo");
return createNetworkInfoArray();
@@ -262,7 +247,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createNetworkInfoArray() {
try {
- // Use the universal NetworkInfo array creation method
+
return IConnectivityManagerProxy.createNetworkInfoArray();
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo array: " + e.getMessage());
@@ -271,34 +256,34 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getAllNetworks - critical for modern apps to list networks
+
@ProxyMethod("getAllNetworks")
public static class GetAllNetworks extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Try original
+
Object result = method.invoke(who, args);
if (result != null) {
- // Check if array is empty
+
if (Array.getLength(result) > 0) {
return result;
}
}
} catch (Exception e) {
- // Ignore
+
}
Slog.d(TAG, "Creating fallback Network[] for getAllNetworks");
- // Try to align with GetActiveNetwork to ensure consistency
+
try {
- // Finds the getActiveNetwork method on the proxy to call it properly
+
Method getActiveNetworkMethod = null;
try {
getActiveNetworkMethod = who.getClass().getMethod("getActiveNetwork");
} catch (NoSuchMethodException e) {
- // Try searching by name if exact match fails
+
for (Method m : who.getClass().getMethods()) {
if (m.getName().equals("getActiveNetwork")) {
getActiveNetworkMethod = m;
@@ -321,13 +306,13 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
Slog.w(TAG, "Failed to use Active Network for fallback: " + e.getMessage());
}
- // Create array with 1 fake network as last resort
+
try {
Class> networkClass = Class.forName("android.net.Network");
Object networkArray = Array.newInstance(networkClass, 1);
- // Create fake network (Network(1))
- // Note: Network(int) is hidden, but accessible via reflection
+
+
Constructor> constructor = networkClass.getConstructor(int.class);
Object network = constructor.newInstance(1);
@@ -340,32 +325,32 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Enhanced hook for getNetworkCapabilities for API 21+
+
@ProxyMethod("getNetworkCapabilities")
public static class GetNetworkCapabilities extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
if (android.os.Build.VERSION.SDK_INT >= 21) {
try {
- // Try to get real capabilities first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Force add capabilities to the real result to ensure app thinks it has internet
+
try {
Method addCapabilityMethod = result.getClass().getMethod("addCapability", int.class);
addCapabilityMethod.setAccessible(true);
- addCapabilityMethod.invoke(result, 12); // NET_CAPABILITY_INTERNET
- addCapabilityMethod.invoke(result, 16); // NET_CAPABILITY_VALIDATED
+ addCapabilityMethod.invoke(result, 12);
+ addCapabilityMethod.invoke(result, 16);
} catch (Exception e) {
- // Ignore if method not found (e.g. immutable on some versions)
+
e.printStackTrace();
}
return result;
}
- // Create NetworkCapabilities using API-specific methods
+
Object nc;
- // Use the universal NetworkCapabilities creation method for all API levels
+
nc = IConnectivityManagerProxy.createNetworkCapabilities();
if (nc != null) {
@@ -380,34 +365,34 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getActiveNetwork to ensure proper network binding
+
@ProxyMethod("getActiveNetwork")
public static class GetActiveNetwork extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
if (android.os.Build.VERSION.SDK_INT >= 21) {
try {
- // Try to get real active network first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // Create a mock Network object to ensure proper binding
- // Use reflection to handle different constructor signatures
+
+
android.net.Network network;
try {
- // Try constructor with int parameter first
+
Constructor constructor = android.net.Network.class.getConstructor(int.class);
network = constructor.newInstance(1);
} catch (Exception e) {
- // Try to access the default constructor via reflection
+
try {
Constructor defaultConstructor = android.net.Network.class.getDeclaredConstructor();
defaultConstructor.setAccessible(true);
network = defaultConstructor.newInstance();
} catch (Exception e2) {
- // If all else fails, return null and let the original method handle it
+
Slog.w(TAG, "Could not create Network object, falling back to original method");
return method.invoke(who, args);
}
@@ -422,7 +407,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getActiveNetworkInfo - critical for legacy internet checks
+
@ProxyMethod("getActiveNetworkInfo")
public static class GetActiveNetworkInfo extends MethodHook {
@Override
@@ -430,39 +415,39 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
try {
Object result = method.invoke(who, args);
if (result != null) {
- // Force CONNECTED state
+
try {
Method setDetailedState = result.getClass().getMethod("setDetailedState",
android.net.NetworkInfo.DetailedState.class, String.class, String.class);
setDetailedState.setAccessible(true);
setDetailedState.invoke(result, android.net.NetworkInfo.DetailedState.CONNECTED, null, null);
} catch (Exception e) {
- // Ignore
+
}
return result;
}
} catch (Exception e) {
- // Ignore
+
}
Slog.d(TAG, "Creating fallback NetworkInfo for getActiveNetworkInfo");
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
}
}
- // Hook for getLinkProperties to handle DNS configuration
+
@ProxyMethod("getLinkProperties")
public static class GetLinkProperties extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
if (android.os.Build.VERSION.SDK_INT >= 21) {
try {
- // Try to get real link properties first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // Create LinkProperties using the universal method for all API levels
+
Object linkProperties = IConnectivityManagerProxy.createLinkProperties();
if (linkProperties != null) {
@@ -477,35 +462,35 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getPrivateDnsServerName to disable private DNS
+
@ProxyMethod("getPrivateDnsServerName")
public static class GetPrivateDnsServerName extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Return null to disable private DNS and use system DNS
+
Slog.d(TAG, "Disabling private DNS for sandboxed app");
return null;
}
}
- // Hook for isPrivateDnsActive to ensure private DNS is not active
+
@ProxyMethod("isPrivateDnsActive")
public static class IsPrivateDnsActive extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Return false to indicate private DNS is not active
+
Slog.d(TAG, "Private DNS disabled for sandboxed app");
return false;
}
}
- // Hook for getDnsServers to ensure proper DNS resolution
+
@ProxyMethod("getDnsServers")
public static class GetDnsServers extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Return system DNS servers instead of custom ones
+
java.util.List dnsServers = new java.util.ArrayList<>();
dnsServers.add(java.net.InetAddress.getByName("8.8.8.8"));
dnsServers.add(java.net.InetAddress.getByName("8.8.4.4"));
@@ -518,32 +503,32 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for isNetworkValidated to ensure network validation
+
@ProxyMethod("isNetworkValidated")
public static class IsNetworkValidated extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Return true to indicate network is validated
+
Slog.d(TAG, "Network validation enabled for sandboxed app");
return true;
}
}
- // Hook for requestNetwork - critical for internet access
+
@ProxyMethod("requestNetwork")
public static class RequestNetwork extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting requestNetwork call for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "requestNetwork succeeded via original method");
return result;
}
- // If original method fails, create a mock network request result
+
Slog.w(TAG, "requestNetwork failed, creating fallback result");
return createMockNetworkRequestResult();
@@ -555,14 +540,14 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createMockNetworkRequestResult() {
try {
- // Create a mock network request result
- // This is critical for apps that need to request network access
+
+
if (android.os.Build.VERSION.SDK_INT >= 21) {
- // For API 21+, try to create a NetworkRequest object
+
Class> networkRequestClass = Class.forName("android.net.NetworkRequest");
if (networkRequestClass != null) {
Slog.d(TAG, "Created fallback NetworkRequest for internet access");
- return null; // Return null to indicate no specific network request
+ return null;
}
}
} catch (Exception e) {
@@ -572,67 +557,67 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for registerNetworkCallback - also critical for internet access
+
@ProxyMethod("registerNetworkCallback")
public static class RegisterNetworkCallback extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting registerNetworkCallback for internet access");
try {
- // Allow the network callback registration to proceed
+
Object result = method.invoke(who, args);
Slog.d(TAG, "Network callback registration successful");
return result;
} catch (Exception e) {
Slog.w(TAG, "Network callback registration failed: " + e.getMessage());
- // Return a success indicator even if it fails
+
return 0;
}
}
}
- // Hook for registerDefaultNetworkCallback - critical for internet access
+
@ProxyMethod("registerDefaultNetworkCallback")
public static class RegisterDefaultNetworkCallback extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting registerDefaultNetworkCallback for internet access");
try {
- // Allow the default network callback registration to proceed
+
Object result = method.invoke(who, args);
Slog.d(TAG, "Default network callback registration successful");
return result;
} catch (Exception e) {
Slog.w(TAG, "Default network callback registration failed: " + e.getMessage());
- // Return a success indicator even if it fails
+
return 0;
}
}
}
- // Hook for getActiveNetworkInfoForUid - important for per-app network access
+
@ProxyMethod("getActiveNetworkInfoForUid")
public static class GetActiveNetworkInfoForUid extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getActiveNetworkInfoForUid for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Force CONNECTED state
+
try {
Method setDetailedState = result.getClass().getMethod("setDetailedState",
android.net.NetworkInfo.DetailedState.class, String.class, String.class);
setDetailedState.setAccessible(true);
setDetailedState.invoke(result, android.net.NetworkInfo.DetailedState.CONNECTED, null, null);
} catch (Exception e) {
- // Ignore
+
}
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for UID");
return createBasicNetworkInfo();
@@ -644,7 +629,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for UID: " + e.getMessage());
@@ -653,58 +638,58 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for addDefaultNetworkActiveListener - critical for network state changes
+
@ProxyMethod("addDefaultNetworkActiveListener")
public static class AddDefaultNetworkActiveListener extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting addDefaultNetworkActiveListener for internet access");
try {
- // Allow the network active listener to proceed
+
Object result = method.invoke(who, args);
Slog.d(TAG, "Default network active listener added successfully");
return result;
} catch (Exception e) {
Slog.w(TAG, "Default network active listener failed: " + e.getMessage());
- // Return a success indicator even if it fails
+
return 0;
}
}
}
- // Hook for removeDefaultNetworkActiveListener - also important
+
@ProxyMethod("removeDefaultNetworkActiveListener")
public static class RemoveDefaultNetworkActiveListener extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting removeDefaultNetworkActiveListener for internet access");
try {
- // Allow the network active listener removal to proceed
+
Object result = method.invoke(who, args);
Slog.d(TAG, "Default network active listener removed successfully");
return result;
} catch (Exception e) {
Slog.w(TAG, "Default network active listener removal failed: " + e.getMessage());
- // Return a success indicator even if it fails
+
return 0;
}
}
}
- // Hook for isActiveNetworkMetered - important for network behavior
+
@ProxyMethod("isActiveNetworkMetered")
public static class IsActiveNetworkMetered extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting isActiveNetworkMetered for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, return false (unmetered) to allow full access
+
Slog.d(TAG, "isActiveNetworkMetered failed, returning false for full access");
return false;
@@ -715,36 +700,36 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkForType - important for specific network type access
+
@ProxyMethod("getNetworkForType")
public static class GetNetworkForType extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkForType for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a mock Network object
+
if (android.os.Build.VERSION.SDK_INT >= 21) {
try {
- // Use reflection to handle different constructor signatures
+
android.net.Network network;
try {
- // Try constructor with int parameter first
+
Constructor constructor = android.net.Network.class.getConstructor(int.class);
network = constructor.newInstance(1);
} catch (Exception e) {
- // Try to access the default constructor via reflection
+
try {
Constructor defaultConstructor = android.net.Network.class.getDeclaredConstructor();
defaultConstructor.setAccessible(true);
network = defaultConstructor.newInstance();
} catch (Exception e2) {
- // If all else fails, return null
+
Slog.w(TAG, "Could not create Network object, returning null");
return null;
}
@@ -765,67 +750,67 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for registerNetworkCallback with NetworkRequest - critical for internet access
+
@ProxyMethod("registerNetworkCallback")
public static class RegisterNetworkCallbackWithRequest extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting registerNetworkCallback with NetworkRequest for internet access");
try {
- // Allow the network callback registration to proceed
+
Object result = method.invoke(who, args);
Slog.d(TAG, "Network callback registration with request successful");
return result;
} catch (Exception e) {
Slog.w(TAG, "Network callback registration with request failed: " + e.getMessage());
- // Return a success indicator even if it fails
+
return 0;
}
}
}
- // Hook for unregisterNetworkCallback - also important
+
@ProxyMethod("unregisterNetworkCallback")
public static class UnregisterNetworkCallback extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting unregisterNetworkCallback for internet access");
try {
- // Allow the network callback unregistration to proceed
+
Object result = method.invoke(who, args);
Slog.d(TAG, "Network callback unregistration successful");
return result;
} catch (Exception e) {
Slog.w(TAG, "Network callback unregistration failed: " + e.getMessage());
- // Return a success indicator even if it fails
+
return 0;
}
}
}
- // Hook for getNetworkInfo with Network parameter - important for modern apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithNetwork extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with Network parameter for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Force CONNECTED state
+
try {
Method setDetailedState = result.getClass().getMethod("setDetailedState",
android.net.NetworkInfo.DetailedState.class, String.class, String.class);
setDetailedState.setAccessible(true);
setDetailedState.invoke(result, android.net.NetworkInfo.DetailedState.CONNECTED, null, null);
} catch (Exception e) {
- // Ignore
+
}
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for Network parameter");
return createBasicNetworkInfo();
@@ -837,7 +822,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for Network: " + e.getMessage());
@@ -846,29 +831,29 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with int parameter - also important
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithInt extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with int parameter for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
- // Force CONNECTED state
+
try {
Method setDetailedState = result.getClass().getMethod("setDetailedState",
android.net.NetworkInfo.DetailedState.class, String.class, String.class);
setDetailedState.setAccessible(true);
setDetailedState.invoke(result, android.net.NetworkInfo.DetailedState.CONNECTED, null, null);
} catch (Exception e) {
- // Ignore
+
}
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for int parameter");
return createBasicNetworkInfo();
@@ -880,7 +865,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for int: " + e.getMessage());
@@ -889,20 +874,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter");
return createBasicNetworkInfo();
@@ -914,7 +899,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String: " + e.getMessage());
@@ -923,20 +908,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString2 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (2) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (2)");
return createBasicNetworkInfo();
@@ -948,7 +933,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (2): " + e.getMessage());
@@ -957,20 +942,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString3 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (3) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (3)");
return createBasicNetworkInfo();
@@ -982,7 +967,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (3): " + e.getMessage());
@@ -991,20 +976,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString4 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (4) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (4)");
return createBasicNetworkInfo();
@@ -1016,7 +1001,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (4): " + e.getMessage());
@@ -1025,20 +1010,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString5 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (5) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (5)");
return createBasicNetworkInfo();
@@ -1050,7 +1035,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (5): " + e.getMessage());
@@ -1059,20 +1044,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString6 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (6) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (6)");
return createBasicNetworkInfo();
@@ -1084,7 +1069,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (6): " + e.getMessage());
@@ -1093,20 +1078,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString7 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (7) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (7)");
return createBasicNetworkInfo();
@@ -1118,7 +1103,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (7): " + e.getMessage());
@@ -1127,20 +1112,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString8 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (8) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (8)");
return createBasicNetworkInfo();
@@ -1152,7 +1137,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (8): " + e.getMessage());
@@ -1161,20 +1146,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString9 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (9) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (9)");
return createBasicNetworkInfo();
@@ -1186,7 +1171,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (9): " + e.getMessage());
@@ -1195,20 +1180,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString10 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (10) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (10)");
return createBasicNetworkInfo();
@@ -1220,7 +1205,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (10): " + e.getMessage());
@@ -1229,20 +1214,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString11 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (11) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (11)");
return createBasicNetworkInfo();
@@ -1254,7 +1239,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (11): " + e.getMessage());
@@ -1263,20 +1248,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString12 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (12) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (12)");
return createBasicNetworkInfo();
@@ -1288,7 +1273,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (12): " + e.getMessage());
@@ -1297,20 +1282,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString13 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (13) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (13)");
return createBasicNetworkInfo();
@@ -1322,7 +1307,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (13): " + e.getMessage());
@@ -1331,20 +1316,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString14 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (14) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (14)");
return createBasicNetworkInfo();
@@ -1356,7 +1341,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (14): " + e.getMessage());
@@ -1365,20 +1350,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString15 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (15) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (15)");
return createBasicNetworkInfo();
@@ -1390,7 +1375,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (15): " + e.getMessage());
@@ -1399,20 +1384,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString16 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (16) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (16)");
return createBasicNetworkInfo();
@@ -1424,7 +1409,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (16): " + e.getMessage());
@@ -1433,20 +1418,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString17 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (17) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (17)");
return createBasicNetworkInfo();
@@ -1458,7 +1443,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (17): " + e.getMessage());
@@ -1467,20 +1452,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString18 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (18) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (18)");
return createBasicNetworkInfo();
@@ -1492,7 +1477,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (18): " + e.getMessage());
@@ -1501,20 +1486,20 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
}
}
- // Hook for getNetworkInfo with String parameter - important for older apps
+
@ProxyMethod("getNetworkInfo")
public static class GetNetworkInfoWithString19 extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting getNetworkInfo with String parameter (19) for internet access");
try {
- // Try to use the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, create a basic NetworkInfo
+
Slog.d(TAG, "Creating fallback NetworkInfo for String parameter (19)");
return createBasicNetworkInfo();
@@ -1526,7 +1511,7 @@ public class IConnectivityManagerProxy extends BinderInvocationStub {
private Object createBasicNetworkInfo() {
try {
- // Use the universal NetworkInfo creation method
+
return createNetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
} catch (Exception e) {
Slog.e(TAG, "Failed to create fallback NetworkInfo for String (19): " + e.getMessage());
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContentProviderProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContentProviderProxy.java
index 0e42b4b..6d69e0a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContentProviderProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContentProviderProxy.java
@@ -8,10 +8,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.AttributionSourceUtils;
-/**
- * IContentProvider Proxy to handle AttributionSource UID issues on Android 12+
- * This prevents crashes related to ContentProvider UID enforcement
- */
+
public class IContentProviderProxy extends ClassInvocationStub {
public static final String TAG = "IContentProviderProxy";
@@ -21,13 +18,13 @@ public class IContentProviderProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return null since this is a global hook, not a specific service
+
return null;
}
@Override
protected void inject(Object base, Object proxy) {
- // This proxy handles ContentProvider calls globally
+
Slog.d(TAG, "IContentProvider proxy initialized for UID mismatch prevention");
}
@@ -36,158 +33,158 @@ public class IContentProviderProxy extends ClassInvocationStub {
return false;
}
- // Hook for query method to fix AttributionSource issues
+
@ProxyMethod("query")
public static class Query extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in query hook: " + e.getMessage());
- // Return null cursor to prevent crashes
+
return null;
}
}
}
- // Hook for insert method to fix AttributionSource issues
+
@ProxyMethod("insert")
public static class Insert extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in insert hook: " + e.getMessage());
- // Return null URI to prevent crashes
+
return null;
}
}
}
- // Hook for update method to fix AttributionSource issues
+
@ProxyMethod("update")
public static class Update extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in update hook: " + e.getMessage());
- // Return 0 to prevent crashes
+
return 0;
}
}
}
- // Hook for delete method to fix AttributionSource issues
+
@ProxyMethod("delete")
public static class Delete extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in delete hook: " + e.getMessage());
- // Return 0 to prevent crashes
+
return 0;
}
}
}
- // Hook for call method to fix AttributionSource issues (used by Settings.System, etc.)
+
@ProxyMethod("call")
public static class Call extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in call method, returning safe default: " + message);
- return null; // Return null to prevent crashes
+ return null;
}
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in call hook: " + e.getMessage());
- // Return null to prevent crashes
+
return null;
}
}
}
- // Hook for getString method to fix UID issues
+
@ProxyMethod("getString")
public static class GetString extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getString, returning safe default: " + message);
- return ""; // Return empty string to prevent crashes
+ return "";
}
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in getString hook: " + e.getMessage());
- // Return empty string to prevent crashes
+
return "";
}
}
}
- // Hook for getStringForUser method to fix UID issues
+
@ProxyMethod("getStringForUser")
public static class GetStringForUser extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getStringForUser, returning safe default: " + message);
- return ""; // Return empty string to prevent crashes
+ return "";
}
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in getStringForUser hook: " + e.getMessage());
- // Return empty string to prevent crashes
+
return "";
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContextHubServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContextHubServiceProxy.java
index fd2e525..ff43f40 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContextHubServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IContextHubServiceProxy.java
@@ -7,9 +7,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.service.base.ValueMethodProxy;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Created by BlackBox on 2022/3/2.
- */
+
public class IContextHubServiceProxy extends BinderInvocationStub {
public IContextHubServiceProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDeviceIdentifiersPolicyProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDeviceIdentifiersPolicyProxy.java
index 90b757d..87bec36 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDeviceIdentifiersPolicyProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDeviceIdentifiersPolicyProxy.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Md5Utils;
-/**
- * updated by alex5402 on 4/3/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IDeviceIdentifiersPolicyProxy extends BinderInvocationStub {
public IDeviceIdentifiersPolicyProxy() {
@@ -44,8 +37,8 @@ public class IDeviceIdentifiersPolicyProxy extends BinderInvocationStub {
public static class x extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
-// args[0] = BlackBoxCore.getHostPkg();
-// return method.invoke(who, args);
+
+
return Md5Utils.md5(BlackBoxCore.getHostPkg());
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java
index 3391b49..6489560 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDevicePolicyManagerProxy.java
@@ -12,14 +12,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 2021/5/17.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IDevicePolicyManagerProxy extends BinderInvocationStub {
public IDevicePolicyManagerProxy() {
super(BRServiceManager.get().getService(Context.DEVICE_POLICY_SERVICE));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDisplayManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDisplayManagerProxy.java
index 4c2b4b2..0d7f0f3 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDisplayManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDisplayManagerProxy.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.fake.service.base.PkgMethodProxy;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 4/16/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IDisplayManagerProxy extends ClassInvocationStub {
public IDisplayManagerProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDnsResolverProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDnsResolverProxy.java
index c271956..0cc4e44 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDnsResolverProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IDnsResolverProxy.java
@@ -12,10 +12,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * DNS Resolver Service Proxy for BlackBox
- * Handles DNS resolution and prevents custom DNS interference
- */
+
public class IDnsResolverProxy extends BinderInvocationStub {
public static final String TAG = "IDnsResolverProxy";
public static final String DNS_RESOLVER_SERVICE = "dnsresolver";
@@ -26,8 +23,8 @@ public class IDnsResolverProxy extends BinderInvocationStub {
@Override
protected Object getWho() {
- // Return null to avoid complex reflection that might fail
- // The service will still be replaced by the proxy
+
+
Slog.d(TAG, "IDnsResolverProxy: Returning null for getWho to avoid reflection issues");
return null;
}
@@ -47,20 +44,20 @@ public class IDnsResolverProxy extends BinderInvocationStub {
return false;
}
- // Hook for DNS resolution to ensure proper fallback
+
@ProxyMethod("resolveDns")
public static class ResolveDns extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting DNS resolution request");
try {
- // Try to resolve using the original method first
+
Object result = method.invoke(who, args);
if (result != null) {
return result;
}
- // If original method fails, provide fallback DNS servers
+
Slog.w(TAG, "DNS resolution failed, providing fallback");
return createFallbackDnsResult();
@@ -72,7 +69,7 @@ public class IDnsResolverProxy extends BinderInvocationStub {
private Object createFallbackDnsResult() {
try {
- // Create a fallback DNS result with Google DNS
+
List fallbackServers = new ArrayList<>();
fallbackServers.add(InetAddress.getByName("8.8.8.8"));
fallbackServers.add(InetAddress.getByName("8.8.4.4"));
@@ -84,18 +81,18 @@ public class IDnsResolverProxy extends BinderInvocationStub {
}
}
- // Hook for private DNS configuration (API 28+)
+
@ProxyMethod("setPrivateDnsConfiguration")
public static class SetPrivateDnsConfiguration extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
if (Build.VERSION.SDK_INT >= 28) {
Slog.d(TAG, "Intercepting private DNS configuration");
- // Disable private DNS for sandboxed apps
+
try {
- // Try to call with disabled configuration
+
if (args != null && args.length > 0) {
- // Set private DNS to disabled
+
Slog.d(TAG, "Disabling private DNS for sandboxed app");
}
return method.invoke(who, args);
@@ -108,14 +105,14 @@ public class IDnsResolverProxy extends BinderInvocationStub {
}
}
- // Hook for DNS server configuration
+
@ProxyMethod("setDnsServersForNetwork")
public static class SetDnsServersForNetwork extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting DNS server configuration");
try {
- // Allow the call but log it
+
Object result = method.invoke(who, args);
Slog.d(TAG, "DNS server configuration applied");
return result;
@@ -126,18 +123,18 @@ public class IDnsResolverProxy extends BinderInvocationStub {
}
}
- // Hook for network validation
+
@ProxyMethod("isNetworkValidated")
public static class IsNetworkValidated extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "Intercepting network validation check");
- // Return true to indicate network is validated
+
return true;
}
}
- // Hook for DNS query timeout (API 21+)
+
@ProxyMethod("setDnsQueryTimeout")
public static class SetDnsQueryTimeout extends MethodHook {
@Override
@@ -145,9 +142,9 @@ public class IDnsResolverProxy extends BinderInvocationStub {
if (Build.VERSION.SDK_INT >= 21) {
Slog.d(TAG, "Intercepting DNS query timeout configuration");
try {
- // Set a reasonable timeout for DNS queries
+
if (args != null && args.length > 0 && args[0] instanceof Integer) {
- int timeout = Math.min((Integer) args[0], 10000); // Max 10 seconds
+ int timeout = Math.min((Integer) args[0], 10000);
Slog.d(TAG, "Setting DNS query timeout to: " + timeout + "ms");
args[0] = timeout;
}
@@ -161,7 +158,7 @@ public class IDnsResolverProxy extends BinderInvocationStub {
}
}
- // Hook for DNS resolver stats (API 23+)
+
@ProxyMethod("getDnsResolverStats")
public static class GetDnsResolverStats extends MethodHook {
@Override
@@ -169,7 +166,7 @@ public class IDnsResolverProxy extends BinderInvocationStub {
if (Build.VERSION.SDK_INT >= 23) {
Slog.d(TAG, "Intercepting DNS resolver stats request");
try {
- // Return empty stats to prevent crashes
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "DNS resolver stats failed: " + e.getMessage());
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IFingerprintManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IFingerprintManagerProxy.java
index 4bfa0eb..9c14f4f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IFingerprintManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IFingerprintManagerProxy.java
@@ -8,11 +8,7 @@ import black.android.view.BRIGraphicsStatsStub;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.service.base.PkgMethodProxy;
-/**
- * @author Findger
- * @function
- * @date :2022/4/2 22:40
- **/
+
public class IFingerprintManagerProxy extends BinderInvocationStub {
public IFingerprintManagerProxy() {
super(BRServiceManager.get().getService(Context.FINGERPRINT_SERVICE));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IGraphicsStatsProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IGraphicsStatsProxy.java
index 766f2f3..7f9f573 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IGraphicsStatsProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IGraphicsStatsProxy.java
@@ -9,14 +9,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 4/13/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IGraphicsStatsProxy extends BinderInvocationStub {
public IGraphicsStatsProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IInputMethodManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IInputMethodManagerProxy.java
index b8eb69b..0a1d7d5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IInputMethodManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IInputMethodManagerProxy.java
@@ -11,13 +11,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.fake.hook.ScanClass;
-/**
- * Created by Milk on 2021/4/26.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- */
+
@ScanClass(IInputMethodManagerProxy.class)
public class IInputMethodManagerProxy extends BinderInvocationStub {
public static final String TAG = "IInputMethodManagerProxy";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IJobServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IJobServiceProxy.java
index 4a30daf..71cc2cc 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IJobServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IJobServiceProxy.java
@@ -16,10 +16,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.UIDSpoofingHelper;
-/**
- * IJobService Proxy to handle job scheduling in sandboxed environments
- * This prevents UID mismatch crashes when scheduling background jobs
- */
+
public class IJobServiceProxy extends BinderInvocationStub {
public static final String TAG = "JobServiceStub";
@@ -43,27 +40,27 @@ public class IJobServiceProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Check if args[0] is actually a JobInfo object
+
if (args == null || args.length == 0) {
Slog.w(TAG, "Schedule: No arguments provided, returning RESULT_FAILURE");
- return 0; // RESULT_FAILURE
+ return 0;
}
if (args[0] == null) {
Slog.w(TAG, "Schedule: args[0] is null, returning RESULT_FAILURE");
- return 0; // RESULT_FAILURE
+ return 0;
}
if (!(args[0] instanceof JobInfo)) {
Slog.w(TAG, "Schedule: args[0] is not JobInfo: " + args[0].getClass().getSimpleName());
- // For non-JobInfo objects, try to handle them gracefully
+
return handleNonJobInfoSchedule(who, method, args);
}
JobInfo jobInfo = (JobInfo) args[0];
Slog.d(TAG, "Schedule: Processing JobInfo for package: " + jobInfo.getService().getPackageName());
- // Try to schedule through BlackBox job manager first
+
try {
JobInfo proxyJobInfo = BlackBoxCore.getBJobManager().schedule(jobInfo);
if (proxyJobInfo != null) {
@@ -75,39 +72,37 @@ public class IJobServiceProxy extends BinderInvocationStub {
Slog.w(TAG, "Schedule: BlackBox job manager failed, trying system fallback", e);
}
- // Fallback: Try to schedule directly with UID spoofing
+
return scheduleWithUIDSpoofing(who, method, args, jobInfo);
} catch (Exception e) {
Slog.e(TAG, "Schedule: Error processing job", e);
- // Handle specific UID validation errors
+
if (isUIDValidationError(e)) {
Slog.w(TAG, "UID validation failed for job scheduling, returning RESULT_FAILURE: " + e.getCause().getMessage());
- return 0; // RESULT_FAILURE - don't retry with same UID
+ return 0;
}
- // For other errors, try to proceed with original method call as fallback
+
try {
return method.invoke(who, args);
} catch (Exception fallbackException) {
Slog.e(TAG, "Schedule: Fallback also failed", fallbackException);
- return 0; // RESULT_FAILURE
+ return 0;
}
}
}
- /**
- * Handle non-JobInfo schedule requests (like WorkManager string IDs)
- */
+
private Object handleNonJobInfoSchedule(Object who, Method method, Object[] args) throws Throwable {
try {
- // For WorkManager string IDs, try to create a minimal JobInfo
+
if (args[0] instanceof String) {
String workId = (String) args[0];
Slog.d(TAG, "Schedule: Handling WorkManager string ID: " + workId);
- // Create a minimal JobInfo that won't cause UID validation issues
+
JobInfo minimalJobInfo = createMinimalJobInfo(workId);
if (minimalJobInfo != null) {
args[0] = minimalJobInfo;
@@ -115,34 +110,32 @@ public class IJobServiceProxy extends BinderInvocationStub {
}
}
- // Try original method for other types
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Schedule: Failed to handle non-JobInfo schedule", e);
- return 0; // RESULT_FAILURE
+ return 0;
}
}
- /**
- * Try to schedule with UID spoofing to bypass validation
- */
+
private Object scheduleWithUIDSpoofing(Object who, Method method, Object[] args, JobInfo jobInfo) throws Throwable {
try {
- // Get the target package name from the JobInfo
+
String targetPackage = jobInfo.getService().getPackageName();
Slog.d(TAG, "Schedule: Attempting UID spoofing for package: " + targetPackage);
- // Use UID spoofing helper to get the best UID for job scheduling
+
UIDSpoofingHelper.logUIDInfo("job_schedule", targetPackage);
- // Check if we need UID spoofing
+
if (UIDSpoofingHelper.needsUIDSpoofing("job_schedule", targetPackage)) {
Slog.d(TAG, "Schedule: UID spoofing needed, attempting to bypass validation");
- // For now, we'll return failure but log the attempt
- // In a full implementation, you'd need to actually spoof the UID at the system level
+
+
Slog.w(TAG, "Schedule: UID spoofing not fully implemented, returning RESULT_FAILURE");
- return 0; // RESULT_FAILURE
+ return 0;
} else {
Slog.d(TAG, "Schedule: No UID spoofing needed, proceeding normally");
return method.invoke(who, args);
@@ -150,28 +143,24 @@ public class IJobServiceProxy extends BinderInvocationStub {
} catch (Exception e) {
Slog.w(TAG, "Schedule: UID spoofing failed", e);
- return 0; // RESULT_FAILURE
+ return 0;
}
}
- /**
- * Create a minimal JobInfo for WorkManager compatibility
- */
+
private JobInfo createMinimalJobInfo(String workId) {
try {
- // This is a simplified approach - in practice, you'd need to create a proper JobInfo
- // For now, we'll return null to indicate failure
+
+
Slog.d(TAG, "Schedule: Creating minimal JobInfo for work ID: " + workId);
- return null; // Placeholder - would need proper JobInfo.Builder implementation
+ return null;
} catch (Exception e) {
Slog.w(TAG, "Schedule: Failed to create minimal JobInfo", e);
return null;
}
}
- /**
- * Check if the error is a UID validation error
- */
+
private boolean isUIDValidationError(Exception e) {
if (e.getCause() instanceof IllegalArgumentException) {
String message = e.getCause().getMessage();
@@ -227,27 +216,27 @@ public class IJobServiceProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Check if args[0] is actually a JobInfo object
+
if (args == null || args.length == 0) {
Slog.w(TAG, "Enqueue: No arguments provided, returning RESULT_FAILURE");
- return 0; // RESULT_FAILURE
+ return 0;
}
if (args[0] == null) {
Slog.w(TAG, "Enqueue: args[0] is null, returning RESULT_FAILURE");
- return 0; // RESULT_FAILURE
+ return 0;
}
if (!(args[0] instanceof JobInfo)) {
Slog.w(TAG, "Enqueue: args[0] is not JobInfo: " + args[0].getClass().getSimpleName());
- // For non-JobInfo objects, try to handle them gracefully
+
return handleNonJobInfoEnqueue(who, method, args);
}
JobInfo jobInfo = (JobInfo) args[0];
Slog.d(TAG, "Enqueue: Processing JobInfo for package: " + jobInfo.getService().getPackageName());
- // Try to enqueue through BlackBox job manager first
+
try {
JobInfo proxyJobInfo = BlackBoxCore.getBJobManager().schedule(jobInfo);
if (proxyJobInfo != null) {
@@ -259,39 +248,37 @@ public class IJobServiceProxy extends BinderInvocationStub {
Slog.w(TAG, "Enqueue: BlackBox job manager failed, trying system fallback", e);
}
- // Fallback: Try to enqueue directly with UID spoofing
+
return enqueueWithUIDSpoofing(who, method, args, jobInfo);
} catch (Exception e) {
Slog.e(TAG, "Enqueue: Error processing job", e);
- // Handle specific UID validation errors
+
if (isUIDValidationError(e)) {
Slog.w(TAG, "UID validation failed for job enqueuing, returning RESULT_FAILURE: " + e.getCause().getMessage());
- return 0; // RESULT_FAILURE - don't retry with same UID
+ return 0;
}
- // For other errors, try to proceed with original method call as fallback
+
try {
return method.invoke(who, args);
} catch (Exception fallbackException) {
Slog.e(TAG, "Enqueue: Fallback also failed", fallbackException);
- return 0; // RESULT_FAILURE
+ return 0;
}
}
}
- /**
- * Handle non-JobInfo enqueue requests (like WorkManager string IDs)
- */
+
private Object handleNonJobInfoEnqueue(Object who, Method method, Object[] args) throws Throwable {
try {
- // For WorkManager string IDs, try to create a minimal JobInfo
+
if (args[0] instanceof String) {
String workId = (String) args[0];
Slog.d(TAG, "Enqueue: Handling WorkManager string ID: " + workId);
- // Create a minimal JobInfo that won't cause UID validation issues
+
JobInfo minimalJobInfo = createMinimalJobInfo(workId);
if (minimalJobInfo != null) {
args[0] = minimalJobInfo;
@@ -299,34 +286,32 @@ public class IJobServiceProxy extends BinderInvocationStub {
}
}
- // Try original method for other types
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Enqueue: Failed to handle non-JobInfo enqueue", e);
- return 0; // RESULT_FAILURE
+ return 0;
}
}
- /**
- * Try to enqueue with UID spoofing to bypass validation
- */
+
private Object enqueueWithUIDSpoofing(Object who, Method method, Object[] args, JobInfo jobInfo) throws Throwable {
try {
- // Get the target package name from the JobInfo
+
String targetPackage = jobInfo.getService().getPackageName();
Slog.d(TAG, "Enqueue: Attempting UID spoofing for package: " + targetPackage);
- // Use UID spoofing helper to get the best UID for job scheduling
+
UIDSpoofingHelper.logUIDInfo("job_enqueue", targetPackage);
- // Check if we need UID spoofing
+
if (UIDSpoofingHelper.needsUIDSpoofing("job_enqueue", targetPackage)) {
Slog.d(TAG, "Enqueue: UID spoofing needed, attempting to bypass validation");
- // For now, we'll return failure but log the attempt
- // In a full implementation, you'd need to actually spoof the UID at the system level
+
+
Slog.w(TAG, "Enqueue: UID spoofing not fully implemented, returning RESULT_FAILURE");
- return 0; // RESULT_FAILURE
+ return 0;
} else {
Slog.d(TAG, "Enqueue: No UID spoofing needed, proceeding normally");
return method.invoke(who, args);
@@ -334,28 +319,24 @@ public class IJobServiceProxy extends BinderInvocationStub {
} catch (Exception e) {
Slog.w(TAG, "Enqueue: UID spoofing failed", e);
- return 0; // RESULT_FAILURE
+ return 0;
}
}
- /**
- * Create a minimal JobInfo for WorkManager compatibility
- */
+
private JobInfo createMinimalJobInfo(String workId) {
try {
- // This is a simplified approach - in practice, you'd need to create a proper JobInfo
- // For now, we'll return null to indicate failure
+
+
Slog.d(TAG, "Enqueue: Creating minimal JobInfo for work ID: " + workId);
- return null; // Placeholder - would need proper JobInfo.Builder implementation
+ return null;
} catch (Exception e) {
Slog.w(TAG, "Enqueue: Failed to create minimal JobInfo", e);
return null;
}
}
- /**
- * Check if the error is a UID validation error
- */
+
private boolean isUIDValidationError(Exception e) {
if (e.getCause() instanceof IllegalArgumentException) {
String message = e.getCause().getMessage();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILauncherAppsProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILauncherAppsProxy.java
index e9cd938..027094f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILauncherAppsProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILauncherAppsProxy.java
@@ -9,14 +9,7 @@ import black.android.os.BRServiceManager;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 4/13/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ILauncherAppsProxy extends BinderInvocationStub {
public ILauncherAppsProxy() {
@@ -46,7 +39,7 @@ public class ILauncherAppsProxy extends BinderInvocationStub {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodParameterUtils.replaceFirstAppPkg(args);
- // todo shouldHideFromSuggestions
+
return super.invoke(proxy, method, args);
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILocationManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILocationManagerProxy.java
index 970e918..3690f08 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILocationManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ILocationManagerProxy.java
@@ -22,14 +22,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ILocationManagerProxy extends BinderInvocationStub {
public static final String TAG = "ILocationManagerProxy";
@@ -54,13 +47,13 @@ public class ILocationManagerProxy extends BinderInvocationStub {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-// Log.d(TAG, "call: " + method.getName());
+
MethodParameterUtils.replaceFirstAppPkg(args);
- // Check if this is a Google Play Services process trying to access location
+
String packageName = BActivityThread.getAppPackageName();
if (packageName != null && packageName.equals("com.google.android.gms")) {
- // For Google Play Services, return null for location requests to prevent crashes
+
if (method.getName().equals("getLastLocation") ||
method.getName().equals("getLastKnownLocation") ||
method.getName().equals("requestLocationUpdates")) {
@@ -77,7 +70,7 @@ public class ILocationManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // todo
+
return true;
}
}
@@ -91,7 +84,7 @@ public class ILocationManagerProxy extends BinderInvocationStub {
return BLocationManager.get().getLocation(BActivityThread.getUserId(), BActivityThread.getAppPackageName()).convert2SystemLocation();
}
- // Handle permission issues gracefully
+
try {
return method.invoke(who, args);
} catch (Exception e) {
@@ -113,7 +106,7 @@ public class ILocationManagerProxy extends BinderInvocationStub {
return BLocationManager.get().getLocation(BActivityThread.getUserId(), BActivityThread.getAppPackageName()).convert2SystemLocation();
}
- // Handle permission issues gracefully
+
try {
return method.invoke(who, args);
} catch (Exception e) {
@@ -139,7 +132,7 @@ public class ILocationManagerProxy extends BinderInvocationStub {
}
}
- // Handle permission issues gracefully
+
try {
return method.invoke(who, args);
} catch (Exception e) {
@@ -187,7 +180,7 @@ public class ILocationManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // todo
+
return 0;
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaRouterServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaRouterServiceProxy.java
index 64fa62a..43b7a2f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaRouterServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaRouterServiceProxy.java
@@ -11,9 +11,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * Created by BlackBox on 2022/3/1.
- */
+
public class IMediaRouterServiceProxy extends BinderInvocationStub {
public IMediaRouterServiceProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaSessionManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaSessionManagerProxy.java
index b20edd8..54af1ad 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaSessionManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMediaSessionManagerProxy.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IMediaSessionManagerProxy extends BinderInvocationStub {
public IMediaSessionManagerProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMiuiSecurityManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMiuiSecurityManagerProxy.java
index bfbc15b..f49ae7c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMiuiSecurityManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IMiuiSecurityManagerProxy.java
@@ -11,10 +11,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Proxy for MIUI SecurityManager to handle privacy and security operations
- * Fixes SecurityException: uid does not have android.permission.WRITE_SECURE_SETTINGS
- */
+
public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
public static final String TAG = "MiuiSecurityManagerProxy";
private static final String SERVICE_NAME = "miui.security.SecurityManager";
@@ -30,7 +27,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
return null;
}
try {
- // Get ISecurityManager interface
+
Class> stubClass = Class.forName("miui.security.ISecurityManager$Stub");
Method asInterface = stubClass.getMethod("asInterface", android.os.IBinder.class);
return asInterface.invoke(null, service);
@@ -51,7 +48,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
}
public boolean isEnable() {
- // Only enable on MIUI/Xiaomi systems
+
return BuildCompat.isMIUI() ||
Build.MANUFACTURER.toLowerCase().contains("xiaomi") ||
Build.BRAND.toLowerCase().contains("xiaomi") ||
@@ -89,10 +86,10 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
public static class SetAppPrivacyStatus extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Bypass privacy status setting - always return success
+
String packageName = args.length > 0 ? (String) args[0] : "unknown";
Slog.d(TAG, "SetAppPrivacyStatus: Bypassing privacy status for " + packageName);
- return true; // Return success
+ return true;
}
}
@@ -100,10 +97,10 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
public static class GetAppPrivacyStatus extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Return default privacy status (enabled/allowed)
+
String packageName = args.length > 0 ? (String) args[0] : "unknown";
Slog.d(TAG, "GetAppPrivacyStatus: Returning default status for " + packageName);
- return 0; // Return allowed status
+ return 0;
}
}
@@ -121,7 +118,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "IsAppPermissionControlOpen: Returning false (disabled)");
- return false; // Disable permission control
+ return false;
}
}
@@ -139,7 +136,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "GetWakeUpTime: Returning default wake up time");
- return 0L; // Return default time
+ return 0L;
}
}
@@ -193,7 +190,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "IsAllowStartActivity: Allowing activity start");
- return true; // Always allow activity starts
+ return true;
}
}
@@ -211,7 +208,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "GetAppRunningControlEnabled: Returning false (disabled)");
- return false; // Disable running control
+ return false;
}
}
@@ -220,7 +217,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "CheckAccessControl: Allowing access");
- return true; // Always allow access
+ return true;
}
}
@@ -238,7 +235,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "GetIcon: Returning null icon");
- return null; // Return null icon
+ return null;
}
}
@@ -247,7 +244,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "IsValidDevice: Returning true (valid device)");
- return true; // Always return valid device
+ return true;
}
}
@@ -256,7 +253,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "ActuallyCheckPermission: Granting permission");
- return 0; // Return granted
+ return 0;
}
}
@@ -265,7 +262,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "CheckSmsBlocked: Returning false (not blocked)");
- return false; // SMS not blocked
+ return false;
}
}
@@ -283,7 +280,7 @@ public class IMiuiSecurityManagerProxy extends BinderInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "GetCurrentUserId: Returning current user ID");
- return 0; // Return user 0
+ return 0;
}
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INetworkManagementServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INetworkManagementServiceProxy.java
index f2e4edf..73e594b 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INetworkManagementServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INetworkManagementServiceProxy.java
@@ -13,10 +13,7 @@ import top.niunaijun.blackbox.fake.service.base.UidMethodProxy;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Enhanced Network Management Service Proxy for BlackBox
- * Created by BlackBox on 2022/3/5.
- */
+
public class INetworkManagementServiceProxy extends BinderInvocationStub {
public static final String NAME = "network_management";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INotificationManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INotificationManagerProxy.java
index fcf6409..60be277 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INotificationManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/INotificationManagerProxy.java
@@ -22,14 +22,7 @@ import top.niunaijun.blackbox.utils.MethodParameterUtils;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
import top.niunaijun.blackbox.utils.compat.ParceledListSliceCompat;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class INotificationManagerProxy extends BinderInvocationStub {
public static final String TAG = "INotificationManagerProxy";
@@ -50,7 +43,7 @@ public class INotificationManagerProxy extends BinderInvocationStub {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-// Slog.d(TAG, "call: " + method.getName());
+
MethodParameterUtils.replaceAllAppPkg(args);
return super.invoke(proxy, method, args);
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPackageManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPackageManagerProxy.java
index dce9b7d..517d9ff 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPackageManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPackageManagerProxy.java
@@ -133,14 +133,14 @@ public class IPackageManagerProxy extends BinderInvocationStub {
String packageName = (String) args[0];
int flags = MethodParameterUtils.toInt(args[1]);
- // Provide fake Google Play Services info for MIUI apps
+
if ("com.android.vending".equals(packageName)) {
return createFakeGooglePlayServicesPackageInfo();
}
PackageInfo packageInfo = BlackBoxCore.getBPackageManager().getPackageInfo(packageName, flags, BlackBoxCore.getUserId());
if (packageInfo != null) {
- // Patch: Mark RECORD_AUDIO and related permissions as granted
+
if (packageInfo.requestedPermissions != null && packageInfo.requestedPermissionsFlags != null) {
for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
String perm = packageInfo.requestedPermissions[i];
@@ -170,7 +170,7 @@ public class IPackageManagerProxy extends BinderInvocationStub {
appInfo.packageName = "com.android.vending";
appInfo.name = "Google Play Store";
appInfo.flags = ApplicationInfo.FLAG_SYSTEM;
- appInfo.uid = 10001; // System app UID
+ appInfo.uid = 10001;
packageInfo.applicationInfo = appInfo;
Slog.d(TAG, "GetPackageInfo: Providing fake Google Play Services info");
@@ -281,9 +281,9 @@ public class IPackageManagerProxy extends BinderInvocationStub {
String packageName = (String) args[0];
int flags = MethodParameterUtils.toInt(args[1]);
-// if (ClientSystemEnv.isFakePackage(packageName)) {
-// packageName = BlackBoxCore.getHostPkg();
-// }
+
+
+
ApplicationInfo applicationInfo = BlackBoxCore.getBPackageManager().getApplicationInfo(packageName, flags, BlackBoxCore.getUserId());
if (applicationInfo != null) {
return applicationInfo;
@@ -316,12 +316,12 @@ public class IPackageManagerProxy extends BinderInvocationStub {
List resolves = BlackBoxCore.getBPackageManager().queryBroadcastReceivers(intent, flags, type, BActivityThread.getUserId());
Slog.d(TAG, "queryIntentReceivers: " + resolves);
- // http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/app/ApplicationPackageManager.java#872
+
if (BuildCompat.isN()) {
return ParceledListSliceCompat.create(resolves);
}
- // http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/app/ApplicationPackageManager.java#699
+
return resolves;
}
}
@@ -368,7 +368,7 @@ public class IPackageManagerProxy extends BinderInvocationStub {
public static class GetInstallerPackageName extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // fake google play
+
return "com.android.vending";
}
}
@@ -377,7 +377,7 @@ public class IPackageManagerProxy extends BinderInvocationStub {
public static class GetSharedLibraries extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // todo
+
return ParceledListSliceCompat.create(new ArrayList<>());
}
}
@@ -389,11 +389,11 @@ public class IPackageManagerProxy extends BinderInvocationStub {
ComponentName componentName = (ComponentName) args[0];
String packageName = componentName.getPackageName();
ApplicationInfo applicationInfo = BlackBoxCore.getBPackageManager().getApplicationInfo(packageName,0, BActivityThread.getUserId());
-// if(applicationInfo == null){
-// throw new IllegalArgumentException();
-// }else{
-// return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
-// }
+
+
+
+
+
if(applicationInfo != null){
return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
}
@@ -415,25 +415,25 @@ public class IPackageManagerProxy extends BinderInvocationStub {
String permission = (String) args[0];
String packageName = (String) args[1];
- // Handle all audio-related permissions comprehensively
+
if (isAudioPermission(permission)) {
Slog.d(TAG, "SimpleAudioPermissionHook: Granting audio permission: " + permission + " to " + packageName);
return PackageManager.PERMISSION_GRANTED;
}
- // Also grant storage/media read permissions so hosted apps can see device media
+
if (isStorageOrMediaPermission(permission)) {
Slog.d(TAG, "SimpleAudioPermissionHook: Granting storage/media permission: " + permission + " to " + packageName);
return PackageManager.PERMISSION_GRANTED;
}
- // Grant notification and Xiaomi permissions automatically
+
if (isNotificationOrXiaomiPermission(permission)) {
Slog.d(TAG, "SimpleAudioPermissionHook: Granting notification/Xiaomi permission: " + permission + " to " + packageName);
return PackageManager.PERMISSION_GRANTED;
}
- // For all other permissions, use the original method
+
return method.invoke(who, args);
}
}
@@ -445,25 +445,25 @@ public class IPackageManagerProxy extends BinderInvocationStub {
String permission = (String) args[0];
String packageName = (String) args[1];
- // Handle all audio-related permissions comprehensively
+
if (isAudioPermission(permission)) {
Slog.d(TAG, "CheckSelfPermission: Granting audio permission: " + permission + " to " + packageName);
return PackageManager.PERMISSION_GRANTED;
}
- // Handle storage/media read permissions
+
if (isStorageOrMediaPermission(permission)) {
Slog.d(TAG, "CheckSelfPermission: Granting storage/media permission: " + permission + " to " + packageName);
return PackageManager.PERMISSION_GRANTED;
}
- // Grant notification and Xiaomi permissions automatically
+
if (isNotificationOrXiaomiPermission(permission)) {
Slog.d(TAG, "CheckSelfPermission: Granting notification/Xiaomi permission: " + permission + " to " + packageName);
return PackageManager.PERMISSION_GRANTED;
}
- // For all other permissions, use the original method
+
return method.invoke(who, args);
}
}
@@ -475,25 +475,25 @@ public class IPackageManagerProxy extends BinderInvocationStub {
String permission = (String) args[0];
String packageName = (String) args[1];
- // For audio permissions, don't show rationale since we grant them automatically
+
if (isAudioPermission(permission)) {
Slog.d(TAG, "ShouldShowRequestPermissionRationale: Not showing rationale for audio permission: " + permission);
return false;
}
- // For storage/media, also suppress rationale (we auto-grant)
+
if (isStorageOrMediaPermission(permission)) {
Slog.d(TAG, "ShouldShowRequestPermissionRationale: Not showing rationale for storage/media permission: " + permission);
return false;
}
- // For notification and Xiaomi permissions, don't show rationale (we auto-grant)
+
if (isNotificationOrXiaomiPermission(permission)) {
Slog.d(TAG, "ShouldShowRequestPermissionRationale: Not showing rationale for notification/Xiaomi permission: " + permission);
return false;
}
- // For all other permissions, use the original method
+
return method.invoke(who, args);
}
}
@@ -505,8 +505,8 @@ public class IPackageManagerProxy extends BinderInvocationStub {
String[] permissions = (String[]) args[0];
String packageName = (String) args[1];
- // Do not filter permissions here; allow system flow to proceed so apps get callbacks.
- // The actual permission granting is handled by checkPermission/checkSelfPermission hooks
+
+
if (permissions != null) {
Slog.d(TAG, "RequestPermissions: Allowing permission request flow for: " + java.util.Arrays.toString(permissions));
}
@@ -519,21 +519,21 @@ public class IPackageManagerProxy extends BinderInvocationStub {
public static class DisableIconLoading extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Prevent icon loading that triggers resource issues
+
Slog.d(TAG, "Blocking icon loading to prevent resource errors");
- return null; // Return null instead of trying to load the icon
+ return null;
}
}
- // Helper: recognize storage/media read permissions across API levels
+
private static boolean isStorageOrMediaPermission(String permission) {
if (permission == null) return false;
- // Legacy storage
+
if (permission.equals(android.Manifest.permission.READ_EXTERNAL_STORAGE)
|| permission.equals(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
return true;
}
- // Android 13+ granular media
+
if (permission.equals(android.Manifest.permission.READ_MEDIA_AUDIO)
|| permission.equals(android.Manifest.permission.READ_MEDIA_VIDEO)
|| permission.equals(android.Manifest.permission.READ_MEDIA_IMAGES)
@@ -542,7 +542,7 @@ public class IPackageManagerProxy extends BinderInvocationStub {
|| permission.equals(android.Manifest.permission.ACCESS_MEDIA_LOCATION)) {
return true;
}
- // Android 14/15 user-selected media
+
if (permission.equals("android.permission.READ_MEDIA_AUDIO_USER_SELECTED")
|| permission.equals("android.permission.READ_MEDIA_VIDEO_USER_SELECTED")
|| permission.equals("android.permission.READ_MEDIA_IMAGES_USER_SELECTED")
@@ -553,7 +553,7 @@ public class IPackageManagerProxy extends BinderInvocationStub {
return false;
}
- // Helper: recognize all audio-related permissions across API levels
+
private static boolean isAudioPermission(String permission) {
if (permission == null) return false;
return permission.equals(android.Manifest.permission.RECORD_AUDIO)
@@ -571,16 +571,16 @@ public class IPackageManagerProxy extends BinderInvocationStub {
|| permission.equals("android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE");
}
- // Helper: recognize notification and Xiaomi-specific permissions
+
private static boolean isNotificationOrXiaomiPermission(String permission) {
if (permission == null) return false;
- // Android 12+ notification permission
+
if (permission.equals("android.permission.POST_NOTIFICATIONS")) {
return true;
}
- // Xiaomi-specific permissions
+
if (permission.equals("miui.permission.USE_INTERNAL_GENERAL_API") ||
permission.equals("miui.permission.OPTIMIZE_POWER") ||
permission.equals("miui.permission.RUN_IN_BACKGROUND") ||
@@ -599,13 +599,13 @@ public class IPackageManagerProxy extends BinderInvocationStub {
public static class SetSplashScreenTheme extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Bypass UID ownership check for setSplashScreenTheme
- // This method fails with "Calling uid X does not own package Y" in virtual environment
- // Especially problematic on Xiaomi HyperOS (Android 15) with enhanced security
+
+
+
String packageName = args.length > 0 ? (String) args[0] : "unknown";
Slog.d(TAG, "SetSplashScreenTheme: Bypassing UID check for package: " + packageName);
- // Check if we're on Xiaomi/MIUI system
+
boolean isXiaomi = BuildCompat.isMIUI() ||
Build.MANUFACTURER.toLowerCase().contains("xiaomi") ||
Build.BRAND.toLowerCase().contains("xiaomi") ||
@@ -613,28 +613,28 @@ public class IPackageManagerProxy extends BinderInvocationStub {
if (isXiaomi) {
Slog.d(TAG, "SetSplashScreenTheme: Detected Xiaomi/HyperOS, using enhanced bypass");
- // On Xiaomi systems, completely skip the call to avoid security exceptions
+
return null;
}
- // For other systems, try to call the original method but catch any SecurityException
+
try {
return method.invoke(who, args);
} catch (SecurityException e) {
Slog.w(TAG, "SetSplashScreenTheme: SecurityException caught, bypassing: " + e.getMessage());
return null;
} catch (Exception e) {
- // If it's wrapped in reflection exception, check the cause
+
if (e.getCause() instanceof SecurityException) {
Slog.w(TAG, "SetSplashScreenTheme: SecurityException (wrapped) caught, bypassing: " + e.getCause().getMessage());
return null;
}
- throw e; // Re-throw other exceptions
+ throw e;
}
}
}
- // Comprehensive Xiaomi/HyperOS security bypass for multiple methods
+
public static class XiaomiSecurityBypass extends MethodHook {
private static final String[] XIAOMI_SECURITY_METHODS = {
"setApplicationEnabledSetting",
@@ -672,7 +672,7 @@ public class IPackageManagerProxy extends BinderInvocationStub {
@Override
public boolean isEnable() {
- // Only enable on Xiaomi/HyperOS systems
+
return BuildCompat.isMIUI() ||
Build.MANUFACTURER.toLowerCase().contains("xiaomi") ||
Build.BRAND.toLowerCase().contains("xiaomi") ||
@@ -681,43 +681,43 @@ public class IPackageManagerProxy extends BinderInvocationStub {
@Override
public String getMethodName() {
- return null; // We handle multiple methods
+ return null;
}
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
- // Check if this is a Xiaomi security-sensitive method
+
for (String securityMethod : XIAOMI_SECURITY_METHODS) {
if (securityMethod.equals(methodName)) {
Slog.d(TAG, "XiaomiSecurityBypass: Intercepting " + methodName + " on Xiaomi/HyperOS");
- // For methods that return void, just return null
+
if (method.getReturnType() == void.class) {
return null;
}
- // For methods that return boolean, return true (success)
+
else if (method.getReturnType() == boolean.class) {
return true;
}
- // For methods that return int, return 0 (success)
+
else if (method.getReturnType() == int.class) {
return 0;
}
- // For other return types, return null
+
else {
return null;
}
}
}
- // Not a security method, proceed normally but catch SecurityExceptions
+
try {
return method.invoke(who, args);
} catch (SecurityException e) {
Slog.w(TAG, "XiaomiSecurityBypass: SecurityException in " + methodName + ", bypassing: " + e.getMessage());
- // Return appropriate default based on return type
+
if (method.getReturnType() == boolean.class) {
return false;
} else if (method.getReturnType() == int.class) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPermissionManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPermissionManagerProxy.java
index 6b184cf..12f5f18 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPermissionManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPermissionManagerProxy.java
@@ -13,9 +13,7 @@ import top.niunaijun.blackbox.fake.service.base.ValueMethodProxy;
import top.niunaijun.blackbox.utils.Reflector;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Created by BlackBox on 2022/3/2.
- */
+
public class IPermissionManagerProxy extends BinderInvocationStub {
public static final String TAG = "IPermissionManagerProxy";
@@ -34,7 +32,7 @@ public class IPermissionManagerProxy extends BinderInvocationStub {
protected void inject(Object baseInvocation, Object proxyInvocation) {
replaceSystemService("permissionmgr");
BRActivityThread.getWithException()._set_sPermissionManager(proxyInvocation);
- // Removed problematic ApplicationPackageManager injection to avoid type conflicts
+
}
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPersistentDataBlockServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPersistentDataBlockServiceProxy.java
index 4a865a1..c6fbc9c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPersistentDataBlockServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPersistentDataBlockServiceProxy.java
@@ -6,9 +6,7 @@ import black.android.service.persistentdata.BRIPersistentDataBlockServiceStub;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.service.base.ValueMethodProxy;
-/**
- * Created by BlackBox on 2022/3/8.
- */
+
public class IPersistentDataBlockServiceProxy extends BinderInvocationStub {
public static final String NAME = "persistent_data_block";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPhoneSubInfoProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPhoneSubInfoProxy.java
index 1096af8..e39e192 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPhoneSubInfoProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPhoneSubInfoProxy.java
@@ -8,9 +8,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * Created by BlackBox on 2022/2/26.
- */
+
public class IPhoneSubInfoProxy extends ClassInvocationStub {
public static final String TAG = "IPhoneSubInfoProxy";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPowerManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPowerManagerProxy.java
index f1b1e0e..e4a2efd 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPowerManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IPowerManagerProxy.java
@@ -7,9 +7,7 @@ import black.android.os.BRServiceManager;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.service.base.ValueMethodProxy;
-/**
- * Created by BlackBox on 2022/3/1.
- */
+
public class IPowerManagerProxy extends BinderInvocationStub {
public IPowerManagerProxy() {
super(BRServiceManager.get().getService(Context.POWER_SERVICE));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensitiveContentProtectionManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensitiveContentProtectionManagerProxy.java
index b8622bc..ac25a7c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensitiveContentProtectionManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensitiveContentProtectionManagerProxy.java
@@ -12,10 +12,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Hook for ISensitiveContentProtectionManager (Android 14+)
- * Fixes SecurityException: Specified calling package [pkg] does not match the calling uid
- */
+
public class ISensitiveContentProtectionManagerProxy extends BinderInvocationStub {
public static final String TAG = "ISensitiveContentProtection";
@@ -58,7 +55,7 @@ public class ISensitiveContentProtectionManagerProxy extends BinderInvocationStu
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
if (args != null && args.length > 0) {
- // setSensitiveContentProtection(IBinder windowToken, String packageName, boolean isProtected)
+
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof String) {
String pkg = (String) args[i];
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensorPrivacyManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensorPrivacyManagerProxy.java
index f7cd87e..9488645 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensorPrivacyManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISensorPrivacyManagerProxy.java
@@ -11,9 +11,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Reflector;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Force microphone sensor privacy OFF for sandboxed apps (Android 12+).
- */
+
public class ISensorPrivacyManagerProxy extends BinderInvocationStub {
public static final String TAG = "SensorPrivacyProxy";
@@ -24,24 +22,24 @@ public class ISensorPrivacyManagerProxy extends BinderInvocationStub {
@Override
protected Object getWho() {
try {
- // Try multiple reflection paths for different Android versions
+
Object stub = null;
- // Android 16+ path
+
try {
stub = Reflector.on("android.hardware.ISensorPrivacyManager$Stub")
.call("asInterface", BRServiceManager.get().getService("sensor_privacy"));
} catch (Exception e1) {
Slog.d(TAG, "Failed Android 16+ path, trying alternative: " + e1.getMessage());
- // Alternative path for older versions
+
try {
stub = Reflector.on("android.hardware.ISensorPrivacyManager")
.call("asInterface", BRServiceManager.get().getService("sensor_privacy"));
} catch (Exception e2) {
Slog.d(TAG, "Failed alternative path: " + e2.getMessage());
- // Last resort: try direct interface casting
+
try {
Class> stubClass = Class.forName("android.hardware.ISensorPrivacyManager$Stub");
Method asInterfaceMethod = stubClass.getMethod("asInterface", android.os.IBinder.class);
@@ -77,7 +75,7 @@ public class ISensorPrivacyManagerProxy extends BinderInvocationStub {
return false;
}
- // Newer APIs: boolean isSensorPrivacyEnabled(int sensor)
+
@ProxyMethod("isSensorPrivacyEnabled")
public static class IsSensorPrivacyEnabled extends MethodHook {
@Override
@@ -87,7 +85,7 @@ public class ISensorPrivacyManagerProxy extends BinderInvocationStub {
}
}
- // Some versions: boolean isSensorPrivacyEnabled(int userId, int sensor)
+
@ProxyMethod("isSensorPrivacyEnabledForUser")
public static class IsSensorPrivacyEnabledForUser extends MethodHook {
@Override
@@ -97,7 +95,7 @@ public class ISensorPrivacyManagerProxy extends BinderInvocationStub {
}
}
- // Some versions: boolean isSensorPrivacyEnabled(int userId, int sensor, String packageName)
+
@ProxyMethod("isSensorPrivacyEnabledForProfile")
public static class IsSensorPrivacyEnabledForProfile extends MethodHook {
@Override
@@ -107,7 +105,7 @@ public class ISensorPrivacyManagerProxy extends BinderInvocationStub {
}
}
- // Allow sensor access
+
@ProxyMethod("setSensorPrivacy")
public static class SetSensorPrivacy extends MethodHook {
@Override
@@ -117,7 +115,7 @@ public class ISensorPrivacyManagerProxy extends BinderInvocationStub {
}
}
- // Allow sensor access
+
@ProxyMethod("setSensorPrivacyForProfile")
public static class SetSensorPrivacyForProfile extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsProviderProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsProviderProxy.java
index aaffc23..060b4b8 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsProviderProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsProviderProxy.java
@@ -13,10 +13,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Settings ContentProvider proxy to handle UID mismatch issues
- * when virtual apps try to access system settings
- */
+
public class ISettingsProviderProxy extends ClassInvocationStub {
public static final String TAG = "ISettingsProviderProxy";
@@ -43,22 +40,22 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Check if this is a feature flag query that might cause UID issues
+
if (args != null && args.length > 0) {
String key = (String) args[0];
if (key != null && key.contains("feature_flag")) {
Slog.d(TAG, "Intercepting feature flag query: " + key + ", returning safe default");
- return "true"; // Return safe default for feature flags
+ return "true";
}
}
- // Try to call the original method
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getStringForUser, returning safe default: " + errorMsg);
- return "true"; // Return safe default for UID mismatch
+ return "true";
}
throw e;
}
@@ -70,22 +67,22 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Check if this is a feature flag query
+
if (args != null && args.length > 0) {
String key = (String) args[0];
if (key != null && key.contains("feature_flag")) {
Slog.d(TAG, "Intercepting feature flag query: " + key + ", returning safe default");
- return "true"; // Return safe default for feature flags
+ return "true";
}
}
- // Try to call the original method
+
return method.invoke(who, args);
} catch (Exception e) {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getString, returning safe default: " + errorMsg);
- return "true"; // Return safe default for UID mismatch
+ return "true";
}
throw e;
}
@@ -102,7 +99,7 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getIntForUser, returning safe default: " + errorMsg);
- return 1; // Return safe default for UID mismatch
+ return 1;
}
throw e;
}
@@ -119,7 +116,7 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getInt, returning safe default: " + errorMsg);
- return 1; // Return safe default for UID mismatch
+ return 1;
}
throw e;
}
@@ -136,7 +133,7 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getLongForUser, returning safe default: " + errorMsg);
- return 1L; // Return safe default for UID mismatch
+ return 1L;
}
throw e;
}
@@ -153,7 +150,7 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getLong, returning safe default: " + errorMsg);
- return 1L; // Return safe default for UID mismatch
+ return 1L;
}
throw e;
}
@@ -170,7 +167,7 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getFloatForUser, returning safe default: " + errorMsg);
- return 1.0f; // Return safe default for UID mismatch
+ return 1.0f;
}
throw e;
}
@@ -187,7 +184,7 @@ public class ISettingsProviderProxy extends ClassInvocationStub {
String errorMsg = e.getMessage();
if (errorMsg != null && errorMsg.contains("Calling uid") && errorMsg.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getFloat, returning safe default: " + errorMsg);
- return 1.0f; // Return safe default for UID mismatch
+ return 1.0f;
}
throw e;
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsSystemProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsSystemProxy.java
index d23a6f9..771d189 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsSystemProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISettingsSystemProxy.java
@@ -8,10 +8,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.AttributionSourceUtils;
-/**
- * ISettingsSystem Proxy to handle AttributionSource UID issues on Android 12+
- * This prevents crashes related to Settings.System UID enforcement
- */
+
public class ISettingsSystemProxy extends ClassInvocationStub {
public static final String TAG = "ISettingsSystemProxy";
@@ -21,13 +18,13 @@ public class ISettingsSystemProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return null since this is a global hook, not a specific service
+
return null;
}
@Override
protected void inject(Object base, Object proxy) {
- // This proxy handles Settings.System calls globally
+
Slog.d(TAG, "ISettingsSystem proxy initialized for UID mismatch prevention");
}
@@ -36,82 +33,82 @@ public class ISettingsSystemProxy extends ClassInvocationStub {
return false;
}
- // Hook for getStringForUser method to fix AttributionSource issues
+
@ProxyMethod("getStringForUser")
public static class GetStringForUser extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getStringForUser, returning safe default: " + message);
- return ""; // Return empty string to prevent crashes
+ return "";
}
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in getStringForUser hook: " + e.getMessage());
- // Return empty string to prevent crashes
+
return "";
}
}
}
- // Hook for getString method to fix AttributionSource issues
+
@ProxyMethod("getString")
public static class GetString extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in getString, returning safe default: " + message);
- return ""; // Return empty string to prevent crashes
+ return "";
}
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in getString hook: " + e.getMessage());
- // Return empty string to prevent crashes
+
return "";
}
}
}
- // Hook for putString method to fix AttributionSource issues
+
@ProxyMethod("putString")
public static class PutString extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in putString, returning false: " + message);
- return false; // Return false to prevent crashes
+ return false;
}
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in putString hook: " + e.getMessage());
- // Return false to prevent crashes
+
return false;
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IShortcutManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IShortcutManagerProxy.java
index 6ad5d90..25d21b6 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IShortcutManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IShortcutManagerProxy.java
@@ -16,15 +16,7 @@ import top.niunaijun.blackbox.fake.service.base.PkgMethodProxy;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
import top.niunaijun.blackbox.utils.compat.ParceledListSliceCompat;
-/**
- * updated by alex5402 on 4/5/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- * 未实现,全部拦截
- */
+
public class IShortcutManagerProxy extends BinderInvocationStub {
public IShortcutManagerProxy() {
@@ -49,7 +41,7 @@ public class IShortcutManagerProxy extends BinderInvocationStub {
@Override
protected void onBindMethod() {
super.onBindMethod();
- addMethodHook(new PkgMethodProxy("getShortcuts"));//修复whtasApp启动黑屏问题
+ addMethodHook(new PkgMethodProxy("getShortcuts"));
addMethodHook(new PkgMethodProxy("disableShortcuts"));
addMethodHook(new PkgMethodProxy("enableShortcuts"));
addMethodHook(new PkgMethodProxy("getRemainingCallCount"));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageManagerProxy.java
index ab08b37..281ed3c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageManagerProxy.java
@@ -15,14 +15,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 4/10/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IStorageManagerProxy extends BinderInvocationStub {
public IStorageManagerProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageStatsManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageStatsManagerProxy.java
index 671f00a..4c2df54 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageStatsManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IStorageStatsManagerProxy.java
@@ -11,9 +11,7 @@ import black.android.os.BRServiceManager;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * Created by BlackBox on 2022/3/3.
- */
+
@TargetApi(Build.VERSION_CODES.O)
public class IStorageStatsManagerProxy extends BinderInvocationStub {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemSensorManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemSensorManagerProxy.java
index 47a1bce..281c0ef 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemSensorManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemSensorManagerProxy.java
@@ -8,10 +8,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.AttributionSourceUtils;
-/**
- * ISystemSensorManager Proxy to handle AttributionSource UID issues on Android 12+
- * This prevents crashes related to SystemSensorManager UID enforcement
- */
+
public class ISystemSensorManagerProxy extends ClassInvocationStub {
public static final String TAG = "ISystemSensorManagerProxy";
@@ -21,13 +18,13 @@ public class ISystemSensorManagerProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return null since this is a global hook, not a specific service
+
return null;
}
@Override
protected void inject(Object base, Object proxy) {
- // This proxy handles SystemSensorManager calls globally
+
Slog.d(TAG, "ISystemSensorManager proxy initialized for UID mismatch prevention");
}
@@ -36,19 +33,19 @@ public class ISystemSensorManagerProxy extends ClassInvocationStub {
return false;
}
- // Hook for SystemSensorManager constructor to fix AttributionSource issues
+
@ProxyMethod("SystemSensorManager")
public static class Constructor extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "UID mismatch in SystemSensorManager constructor, creating safe fallback: " + message);
@@ -57,44 +54,42 @@ public class ISystemSensorManagerProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in SystemSensorManager constructor hook: " + e.getMessage());
- // Create safe fallback
+
return createSafeSensorManager();
}
}
}
- // Hook for parsePackageList method to fix AttributionSource issues
+
@ProxyMethod("parsePackageList")
public static class ParsePackageList extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in parsePackageList hook: " + e.getMessage());
- // Return empty list to prevent crashes
+
return new java.util.ArrayList<>();
}
}
}
- /**
- * Create a safe SystemSensorManager for fallback
- */
+
private static Object createSafeSensorManager() {
try {
- // Try to create a safe SystemSensorManager using reflection
+
Class> sensorManagerClass = Class.forName("android.hardware.SystemSensorManager");
- // Try different constructor signatures
+
Object sensorManager = null;
try {
- // Try default constructor
+
java.lang.reflect.Constructor> constructor = sensorManagerClass.getDeclaredConstructor();
constructor.setAccessible(true);
sensorManager = constructor.newInstance();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemUpdateProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemUpdateProxy.java
index 452d102..85d06d1 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemUpdateProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ISystemUpdateProxy.java
@@ -5,11 +5,7 @@ import black.android.os.BRServiceManager;
import black.android.view.BRIAutoFillManagerStub;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
-/**
- * @author Findger
- * @function
- * @date :2022/4/2 21:59
- **/
+
public class ISystemUpdateProxy extends BinderInvocationStub {
public ISystemUpdateProxy() {
super(BRServiceManager.get().getService("system_update"));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyManagerProxy.java
index eccb926..00ce43d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyManagerProxy.java
@@ -20,14 +20,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Md5Utils;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ITelephonyManagerProxy extends BinderInvocationStub {
public static final String TAG = "ITelephonyManagerProxy";
@@ -55,8 +48,8 @@ public class ITelephonyManagerProxy extends BinderInvocationStub {
public static class GetDeviceId extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
-// MethodParameterUtils.replaceFirstAppPkg(args);
-// return method.invoke(who, args);
+
+
return Md5Utils.md5(BlackBoxCore.getHostPkg());
}
}
@@ -65,8 +58,8 @@ public class ITelephonyManagerProxy extends BinderInvocationStub {
public static class getImeiForSlot extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
-// MethodParameterUtils.replaceFirstAppPkg(args);
-// return method.invoke(who, args);
+
+
return Md5Utils.md5(BlackBoxCore.getHostPkg());
}
}
@@ -75,8 +68,8 @@ public class ITelephonyManagerProxy extends BinderInvocationStub {
public static class GetMeidForSlot extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
-// MethodParameterUtils.replaceFirstAppPkg(args);
-// return method.invoke(who, args);
+
+
return Md5Utils.md5(BlackBoxCore.getHostPkg());
}
}
@@ -122,7 +115,7 @@ public class ITelephonyManagerProxy extends BinderInvocationStub {
if (BLocationManager.isFakeLocationEnable()) {
BCell cell = BLocationManager.get().getCell(BActivityThread.getUserId(), BActivityThread.getAppPackageName());
if (cell != null) {
- // TODO Transfer BCell to CdmaCellLocation/GsmCellLocation
+
return null;
}
}
@@ -136,7 +129,7 @@ public class ITelephonyManagerProxy extends BinderInvocationStub {
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
if (BLocationManager.isFakeLocationEnable()) {
List cell = BLocationManager.get().getAllCell(BActivityThread.getUserId(), BActivityThread.getAppPackageName());
- // TODO Transfer BCell to CdmaCellLocation/GsmCellLocation
+
return cell;
}
try {
@@ -175,7 +168,7 @@ public class ITelephonyManagerProxy extends BinderInvocationStub {
Log.d(TAG, "getNeighboringCellInfo");
if (BLocationManager.isFakeLocationEnable()) {
List cell = BLocationManager.get().getNeighboringCell(BActivityThread.getUserId(), BActivityThread.getAppPackageName());
- // TODO Transfer BCell to CdmaCellLocation/GsmCellLocation
+
return null;
}
return method.invoke(who, args);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyRegistryProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyRegistryProxy.java
index 9866cf1..474dda0 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyRegistryProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ITelephonyRegistryProxy.java
@@ -9,14 +9,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * updated by alex5402 on 2021/5/17.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ITelephonyRegistryProxy extends BinderInvocationStub {
public ITelephonyRegistryProxy() {
super(BRServiceManager.get().getService("telephony.registry"));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java
index 93cbb44..ccb30dd 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IUserManagerProxy.java
@@ -14,14 +14,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IUserManagerProxy extends BinderInvocationStub {
public IUserManagerProxy() {
super(BRServiceManager.get().getService(Context.USER_SERVICE));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVibratorServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVibratorServiceProxy.java
index 5554b87..cb446ed 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVibratorServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVibratorServiceProxy.java
@@ -12,9 +12,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * Created by BlackBox on 2022/3/7.
- */
+
public class IVibratorServiceProxy extends BinderInvocationStub {
private static String NAME;
static {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVpnManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVpnManagerProxy.java
index 4bd8abe..e3461bb 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVpnManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IVpnManagerProxy.java
@@ -5,14 +5,7 @@ import black.android.os.BRServiceManager;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.ScanClass;
-/**
- * updated by alex5402 on 4/12/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
@ScanClass(VpnCommonProxy.class)
public class IVpnManagerProxy extends BinderInvocationStub {
public static final String TAG = "IVpnManagerProxy";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWebViewUpdateServiceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWebViewUpdateServiceProxy.java
index 237ff79..bdd2a54 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWebViewUpdateServiceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWebViewUpdateServiceProxy.java
@@ -10,10 +10,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.fake.hook.ClassInvocationStub;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Enhanced WebView update service proxy to handle WebView provider issues,
- * package validation, and provide comprehensive WebView service support.
- */
+
public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
public static final String TAG = "IWebViewUpdateServiceProxy";
@@ -23,12 +20,12 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook WebView update service methods
+
}
@Override
@@ -36,7 +33,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
return false;
}
- // Hook getCurrentWebViewPackage() to return a valid WebView package
+
@ProxyMethod("getCurrentWebViewPackage")
public static class GetCurrentWebViewPackage extends MethodHook {
@Override
@@ -44,7 +41,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewUpdateService: getCurrentWebViewPackage called");
try {
- // Try to get the current WebView package from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewUpdateService: Successfully got current WebView package");
@@ -54,13 +51,13 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewUpdateService: Failed to get current WebView package", e);
}
- // Return null to let the system use the default WebView provider
+
Slog.d(TAG, "WebViewUpdateService: Returning null to use system default");
return null;
}
}
- // Hook getValidWebViewPackages() to return valid packages
+
@ProxyMethod("getValidWebViewPackages")
public static class GetValidWebViewPackages extends MethodHook {
@Override
@@ -68,7 +65,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewUpdateService: getValidWebViewPackages called");
try {
- // Try to get valid WebView packages from the system
+
Object result = method.invoke(who, args);
if (result != null && result instanceof PackageInfo[]) {
PackageInfo[] packages = (PackageInfo[]) result;
@@ -81,13 +78,13 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewUpdateService: Failed to get valid WebView packages", e);
}
- // Return empty array to prevent WebView provider conflicts
+
Slog.d(TAG, "WebViewUpdateService: Returning empty array to prevent conflicts");
return new PackageInfo[0];
}
}
- // Hook isMultiProcessEnabled() to return true
+
@ProxyMethod("isMultiProcessEnabled")
public static class IsMultiProcessEnabled extends MethodHook {
@Override
@@ -97,7 +94,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
}
}
- // Hook getWebViewPackages() to return available WebView packages
+
@ProxyMethod("getWebViewPackages")
public static class GetWebViewPackages extends MethodHook {
@Override
@@ -105,7 +102,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewUpdateService: getWebViewPackages called");
try {
- // Try to get WebView packages from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewUpdateService: Successfully got WebView packages");
@@ -115,12 +112,12 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewUpdateService: Failed to get WebView packages", e);
}
- // Return empty list if system call fails
+
return new ArrayList<>();
}
}
- // Hook getWebViewProviderInfo() to return provider information
+
@ProxyMethod("getWebViewProviderInfo")
public static class GetWebViewProviderInfo extends MethodHook {
@Override
@@ -128,7 +125,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewUpdateService: getWebViewProviderInfo called");
try {
- // Try to get WebView provider info from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewUpdateService: Successfully got WebView provider info");
@@ -138,12 +135,12 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewUpdateService: Failed to get WebView provider info", e);
}
- // Return null if system call fails
+
return null;
}
}
- // Hook isWebViewPackage() to validate WebView packages
+
@ProxyMethod("isWebViewPackage")
public static class IsWebViewPackage extends MethodHook {
@Override
@@ -152,7 +149,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
String packageName = (String) args[0];
Slog.d(TAG, "WebViewUpdateService: isWebViewPackage called for: " + packageName);
- // Check if it's a known WebView package
+
if (isKnownWebViewPackage(packageName)) {
Slog.d(TAG, "WebViewUpdateService: " + packageName + " is a known WebView package");
return true;
@@ -170,7 +167,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
private boolean isKnownWebViewPackage(String packageName) {
if (packageName == null) return false;
- // List of known WebView packages
+
return packageName.equals("com.google.android.webview") ||
packageName.equals("com.google.android.webview.dev") ||
packageName.equals("com.google.android.webview.beta") ||
@@ -182,7 +179,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
}
}
- // Hook getWebViewProvider() to get the current WebView provider
+
@ProxyMethod("getWebViewProvider")
public static class GetWebViewProvider extends MethodHook {
@Override
@@ -190,7 +187,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewUpdateService: getWebViewProvider called");
try {
- // Try to get WebView provider from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewUpdateService: Successfully got WebView provider");
@@ -200,12 +197,12 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewUpdateService: Failed to get WebView provider", e);
}
- // Return null if system call fails
+
return null;
}
}
- // Hook enableWebViewPackage() to enable WebView packages
+
@ProxyMethod("enableWebViewPackage")
public static class EnableWebViewPackage extends MethodHook {
@Override
@@ -219,13 +216,13 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WebViewUpdateService: Failed to enable WebView package", e);
- // Return success to prevent crashes
+
return true;
}
}
}
- // Hook disableWebViewPackage() to disable WebView packages
+
@ProxyMethod("disableWebViewPackage")
public static class DisableWebViewPackage extends MethodHook {
@Override
@@ -239,7 +236,7 @@ public class IWebViewUpdateServiceProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WebViewUpdateService: Failed to disable WebView package", e);
- // Return success to prevent crashes
+
return true;
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java
index 4e35281..2f1f81d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiManagerProxy.java
@@ -14,14 +14,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/12/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IWifiManagerProxy extends BinderInvocationStub {
public static final String TAG = "IWifiManagerProxy";
@@ -46,11 +39,7 @@ public class IWifiManagerProxy extends BinderInvocationStub {
@ProxyMethod("getConnectionInfo")
public static class GetConnectionInfo extends MethodHook {
- /*
- * It doesn't have public method to set BSSID and SSID fields in WifiInfo class,
- * So the reflection framework invocation appeared.
- * commented by BlackBoxing at 2022/03/08
- * */
+
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
WifiInfo wifiInfo = (WifiInfo) method.invoke(who, args);
@@ -68,13 +57,13 @@ public class IWifiManagerProxy extends BinderInvocationStub {
}
public static int ip2Int(String ipString) {
- // 取 ip 的各段
+
String[] ipSlices = ipString.split("\\.");
int rs = 0;
for (int i = 0; i < ipSlices.length; i++) {
- // 将 ip 的每一段解析为 int,并根据位置左移 8 位
+
int intSlice = Integer.parseInt(ipSlices[i]) << 8 * i;
- // 或运算
+
rs = rs | intSlice;
}
return rs;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiScannerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiScannerProxy.java
index 5d12974..432339d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiScannerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWifiScannerProxy.java
@@ -7,11 +7,7 @@ import black.android.net.wifi.BRIWifiManagerStub;
import black.android.os.BRServiceManager;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
-/**
- * @author Findger
- * @function
- * @date :2022/4/3 13:05
- **/
+
public class IWifiScannerProxy extends BinderInvocationStub {
public IWifiScannerProxy() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowManagerProxy.java
index f2f0712..5bb90d7 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowManagerProxy.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/6/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IWindowManagerProxy extends BinderInvocationStub {
public static final String TAG = "WindowManagerStub";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowSessionProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowSessionProxy.java
index 5459068..e9b52f5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowSessionProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IWindowSessionProxy.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/6/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class IWindowSessionProxy extends BinderInvocationStub {
public static final String TAG = "WindowSessionStub";
@@ -58,7 +51,11 @@ public class IWindowSessionProxy extends BinderInvocationStub {
continue;
}
if (arg instanceof WindowManager.LayoutParams) {
- ((WindowManager.LayoutParams) arg).packageName = BlackBoxCore.getHostPkg();
+ WindowManager.LayoutParams lp = (WindowManager.LayoutParams) arg;
+ lp.packageName = BlackBoxCore.getHostPkg();
+ if (BlackBoxCore.get().isDisableFlagSecure()) {
+ lp.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
+ }
}
}
return method.invoke(who, args);
@@ -68,4 +65,23 @@ public class IWindowSessionProxy extends BinderInvocationStub {
@ProxyMethod("addToDisplayAsUser")
public static class AddToDisplayAsUser extends AddToDisplay {
}
+
+ @ProxyMethod("relayout")
+ public static class Relayout extends MethodHook {
+ @Override
+ protected Object hook(Object who, Method method, Object[] args) throws Throwable {
+ for (Object arg : args) {
+ if (arg == null) {
+ continue;
+ }
+ if (arg instanceof WindowManager.LayoutParams) {
+ WindowManager.LayoutParams lp = (WindowManager.LayoutParams) arg;
+ if (BlackBoxCore.get().isDisableFlagSecure()) {
+ lp.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
+ }
+ }
+ }
+ return method.invoke(who, args);
+ }
+ }
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiAttributionSourceProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiAttributionSourceProxy.java
index 7683e84..4500309 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiAttributionSourceProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiAttributionSourceProxy.java
@@ -9,10 +9,7 @@ import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.AttributionSourceUtils;
import top.niunaijun.blackbox.util.XiaomiDeviceDetector;
-/**
- * IXiaomiAttributionSource Proxy to handle MIUI-specific UID issues on Android 12+
- * This prevents crashes related to Xiaomi's enhanced security enforcement
- */
+
public class IXiaomiAttributionSourceProxy extends ClassInvocationStub {
public static final String TAG = "IXiaomiAttributionSourceProxy";
@@ -22,13 +19,13 @@ public class IXiaomiAttributionSourceProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return null since this is a global hook, not a specific service
+
return null;
}
@Override
protected void inject(Object base, Object proxy) {
- // This proxy handles Xiaomi-specific AttributionSource issues globally
+
if (XiaomiDeviceDetector.isXiaomiDevice()) {
Slog.d(TAG, "IXiaomiAttributionSource proxy initialized for MIUI UID mismatch prevention on " +
XiaomiDeviceDetector.getDeviceModel() + " (MIUI " + XiaomiDeviceDetector.getMiuiVersion() + ")");
@@ -42,19 +39,19 @@ public class IXiaomiAttributionSourceProxy extends ClassInvocationStub {
return false;
}
- // Hook for AttributionSource constructor to fix UID issues on Xiaomi
+
@ProxyMethod("AttributionSource")
public static class AttributionSourceConstructor extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "Xiaomi UID mismatch in AttributionSource constructor, creating safe fallback: " + message);
@@ -63,44 +60,44 @@ public class IXiaomiAttributionSourceProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi AttributionSource constructor hook: " + e.getMessage());
- // Create safe fallback for Xiaomi devices
+
return AttributionSourceUtils.createSafeAttributionSource();
}
}
}
- // Hook for enforceCallingUid to bypass Xiaomi's strict enforcement
+
@ProxyMethod("enforceCallingUid")
public static class EnforceCallingUid extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always allow on Xiaomi devices to prevent crashes
+
Slog.d(TAG, "Xiaomi enforceCallingUid bypassed to prevent UID mismatch crashes");
- return null; // Indicate success
+ return null;
}
}
- // Hook for enforceCallingUidAndPid to bypass Xiaomi's strict enforcement
+
@ProxyMethod("enforceCallingUidAndPid")
public static class EnforceCallingUidAndPid extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
- // Always allow on Xiaomi devices to prevent crashes
+
Slog.d(TAG, "Xiaomi enforceCallingUidAndPid bypassed to prevent UID mismatch crashes");
- return null; // Indicate success
+ return null;
}
}
- // Hook for fromParcel to fix UID issues in deserialized objects
+
@ProxyMethod("fromParcel")
public static class FromParcel extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Call original method first
+
Object result = method.invoke(who, args);
- // Fix the UID of the created object for Xiaomi compatibility
+
if (result != null) {
AttributionSourceUtils.fixAttributionSourceUid(result);
}
@@ -108,7 +105,7 @@ public class IXiaomiAttributionSourceProxy extends ClassInvocationStub {
return result;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi fromParcel hook: " + e.getMessage());
- // Create safe fallback for Xiaomi devices
+
return AttributionSourceUtils.createSafeAttributionSource();
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiMiuiServicesProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiMiuiServicesProxy.java
index 1d020f5..0105187 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiMiuiServicesProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiMiuiServicesProxy.java
@@ -9,10 +9,7 @@ import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.AttributionSourceUtils;
import top.niunaijun.blackbox.util.XiaomiDeviceDetector;
-/**
- * IXiaomiMiuiServices Proxy to handle MIUI-specific service issues on Android 12+
- * This prevents crashes related to Xiaomi's MIUI framework and proprietary services
- */
+
public class IXiaomiMiuiServicesProxy extends ClassInvocationStub {
public static final String TAG = "IXiaomiMiuiServicesProxy";
@@ -22,13 +19,13 @@ public class IXiaomiMiuiServicesProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return null since this is a global hook, not a specific service
+
return null;
}
@Override
protected void inject(Object base, Object proxy) {
- // This proxy handles Xiaomi-specific MIUI service issues globally
+
if (XiaomiDeviceDetector.isXiaomiDevice()) {
Slog.d(TAG, "IXiaomiMiuiServices proxy initialized for MIUI service crash prevention on " +
XiaomiDeviceDetector.getDeviceModel() + " (MIUI " + XiaomiDeviceDetector.getMiuiVersion() + ")");
@@ -42,19 +39,19 @@ public class IXiaomiMiuiServicesProxy extends ClassInvocationStub {
return false;
}
- // Hook for MiuiCameraCoveredManager to prevent NullPointerException on Xiaomi
+
@ProxyMethod("MiuiCameraCoveredManager")
public static class MiuiCameraCoveredManager extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (NullPointerException e) {
- // Handle NullPointerException specifically for MIUI camera manager on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Attempt to invoke virtual method") &&
message.contains("android.provider.MiuiSettings$SettingsCloudData$CloudData.getString")) {
@@ -63,7 +60,7 @@ public class IXiaomiMiuiServicesProxy extends ClassInvocationStub {
}
throw e;
} catch (SecurityException e) {
- // Handle SecurityException for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "MIUI Camera Manager UID mismatch on Xiaomi, creating safe fallback: " + message);
@@ -72,158 +69,156 @@ public class IXiaomiMiuiServicesProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in MIUI Camera Manager hook: " + e.getMessage());
- // Create safe fallback for Xiaomi devices
+
return createSafeMiuiCameraManagerForXiaomi();
}
}
}
- // Hook for MiuiForceDarkConfig to prevent crashes on Xiaomi
+
@ProxyMethod("MiuiForceDarkConfig")
public static class MiuiForceDarkConfig extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in MIUI Force Dark Config hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return null;
}
}
}
- // Hook for MiuiMonitorThread to prevent crashes on Xiaomi
+
@ProxyMethod("MiuiMonitorThread")
public static class MiuiMonitorThread extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in MIUI Monitor Thread hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return null;
}
}
}
- // Hook for MiuiDownscaleImpl to prevent crashes on Xiaomi
+
@ProxyMethod("MiuiDownscaleImpl")
public static class MiuiDownscaleImpl extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in MIUI Downscale Implementation hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return null;
}
}
}
- // Hook for ForceDarkHelperStubImpl to prevent crashes on Xiaomi
+
@ProxyMethod("ForceDarkHelperStubImpl")
public static class ForceDarkHelperStubImpl extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in Force Dark Helper Stub Implementation hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return null;
}
}
}
- // Hook for HandWritingStubImpl to prevent crashes on Xiaomi
+
@ProxyMethod("HandWritingStubImpl")
public static class HandWritingStubImpl extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in Hand Writing Stub Implementation hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return null;
}
}
}
- // Hook for OplusScrollToTopManager to prevent crashes on Xiaomi
+
@ProxyMethod("OplusScrollToTopManager")
public static class OplusScrollToTopManager extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in Oplus Scroll To Top Manager hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return null;
}
}
}
- // Hook for OplusOverScrollerExtImpl to prevent crashes on Xiaomi
+
@ProxyMethod("OplusOverScrollerExtImpl")
public static class OplusOverScrollerExtImpl extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "Error in Oplus Over Scroller Extension Implementation hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return null;
}
}
}
- /**
- * Create a safe MiuiCameraManager specifically for Xiaomi devices
- */
+
private static Object createSafeMiuiCameraManagerForXiaomi() {
try {
- // Try to create a safe MiuiCameraCoveredManager using reflection
+
Class> miuiCameraManagerClass = Class.forName("android.provider.MiuiSettings$SettingsCloudData$CloudData");
- // Try different constructor signatures that work on Xiaomi
+
Object miuiCameraManager = null;
try {
- // Try default constructor
+
java.lang.reflect.Constructor> constructor = miuiCameraManagerClass.getDeclaredConstructor();
constructor.setAccessible(true);
miuiCameraManager = constructor.newInstance();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiSettingsProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiSettingsProxy.java
index 7570a99..c3662c5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiSettingsProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/IXiaomiSettingsProxy.java
@@ -9,10 +9,7 @@ import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.utils.AttributionSourceUtils;
import top.niunaijun.blackbox.util.XiaomiDeviceDetector;
-/**
- * IXiaomiSettings Proxy to handle MIUI-specific Settings access issues on Android 12+
- * This prevents crashes related to Xiaomi's enhanced security enforcement in system settings
- */
+
public class IXiaomiSettingsProxy extends ClassInvocationStub {
public static final String TAG = "IXiaomiSettingsProxy";
@@ -22,13 +19,13 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- // Return null since this is a global hook, not a specific service
+
return null;
}
@Override
protected void inject(Object base, Object proxy) {
- // This proxy handles Xiaomi-specific Settings access issues globally
+
if (XiaomiDeviceDetector.isXiaomiDevice()) {
Slog.d(TAG, "IXiaomiSettings proxy initialized for MIUI Settings UID mismatch prevention on " +
XiaomiDeviceDetector.getDeviceModel() + " (MIUI " + XiaomiDeviceDetector.getMiuiVersion() + ")");
@@ -42,19 +39,19 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
return false;
}
- // Hook for Settings.System.getStringForUser to fix UID issues on Xiaomi
+
@ProxyMethod("getStringForUser")
public static class GetStringForUser extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "Xiaomi UID mismatch in getStringForUser, returning safe default: " + message);
@@ -63,25 +60,25 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi getStringForUser hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return getSafeDefaultForXiaomiSettings();
}
}
}
- // Hook for Settings.System.getString to fix UID issues on Xiaomi
+
@ProxyMethod("getString")
public static class GetString extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "Xiaomi UID mismatch in getString, returning safe default: " + message);
@@ -90,25 +87,25 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi getString hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return getSafeDefaultForXiaomiSettings();
}
}
}
- // Hook for Settings.System.getIntForUser to fix UID issues on Xiaomi
+
@ProxyMethod("getIntForUser")
public static class GetIntForUser extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "Xiaomi UID mismatch in getIntForUser, returning safe default: " + message);
@@ -117,25 +114,25 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi getIntForUser hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return getSafeDefaultIntForXiaomiSettings();
}
}
}
- // Hook for Settings.System.getInt to fix UID issues on Xiaomi
+
@ProxyMethod("getInt")
public static class GetInt extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "Xiaomi UID mismatch in getInt, returning safe default: " + message);
@@ -144,25 +141,25 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi getInt hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return getSafeDefaultIntForXiaomiSettings();
}
}
}
- // Hook for Settings.Global.getStringForUser to fix UID issues on Xiaomi
+
@ProxyMethod("getStringForUser")
public static class GlobalGetStringForUser extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "Xiaomi UID mismatch in Global.getStringForUser, returning safe default: " + message);
@@ -171,25 +168,25 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi Global.getStringForUser hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return getSafeDefaultForXiaomiSettings();
}
}
}
- // Hook for Settings.Global.getString to fix UID issues on Xiaomi
+
@ProxyMethod("getString")
public static class GlobalGetString extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
- // Fix AttributionSource in args before calling original method
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
- // Call original method
+
return method.invoke(who, args);
} catch (SecurityException e) {
- // Handle SecurityException specifically for UID mismatch on Xiaomi
+
String message = e.getMessage();
if (message != null && message.contains("Calling uid") && message.contains("doesn't match source uid")) {
Slog.w(TAG, "Xiaomi UID mismatch in Global.getString, returning safe default: " + message);
@@ -198,25 +195,21 @@ public class IXiaomiSettingsProxy extends ClassInvocationStub {
throw e;
} catch (Exception e) {
Slog.w(TAG, "Error in Xiaomi Global.getString hook: " + e.getMessage());
- // Return safe default for Xiaomi devices
+
return getSafeDefaultForXiaomiSettings();
}
}
}
- /**
- * Get safe default value for Xiaomi Settings access
- */
+
private static String getSafeDefaultForXiaomiSettings() {
- // Return empty string as safe default for Xiaomi devices
+
return "";
}
- /**
- * Get safe default int value for Xiaomi Settings access
- */
+
private static int getSafeDefaultIntForXiaomiSettings() {
- // Return 0 as safe default for Xiaomi devices
+
return 0;
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/LevelDbProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/LevelDbProxy.java
index eab1927..6f2e348 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/LevelDbProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/LevelDbProxy.java
@@ -7,9 +7,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * LevelDB proxy to handle GMS LevelDB lock issues and database problems.
- */
+
public class LevelDbProxy extends ClassInvocationStub {
public static final String TAG = "LevelDbProxy";
@@ -19,12 +17,12 @@ public class LevelDbProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook LevelDB class methods directly
+
}
@Override
@@ -32,7 +30,7 @@ public class LevelDbProxy extends ClassInvocationStub {
return false;
}
- // Hook LevelDB open method to handle lock issues
+
@ProxyMethod("open")
public static class Open extends MethodHook {
@Override
@@ -43,11 +41,11 @@ public class LevelDbProxy extends ClassInvocationStub {
String message = e.getMessage();
if (message != null && message.contains("lock") && message.contains("Try again")) {
Slog.w(TAG, "LevelDB lock error detected, returning null: " + message);
- // Return null to indicate database is unavailable
+
return null;
} else if (message != null && message.contains("IO error")) {
Slog.w(TAG, "LevelDB IO error detected, returning null: " + message);
- // Return null for IO errors
+
return null;
}
throw e;
@@ -55,7 +53,7 @@ public class LevelDbProxy extends ClassInvocationStub {
}
}
- // Hook LevelDB nativeOpen method to handle native lock issues
+
@ProxyMethod("nativeOpen")
public static class NativeOpen extends MethodHook {
@Override
@@ -66,7 +64,7 @@ public class LevelDbProxy extends ClassInvocationStub {
String message = e.getMessage();
if (message != null && (message.contains("lock") || message.contains("IO error"))) {
Slog.w(TAG, "LevelDB native lock/IO error detected, returning null: " + message);
- // Return null to indicate database is unavailable
+
return null;
}
throw e;
@@ -74,7 +72,7 @@ public class LevelDbProxy extends ClassInvocationStub {
}
}
- // Hook LevelDB get method to handle null database
+
@ProxyMethod("get")
public static class Get extends MethodHook {
@Override
@@ -92,7 +90,7 @@ public class LevelDbProxy extends ClassInvocationStub {
}
}
- // Hook LevelDB put method to handle null database
+
@ProxyMethod("put")
public static class Put extends MethodHook {
@Override
@@ -110,7 +108,7 @@ public class LevelDbProxy extends ClassInvocationStub {
}
}
- // Hook LevelDB delete method to handle null database
+
@ProxyMethod("delete")
public static class Delete extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderClassProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderClassProxy.java
index c5f8602..be8e529 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderClassProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderClassProxy.java
@@ -9,9 +9,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * MediaRecorder class proxy to directly hook MediaRecorder instance methods.
- */
+
public class MediaRecorderClassProxy extends ClassInvocationStub {
public static final String TAG = "MediaRecorderClassProxy";
@@ -21,12 +19,12 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook MediaRecorder class methods directly
+
}
@Override
@@ -34,7 +32,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
return false;
}
- // Hook MediaRecorder constructor
+
@ProxyMethod("")
public static class Constructor extends MethodHook {
@Override
@@ -44,7 +42,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook setAudioSource
+
@ProxyMethod("setAudioSource")
public static class SetAudioSource extends MethodHook {
@Override
@@ -54,7 +52,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook setOutputFormat
+
@ProxyMethod("setOutputFormat")
public static class SetOutputFormat extends MethodHook {
@Override
@@ -64,7 +62,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook setAudioEncoder
+
@ProxyMethod("setAudioEncoder")
public static class SetAudioEncoder extends MethodHook {
@Override
@@ -74,7 +72,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook setOutputFile
+
@ProxyMethod("setOutputFile")
public static class SetOutputFile extends MethodHook {
@Override
@@ -84,7 +82,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook prepare
+
@ProxyMethod("prepare")
public static class Prepare extends MethodHook {
@Override
@@ -94,7 +92,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook start
+
@ProxyMethod("start")
public static class Start extends MethodHook {
@Override
@@ -104,7 +102,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook stop
+
@ProxyMethod("stop")
public static class Stop extends MethodHook {
@Override
@@ -114,7 +112,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook release
+
@ProxyMethod("release")
public static class Release extends MethodHook {
@Override
@@ -124,7 +122,7 @@ public class MediaRecorderClassProxy extends ClassInvocationStub {
}
}
- // Hook reset
+
@ProxyMethod("reset")
public static class Reset extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderProxy.java
index 95c22d3..3484e50 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/MediaRecorderProxy.java
@@ -9,9 +9,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * MediaRecorder proxy to handle audio recording in sandboxed apps.
- */
+
public class MediaRecorderProxy extends ClassInvocationStub {
public static final String TAG = "MediaRecorderProxy";
@@ -21,12 +19,12 @@ public class MediaRecorderProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook MediaRecorder class methods directly
+
}
@Override
@@ -34,7 +32,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
return false;
}
- // Hook MediaRecorder constructor
+
@ProxyMethod("")
public static class Constructor extends MethodHook {
@Override
@@ -44,7 +42,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setAudioSource
+
@ProxyMethod("setAudioSource")
public static class SetAudioSource extends MethodHook {
@Override
@@ -54,7 +52,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setOutputFormat
+
@ProxyMethod("setOutputFormat")
public static class SetOutputFormat extends MethodHook {
@Override
@@ -64,7 +62,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setAudioEncoder
+
@ProxyMethod("setAudioEncoder")
public static class SetAudioEncoder extends MethodHook {
@Override
@@ -74,7 +72,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setOutputFile
+
@ProxyMethod("setOutputFile")
public static class SetOutputFile extends MethodHook {
@Override
@@ -84,7 +82,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook prepare
+
@ProxyMethod("prepare")
public static class Prepare extends MethodHook {
@Override
@@ -94,7 +92,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook start
+
@ProxyMethod("start")
public static class Start extends MethodHook {
@Override
@@ -104,7 +102,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook stop
+
@ProxyMethod("stop")
public static class Stop extends MethodHook {
@Override
@@ -114,7 +112,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook release
+
@ProxyMethod("release")
public static class Release extends MethodHook {
@Override
@@ -124,7 +122,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook reset
+
@ProxyMethod("reset")
public static class Reset extends MethodHook {
@Override
@@ -134,7 +132,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setAudioSamplingRate
+
@ProxyMethod("setAudioSamplingRate")
public static class SetAudioSamplingRate extends MethodHook {
@Override
@@ -144,7 +142,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setAudioChannels
+
@ProxyMethod("setAudioChannels")
public static class SetAudioChannels extends MethodHook {
@Override
@@ -154,7 +152,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setAudioEncodingBitRate
+
@ProxyMethod("setAudioEncodingBitRate")
public static class SetAudioEncodingBitRate extends MethodHook {
@Override
@@ -164,7 +162,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setMaxDuration
+
@ProxyMethod("setMaxDuration")
public static class SetMaxDuration extends MethodHook {
@Override
@@ -174,7 +172,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setMaxFileSize
+
@ProxyMethod("setMaxFileSize")
public static class SetMaxFileSize extends MethodHook {
@Override
@@ -184,7 +182,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setOnErrorListener
+
@ProxyMethod("setOnErrorListener")
public static class SetOnErrorListener extends MethodHook {
@Override
@@ -194,7 +192,7 @@ public class MediaRecorderProxy extends ClassInvocationStub {
}
}
- // Hook setOnInfoListener
+
@ProxyMethod("setOnInfoListener")
public static class SetOnInfoListener extends MethodHook {
@Override
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ReLinkerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ReLinkerProxy.java
index 26070c0..fd87a40 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ReLinkerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ReLinkerProxy.java
@@ -7,9 +7,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * ReLinker proxy to handle com.getkeepsafe.relinker library loading issues.
- */
+
public class ReLinkerProxy extends ClassInvocationStub {
public static final String TAG = "ReLinkerProxy";
@@ -19,12 +17,12 @@ public class ReLinkerProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Not needed for class method hooks
+
}
@Override
@@ -32,20 +30,20 @@ public class ReLinkerProxy extends ClassInvocationStub {
return false;
}
- // Hook ReLinker.loadLibrary() to handle missing libraries
+
@ProxyMethod("loadLibrary")
public static class LoadLibrary extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "ReLinker: loadLibrary called, intercepting to prevent MissingLibraryException");
- // Return null to indicate success without actually loading the library
- // This prevents the MissingLibraryException from being thrown
+
+
return null;
}
}
- // Hook ReLinker.loadLibrary() with context parameter
+
@ProxyMethod("loadLibrary")
public static class LoadLibraryWithContext extends MethodHook {
@Override
@@ -55,12 +53,12 @@ public class ReLinkerProxy extends ClassInvocationStub {
Slog.d(TAG, "ReLinker: loadLibrary called for: " + libraryName);
}
- // Return null to indicate success
+
return null;
}
}
- // Hook ReLinker.loadLibrary() with all parameters
+
@ProxyMethod("loadLibrary")
public static class LoadLibraryWithAllParams extends MethodHook {
@Override
@@ -71,7 +69,7 @@ public class ReLinkerProxy extends ClassInvocationStub {
Slog.d(TAG, "ReLinker: loadLibrary called for: " + libraryName + " version: " + version);
}
- // Return null to indicate success
+
return null;
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ResourcesManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ResourcesManagerProxy.java
index e4cfc03..0a18dce 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ResourcesManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/ResourcesManagerProxy.java
@@ -8,9 +8,7 @@ import top.niunaijun.blackbox.fake.hook.ClassInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * Proxy for ResourcesManager to block problematic resource loading
- */
+
public class ResourcesManagerProxy extends ClassInvocationStub {
public static final String TAG = "ResourcesManagerProxy";
@@ -26,12 +24,12 @@ public class ResourcesManagerProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // This is a static hook, not an instance hook
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // This is a static hook, no injection needed
+
}
@Override
@@ -50,18 +48,18 @@ public class ResourcesManagerProxy extends ClassInvocationStub {
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String path = (String) args[0];
- // Block problematic resource paths
+
if (path != null && (path.contains("resource-cache") ||
path.contains("@idmap") ||
path.contains(".frro") ||
path.contains("systemui") ||
path.contains("data@resource-cache@"))) {
Log.d(TAG, "Blocking problematic ApkAssets load: " + path);
- // Return null or throw exception to prevent loading
+
return null;
}
- // For non-problematic paths, proceed normally
+
return method.invoke(who, args);
}
}
@@ -72,18 +70,18 @@ public class ResourcesManagerProxy extends ClassInvocationStub {
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
String path = (String) args[0];
- // Block problematic overlay paths
+
if (path != null && (path.contains("resource-cache") ||
path.contains("@idmap") ||
path.contains(".frro") ||
path.contains("systemui") ||
path.contains("data@resource-cache@"))) {
Log.d(TAG, "Blocking problematic overlay path: " + path);
- // Return null to prevent loading
+
return null;
}
- // For non-problematic paths, proceed normally
+
return method.invoke(who, args);
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SQLiteDatabaseProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SQLiteDatabaseProxy.java
index e58272b..21a6c98 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SQLiteDatabaseProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SQLiteDatabaseProxy.java
@@ -10,9 +10,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * SQLiteDatabase proxy to handle database-related issues in sandboxed apps.
- */
+
public class SQLiteDatabaseProxy extends ClassInvocationStub {
public static final String TAG = "SQLiteDatabaseProxy";
@@ -22,12 +20,12 @@ public class SQLiteDatabaseProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Hook SQLiteDatabase class methods directly
+
}
@Override
@@ -35,7 +33,7 @@ public class SQLiteDatabaseProxy extends ClassInvocationStub {
return false;
}
- // Hook rawQuery to handle missing tables gracefully
+
@ProxyMethod("rawQuery")
public static class RawQuery extends MethodHook {
@Override
@@ -44,7 +42,7 @@ public class SQLiteDatabaseProxy extends ClassInvocationStub {
String sql = (String) args[0];
if (sql != null && sql.contains("DurableJob")) {
Slog.w(TAG, "SQLiteDatabase: rawQuery called with DurableJob table, returning empty cursor");
- // Return an empty cursor instead of crashing
+
return null;
}
return method.invoke(who, args);
@@ -58,7 +56,7 @@ public class SQLiteDatabaseProxy extends ClassInvocationStub {
}
}
- // Hook query to handle missing tables gracefully
+
@ProxyMethod("query")
public static class Query extends MethodHook {
@Override
@@ -67,7 +65,7 @@ public class SQLiteDatabaseProxy extends ClassInvocationStub {
String table = (String) args[0];
if (table != null && table.equals("DurableJob")) {
Slog.w(TAG, "SQLiteDatabase: query called on DurableJob table, returning empty cursor");
- // Return an empty cursor instead of crashing
+
return null;
}
return method.invoke(who, args);
@@ -81,7 +79,7 @@ public class SQLiteDatabaseProxy extends ClassInvocationStub {
}
}
- // Hook execSQL to handle missing tables gracefully
+
@ProxyMethod("execSQL")
public static class ExecSQL extends MethodHook {
@Override
@@ -90,7 +88,7 @@ public class SQLiteDatabaseProxy extends ClassInvocationStub {
String sql = (String) args[0];
if (sql != null && sql.contains("DurableJob")) {
Slog.w(TAG, "SQLiteDatabase: execSQL called with DurableJob table, ignoring");
- // Ignore DurableJob table operations
+
return null;
}
return method.invoke(who, args);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/StubHelper.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/StubHelper.java
index ee9a3ba..2c1f1de 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/StubHelper.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/StubHelper.java
@@ -7,38 +7,29 @@ import java.lang.reflect.Method;
import black.android.os.BRServiceManager;
-/**
- * Helper class to handle missing generated stub classes
- * Created to fix crashes caused by missing BR*Stub classes
- */
+
public class StubHelper {
private static final String TAG = "StubHelper";
- /**
- * Get a service interface using the generated stub class or fallback to reflection
- * @param serviceName The name of the service
- * @param stubClassName The expected generated stub class name
- * @param realStubClassName The real Android stub class name
- * @return The service interface or null if all attempts fail
- */
+
public static Object getServiceInterface(String serviceName, String stubClassName, String realStubClassName) {
try {
- // Try to use the generated class first
+
Class> stubClass = Class.forName(stubClassName);
Method getMethod = stubClass.getMethod("get");
Object stub = getMethod.invoke(null);
- // Try different method signatures for asInterface
+
Method asInterfaceMethod = null;
try {
- // Try with IBinder parameter
+
asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class);
} catch (NoSuchMethodException e1) {
try {
- // Try with Object parameter (some generated classes use Object)
+
asInterfaceMethod = stubClass.getMethod("asInterface", Object.class);
} catch (NoSuchMethodException e2) {
- // Try with any parameter type
+
Method[] methods = stubClass.getMethods();
for (Method method : methods) {
if (method.getName().equals("asInterface") && method.getParameterCount() == 1) {
@@ -59,7 +50,7 @@ public class StubHelper {
Log.w(TAG, "Failed to use generated stub class: " + stubClassName, e);
}
- // Fallback: use reflection to get the real service
+
try {
IBinder binder = BRServiceManager.get().getService(serviceName);
Class> stubClass = Class.forName(realStubClassName);
@@ -71,32 +62,25 @@ public class StubHelper {
}
}
- /**
- * Get a service interface using the generated stub class or fallback to reflection
- * @param serviceName The name of the service
- * @param stubClassName The expected generated stub class name
- * @param realStubClassName The real Android stub class name
- * @param binder The IBinder to use (if not null, serviceName is ignored)
- * @return The service interface or null if all attempts fail
- */
+
public static Object getServiceInterface(String serviceName, String stubClassName, String realStubClassName, IBinder binder) {
try {
- // Try to use the generated class first
+
Class> stubClass = Class.forName(stubClassName);
Method getMethod = stubClass.getMethod("get");
Object stub = getMethod.invoke(null);
- // Try different method signatures for asInterface
+
Method asInterfaceMethod = null;
try {
- // Try with IBinder parameter
+
asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class);
} catch (NoSuchMethodException e1) {
try {
- // Try with Object parameter (some generated classes use Object)
+
asInterfaceMethod = stubClass.getMethod("asInterface", Object.class);
} catch (NoSuchMethodException e2) {
- // Try with any parameter type
+
Method[] methods = stubClass.getMethods();
for (Method method : methods) {
if (method.getName().equals("asInterface") && method.getParameterCount() == 1) {
@@ -117,7 +101,7 @@ public class StubHelper {
Log.w(TAG, "Failed to use generated stub class: " + stubClassName, e);
}
- // Fallback: use reflection to get the real service
+
try {
IBinder serviceBinder = binder != null ? binder : BRServiceManager.get().getService(serviceName);
Class> stubClass = Class.forName(realStubClassName);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SystemLibraryProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SystemLibraryProxy.java
index b6a2bd7..2a58830 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SystemLibraryProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/SystemLibraryProxy.java
@@ -7,9 +7,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * System library proxy to handle native library loading issues in sandboxed apps.
- */
+
public class SystemLibraryProxy extends ClassInvocationStub {
public static final String TAG = "SystemLibraryProxy";
@@ -19,12 +17,12 @@ public class SystemLibraryProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Not needed for class method hooks
+
}
@Override
@@ -32,7 +30,7 @@ public class SystemLibraryProxy extends ClassInvocationStub {
return false;
}
- // Hook System.loadLibrary() to handle missing libraries
+
@ProxyMethod("loadLibrary")
public static class LoadLibrary extends MethodHook {
@Override
@@ -41,24 +39,24 @@ public class SystemLibraryProxy extends ClassInvocationStub {
String libraryName = (String) args[0];
Slog.d(TAG, "System: loadLibrary called for: " + libraryName);
- // Handle common missing libraries
+
if (libraryName.equals("c++_shared") || libraryName.contains("c++")) {
Slog.d(TAG, "System: Intercepting c++ library load, returning success");
- return null; // Return null to indicate success
+ return null;
}
if (libraryName.contains("flutter") || libraryName.contains("meemo")) {
Slog.d(TAG, "System: Intercepting Flutter/Meemo library load, returning success");
- return null; // Return null to indicate success
+ return null;
}
}
- // For other libraries, proceed normally
+
return method.invoke(who, args);
}
}
- // Hook System.load() for absolute path library loading
+
@ProxyMethod("load")
public static class Load extends MethodHook {
@Override
@@ -67,19 +65,19 @@ public class SystemLibraryProxy extends ClassInvocationStub {
String libraryPath = (String) args[0];
Slog.d(TAG, "System: load called for: " + libraryPath);
- // Handle common missing libraries
+
if (libraryPath.contains("libc++_shared.so") || libraryPath.contains("c++_shared")) {
Slog.d(TAG, "System: Intercepting libc++_shared.so load, returning success");
- return null; // Return null to indicate success
+ return null;
}
if (libraryPath.contains("flutter") || libraryPath.contains("meemo")) {
Slog.d(TAG, "System: Intercepting Flutter/Meemo library load, returning success");
- return null; // Return null to indicate success
+ return null;
}
}
- // For other libraries, proceed normally
+
return method.invoke(who, args);
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/VpnCommonProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/VpnCommonProxy.java
index 1b4c04f..d3c8a1a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/VpnCommonProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/VpnCommonProxy.java
@@ -12,9 +12,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.proxy.ProxyVpnService;
import top.niunaijun.blackbox.utils.MethodParameterUtils;
-/**
- * Created by BlackBox on 2022/2/26.
- */
+
public class VpnCommonProxy {
@ProxyMethod("setVpnPackageAuthorization")
public static class setVpnPackageAuthorization extends MethodHook {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewFactoryProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewFactoryProxy.java
index b70135b..3cfee00 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewFactoryProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewFactoryProxy.java
@@ -13,10 +13,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * WebView Factory proxy to handle WebView initialization, provider selection,
- * and factory-related issues that commonly cause WebView problems.
- */
+
public class WebViewFactoryProxy extends ClassInvocationStub {
public static final String TAG = "WebViewFactoryProxy";
@@ -26,12 +23,12 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Not needed for class method hooks
+
}
@Override
@@ -39,7 +36,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
return false;
}
- // Hook WebViewFactory.getWebViewProviderClass() to return a valid provider
+
@ProxyMethod("getWebViewProviderClass")
public static class GetWebViewProviderClass extends MethodHook {
@Override
@@ -47,7 +44,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewFactory: getWebViewProviderClass called");
try {
- // Try to get the WebView provider class from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView provider class");
@@ -57,7 +54,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView provider class", e);
}
- // Return the default WebView provider class
+
try {
Class> webViewClass = WebView.class;
Slog.d(TAG, "WebViewFactory: Returning default WebView class: " + webViewClass.getName());
@@ -69,7 +66,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
}
}
- // Hook WebViewFactory.getWebViewProviderPackage() to return a valid package
+
@ProxyMethod("getWebViewProviderPackage")
public static class GetWebViewProviderPackage extends MethodHook {
@Override
@@ -77,7 +74,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewFactory: getWebViewProviderPackage called");
try {
- // Try to get the WebView provider package from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView provider package");
@@ -87,14 +84,14 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView provider package", e);
}
- // Return a default WebView package name
+
String defaultPackage = "com.google.android.webview";
Slog.d(TAG, "WebViewFactory: Returning default WebView package: " + defaultPackage);
return defaultPackage;
}
}
- // Hook WebViewFactory.getWebViewProviderInfo() to return provider information
+
@ProxyMethod("getWebViewProviderInfo")
public static class GetWebViewProviderInfo extends MethodHook {
@Override
@@ -102,7 +99,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewFactory: getWebViewProviderInfo called");
try {
- // Try to get the WebView provider info from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView provider info");
@@ -112,23 +109,23 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView provider info", e);
}
- // Return null to let the system use default
+
Slog.d(TAG, "WebViewFactory: Returning null to use system default");
return null;
}
}
- // Hook WebViewFactory.isWebViewSupported() to return true
+
@ProxyMethod("isWebViewSupported")
public static class IsWebViewSupported extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
Slog.d(TAG, "WebViewFactory: isWebViewSupported called, returning true");
- return true; // Always indicate WebView is supported
+ return true;
}
}
- // Hook WebViewFactory.getWebViewPackage() to return a valid package
+
@ProxyMethod("getWebViewPackage")
public static class GetWebViewPackage extends MethodHook {
@Override
@@ -136,7 +133,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewFactory: getWebViewPackage called");
try {
- // Try to get the WebView package from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView package");
@@ -146,14 +143,14 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView package", e);
}
- // Return a default WebView package
+
String defaultPackage = "com.google.android.webview";
Slog.d(TAG, "WebViewFactory: Returning default WebView package: " + defaultPackage);
return defaultPackage;
}
}
- // Hook WebViewFactory.getWebViewProviderClassLoader() to return a valid class loader
+
@ProxyMethod("getWebViewProviderClassLoader")
public static class GetWebViewProviderClassLoader extends MethodHook {
@Override
@@ -161,7 +158,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewFactory: getWebViewProviderClassLoader called");
try {
- // Try to get the WebView provider class loader from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView provider class loader");
@@ -171,7 +168,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView provider class loader", e);
}
- // Return the current class loader as fallback
+
try {
ClassLoader classLoader = WebView.class.getClassLoader();
Slog.d(TAG, "WebViewFactory: Returning current class loader: " + classLoader);
@@ -183,7 +180,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
}
}
- // Hook WebViewFactory.getWebViewProviderPackageInfo() to return package info
+
@ProxyMethod("getWebViewProviderPackageInfo")
public static class GetWebViewProviderPackageInfo extends MethodHook {
@Override
@@ -191,7 +188,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.d(TAG, "WebViewFactory: getWebViewProviderPackageInfo called");
try {
- // Try to get the WebView provider package info from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView provider package info");
@@ -201,13 +198,13 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView provider package info", e);
}
- // Return null to let the system use default
+
Slog.d(TAG, "WebViewFactory: Returning null to use system default");
return null;
}
}
- // Hook WebViewFactory.getWebViewProviderClass() with package name parameter
+
@ProxyMethod("getWebViewProviderClass")
public static class GetWebViewProviderClassWithPackage extends MethodHook {
@Override
@@ -218,7 +215,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
}
try {
- // Try to get the WebView provider class from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView provider class");
@@ -228,7 +225,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView provider class", e);
}
- // Return the default WebView class
+
try {
Class> webViewClass = WebView.class;
Slog.d(TAG, "WebViewFactory: Returning default WebView class: " + webViewClass.getName());
@@ -240,7 +237,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
}
}
- // Hook WebViewFactory.getWebViewProviderClassLoader() with package name parameter
+
@ProxyMethod("getWebViewProviderClassLoader")
public static class GetWebViewProviderClassLoaderWithPackage extends MethodHook {
@Override
@@ -251,7 +248,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
}
try {
- // Try to get the WebView provider class loader from the system
+
Object result = method.invoke(who, args);
if (result != null) {
Slog.d(TAG, "WebViewFactory: Successfully got WebView provider class loader");
@@ -261,7 +258,7 @@ public class WebViewFactoryProxy extends ClassInvocationStub {
Slog.w(TAG, "WebViewFactory: Failed to get WebView provider class loader", e);
}
- // Return the current class loader as fallback
+
try {
ClassLoader classLoader = WebView.class.getClassLoader();
Slog.d(TAG, "WebViewFactory: Returning current class loader: " + classLoader);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java
index 6d697e3..e356e0d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WebViewProxy.java
@@ -17,10 +17,7 @@ import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
import top.niunaijun.blackbox.app.BActivityThread;
-/**
- * Enhanced WebView proxy to handle WebView data directory conflicts, initialization issues,
- * and provide comprehensive WebView support in virtual environments.
- */
+
public class WebViewProxy extends ClassInvocationStub {
public static final String TAG = "WebViewProxy";
@@ -28,22 +25,15 @@ public class WebViewProxy extends ClassInvocationStub {
super();
}
- /**
- * getWho() returns null and inject() is empty because this class hooks
- * instance/static methods on WebView class itself, NOT a system service binder.
- *
- * Unlike binder proxies (e.g., IActivityManagerProxy) that replace services
- * in ServiceManager.sCache, class proxies use @ProxyMethod inner classes
- * to intercept specific methods via reflection/instrumentation.
- */
+
@Override
protected Object getWho() {
- return null; // Not needed for class method hooks
+ return null;
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Not needed for class method hooks
+
}
@Override
@@ -51,7 +41,7 @@ public class WebViewProxy extends ClassInvocationStub {
return false;
}
- // Hook WebView constructor to handle data directory conflicts
+
@ProxyMethod("")
public static class Constructor extends MethodHook {
@Override
@@ -66,19 +56,19 @@ public class WebViewProxy extends ClassInvocationStub {
}
if (context != null) {
- // Create unique WebView data directory for this virtual app
+
String packageName = context.getPackageName();
String userId = String.valueOf(BActivityThread.getUserId());
String uniqueDataDir = context.getApplicationInfo().dataDir + "/webview_" + userId + "_" + android.os.Process.myPid();
- // Ensure the directory exists
+
File dataDir = new File(uniqueDataDir);
if (!dataDir.exists()) {
dataDir.mkdirs();
Slog.d(TAG, "WebView: Created unique data directory: " + uniqueDataDir);
}
- // Set system properties for WebView
+
System.setProperty("webview.data.dir", uniqueDataDir);
System.setProperty("webview.cache.dir", uniqueDataDir + "/cache");
System.setProperty("webview.cookies.dir", uniqueDataDir + "/cookies");
@@ -86,19 +76,19 @@ public class WebViewProxy extends ClassInvocationStub {
Slog.d(TAG, "WebView: Set custom data directory: " + uniqueDataDir);
}
- // Proceed with normal constructor
+
Object result = method.invoke(who, args);
if (result instanceof WebView) {
WebView webView = (WebView) result;
- // Configure WebView for better compatibility
+
configureWebView(webView);
}
return result;
} catch (Exception e) {
Slog.w(TAG, "WebView: Constructor failed, attempting fallback", e);
- // Try to create a minimal WebView
+
return createFallbackWebView(context);
}
}
@@ -107,18 +97,18 @@ public class WebViewProxy extends ClassInvocationStub {
try {
WebSettings settings = webView.getSettings();
if (settings != null) {
- // Enable JavaScript
+
settings.setJavaScriptEnabled(true);
- // Enable DOM storage
+
settings.setDomStorageEnabled(true);
- // Enable database
+
settings.setDatabaseEnabled(true);
- // Set cache mode
+
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
- // Enable AppCache (Restored per user request, deprecated/removed in new SDKs)
+
try {
- // Use reflection because methods are removed in API 33+ SDK
+
Method setAppCacheEnabled = settings.getClass().getMethod("setAppCacheEnabled", boolean.class);
setAppCacheEnabled.invoke(settings, true);
@@ -127,43 +117,43 @@ public class WebViewProxy extends ClassInvocationStub {
setAppCachePath.invoke(settings, webView.getContext().getCacheDir().getAbsolutePath());
}
} catch (Throwable e) {
- // Method missing on newer Android versions/SDKs, ignore
+
Slog.w(TAG, "WebView: AppCache not supported: " + e.getMessage());
}
- // CRITICAL: Enable network access explicitly
+
settings.setBlockNetworkLoads(false);
settings.setBlockNetworkImage(false);
- // Enable file access for local resources
+
settings.setAllowFileAccess(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
settings.setAllowFileAccessFromFileURLs(true);
settings.setAllowUniversalAccessFromFileURLs(true);
}
- // Enable mixed content (for HTTPS sites with HTTP resources)
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
- // Set user agent
+
String userAgent = settings.getUserAgentString();
if (userAgent != null && !userAgent.contains("BlackBox")) {
settings.setUserAgentString(userAgent + " BlackBox");
}
- // Force network available
+
try {
webView.setNetworkAvailable(true);
} catch (Exception e) {
- // Ignore
+
}
- // Allow content access
+
settings.setAllowContentAccess(true);
- // Disable safe browsing (API 26+) - often fails in sandbox
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settings.setSafeBrowsingEnabled(false);
}
@@ -178,7 +168,7 @@ public class WebViewProxy extends ClassInvocationStub {
private WebView createFallbackWebView(Context context) {
try {
if (context != null) {
- // Create a minimal WebView with basic configuration
+
WebView webView = new WebView(context);
WebSettings settings = webView.getSettings();
if (settings != null) {
@@ -195,7 +185,7 @@ public class WebViewProxy extends ClassInvocationStub {
}
}
- // Hook WebView.setDataDirectorySuffix() to prevent conflicts
+
@ProxyMethod("setDataDirectorySuffix")
public static class SetDataDirectorySuffix extends MethodHook {
@Override
@@ -205,7 +195,7 @@ public class WebViewProxy extends ClassInvocationStub {
String suffix = (String) args[0];
Slog.d(TAG, "WebView: setDataDirectorySuffix called with: " + suffix);
- // Create a unique suffix for each virtual app and process
+
Context context = BlackBoxCore.getContext();
String packageName = context != null ? context.getPackageName() : "unknown";
String userId = String.valueOf(BActivityThread.getUserId());
@@ -217,12 +207,12 @@ public class WebViewProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WebView: setDataDirectorySuffix failed, continuing without suffix", e);
- return null; // Return null to indicate success
+ return null;
}
}
}
- // Hook WebView.getDataDirectory() to return unique directory
+
@ProxyMethod("getDataDirectory")
public static class GetDataDirectory extends MethodHook {
@Override
@@ -230,14 +220,14 @@ public class WebViewProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "WebView: getDataDirectory called, returning unique directory");
- // Return a unique data directory for each virtual app and process
+
Context context = BlackBoxCore.getContext();
if (context != null) {
String packageName = context.getPackageName();
String userId = String.valueOf(BActivityThread.getUserId());
String uniqueDir = context.getApplicationInfo().dataDir + "/webview_" + userId + "_" + android.os.Process.myPid();
- // Ensure directory exists
+
File dir = new File(uniqueDir);
if (!dir.exists()) {
dir.mkdirs();
@@ -250,13 +240,13 @@ public class WebViewProxy extends ClassInvocationStub {
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WebView: getDataDirectory failed, returning fallback", e);
- // Return a safe fallback directory
+
return "/data/data/" + BlackBoxCore.getHostPkg() + "/webview_fallback";
}
}
}
- // Hook WebViewDatabase.getInstance() to prevent conflicts
+
@ProxyMethod("getInstance")
public static class GetWebViewDatabaseInstance extends MethodHook {
@Override
@@ -264,15 +254,15 @@ public class WebViewProxy extends ClassInvocationStub {
Slog.d(TAG, "WebView: getInstance called for WebViewDatabase");
try {
- // Get the context from BlackBox
+
Context context = BlackBoxCore.getContext();
if (context != null) {
- // Create a unique database instance
+
String packageName = context.getPackageName();
String userId = String.valueOf(BActivityThread.getUserId());
String uniqueDbPath = context.getApplicationInfo().dataDir + "/webview_db_" + userId + "_" + android.os.Process.myPid();
- // Set database path
+
System.setProperty("webview.database.path", uniqueDbPath);
Slog.d(TAG, "WebView: Set unique database path: " + uniqueDbPath);
}
@@ -285,7 +275,7 @@ public class WebViewProxy extends ClassInvocationStub {
}
}
- // Hook WebView.loadUrl() to handle common issues
+
@ProxyMethod("loadUrl")
public static class LoadUrl extends MethodHook {
@Override
@@ -294,9 +284,9 @@ public class WebViewProxy extends ClassInvocationStub {
String url = (String) args[0];
Slog.d(TAG, "WebView: loadUrl called with: " + url);
- // Handle common URL issues
+
if (url != null && url.startsWith("file://")) {
- // Ensure file URLs work in virtual environment
+
Slog.d(TAG, "WebView: Handling file URL: " + url);
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WorkManagerProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WorkManagerProxy.java
index 457403a..8562a33 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WorkManagerProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/WorkManagerProxy.java
@@ -11,10 +11,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * WorkManager Proxy to handle WorkManager-specific job scheduling issues
- * This prevents UID validation crashes when WorkManager tries to schedule background jobs
- */
+
public class WorkManagerProxy extends ClassInvocationStub {
public static final String TAG = "WorkManagerProxy";
@@ -27,7 +24,7 @@ public class WorkManagerProxy extends ClassInvocationStub {
try {
Context context = BlackBoxCore.getContext();
if (context != null) {
- // Try to get the real WorkManager instance
+
Class> workManagerClass = Class.forName("androidx.work.WorkManager");
Method getInstanceMethod = workManagerClass.getMethod("getInstance", Context.class);
return getInstanceMethod.invoke(null, context);
@@ -40,7 +37,7 @@ public class WorkManagerProxy extends ClassInvocationStub {
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
- // Not needed for class method hooks
+
}
@Override
@@ -48,9 +45,7 @@ public class WorkManagerProxy extends ClassInvocationStub {
return false;
}
- /**
- * Hook WorkManager.enqueue() to handle UID validation issues
- */
+
@ProxyMethod("enqueue")
public static class Enqueue extends MethodHook {
@Override
@@ -58,7 +53,7 @@ public class WorkManagerProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "WorkManager: enqueue() called");
- // Log the arguments for debugging
+
if (args != null) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
@@ -67,23 +62,23 @@ public class WorkManagerProxy extends ClassInvocationStub {
}
}
- // Try to proceed with the original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WorkManager: enqueue() failed, returning mock result", e);
- // Return a mock result to prevent crashes
+
return createMockWorkResult();
}
}
private Object createMockWorkResult() {
try {
- // Try to create a mock WorkResult object
+
Class> workResultClass = Class.forName("androidx.work.Operation");
- // Return a mock operation that indicates success
- return null; // Placeholder - would need proper mock implementation
+
+ return null;
} catch (Exception e) {
Slog.w(TAG, "WorkManager: Failed to create mock result", e);
return null;
@@ -91,9 +86,7 @@ public class WorkManagerProxy extends ClassInvocationStub {
}
}
- /**
- * Hook WorkManager.enqueueUniqueWork() to handle UID validation issues
- */
+
@ProxyMethod("enqueueUniqueWork")
public static class EnqueueUniqueWork extends MethodHook {
@Override
@@ -101,29 +94,29 @@ public class WorkManagerProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "WorkManager: enqueueUniqueWork() called");
- // Log the arguments for debugging
+
if (args != null && args.length > 0) {
String workName = (String) args[0];
Slog.d(TAG, "WorkManager: Unique work name: " + workName);
}
- // Try to proceed with the original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WorkManager: enqueueUniqueWork() failed, returning mock result", e);
- // Return a mock result to prevent crashes
+
return createMockWorkResult();
}
}
private Object createMockWorkResult() {
try {
- // Try to create a mock WorkResult object
+
Class> workResultClass = Class.forName("androidx.work.Operation");
- // Return a mock operation that indicates success
- return null; // Placeholder - would need proper mock implementation
+
+ return null;
} catch (Exception e) {
Slog.w(TAG, "WorkManager: Failed to create mock result", e);
return null;
@@ -131,9 +124,7 @@ public class WorkManagerProxy extends ClassInvocationStub {
}
}
- /**
- * Hook WorkManager.enqueueUniquePeriodicWork() to handle UID validation issues
- */
+
@ProxyMethod("enqueueUniquePeriodicWork")
public static class EnqueueUniquePeriodicWork extends MethodHook {
@Override
@@ -141,29 +132,29 @@ public class WorkManagerProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "WorkManager: enqueueUniquePeriodicWork() called");
- // Log the arguments for debugging
+
if (args != null && args.length > 0) {
String workName = (String) args[0];
Slog.d(TAG, "WorkManager: Periodic work name: " + workName);
}
- // Try to proceed with the original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WorkManager: enqueueUniquePeriodicWork() failed, returning mock result", e);
- // Return a mock result to prevent crashes
+
return createMockWorkResult();
}
}
private Object createMockWorkResult() {
try {
- // Try to create a mock WorkResult object
+
Class> workResultClass = Class.forName("androidx.work.Operation");
- // Return a mock operation that indicates success
- return null; // Placeholder - would need proper mock implementation
+
+ return null;
} catch (Exception e) {
Slog.w(TAG, "WorkManager: Failed to create mock result", e);
return null;
@@ -171,9 +162,7 @@ public class WorkManagerProxy extends ClassInvocationStub {
}
}
- /**
- * Hook WorkManager.cancelAllWork() to handle UID validation issues
- */
+
@ProxyMethod("cancelAllWork")
public static class CancelAllWork extends MethodHook {
@Override
@@ -181,21 +170,19 @@ public class WorkManagerProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "WorkManager: cancelAllWork() called");
- // Try to proceed with the original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WorkManager: cancelAllWork() failed, ignoring", e);
- // Return void (null) for cancel operations
+
return null;
}
}
}
- /**
- * Hook WorkManager.cancelWorkById() to handle UID validation issues
- */
+
@ProxyMethod("cancelWorkById")
public static class CancelWorkById extends MethodHook {
@Override
@@ -203,27 +190,25 @@ public class WorkManagerProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "WorkManager: cancelWorkById() called");
- // Log the work ID for debugging
+
if (args != null && args.length > 0) {
String workId = (String) args[0];
Slog.d(TAG, "WorkManager: Cancelling work ID: " + workId);
}
- // Try to proceed with the original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WorkManager: cancelWorkById() failed, ignoring", e);
- // Return void (null) for cancel operations
+
return null;
}
}
}
- /**
- * Hook WorkManager.getWorkInfos() to handle UID validation issues
- */
+
@ProxyMethod("getWorkInfos")
public static class GetWorkInfos extends MethodHook {
@Override
@@ -231,22 +216,22 @@ public class WorkManagerProxy extends ClassInvocationStub {
try {
Slog.d(TAG, "WorkManager: getWorkInfos() called");
- // Try to proceed with the original method
+
return method.invoke(who, args);
} catch (Exception e) {
Slog.w(TAG, "WorkManager: getWorkInfos() failed, returning empty list", e);
- // Return an empty list to prevent crashes
+
return createEmptyWorkInfoList();
}
}
private Object createEmptyWorkInfoList() {
try {
- // Try to create an empty WorkInfo list
+
Class> workInfoListClass = Class.forName("androidx.work.WorkInfo");
- // Return an empty list
+
return java.util.Collections.emptyList();
} catch (Exception e) {
Slog.w(TAG, "WorkManager: Failed to create empty work info list", e);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/base/UidMethodProxy.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/base/UidMethodProxy.java
index 047c553..6b64d8a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/base/UidMethodProxy.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/base/UidMethodProxy.java
@@ -6,9 +6,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.fake.hook.MethodHook;
-/**
- * Created by BlackBox on 2022/3/5.
- */
+
public class UidMethodProxy extends MethodHook {
private final int index;
private final String name;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/ContentServiceStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/ContentServiceStub.java
index 841a8b6..9b8dfc4 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/ContentServiceStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/ContentServiceStub.java
@@ -8,14 +8,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/6/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ContentServiceStub extends BinderInvocationStub {
public ContentServiceStub() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/RestrictionsManagerStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/RestrictionsManagerStub.java
index 99f1b9d..a5894a4 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/RestrictionsManagerStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/RestrictionsManagerStub.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class RestrictionsManagerStub extends BinderInvocationStub {
public RestrictionsManagerStub() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/BContentProvider.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/BContentProvider.java
index f11c2ba..4f1043f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/BContentProvider.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/BContentProvider.java
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.fake.service.context.providers;
import android.os.IInterface;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public interface BContentProvider {
IInterface wrapper(final IInterface contentProviderProxy, final String appPkg);
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/ContentProviderStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/ContentProviderStub.java
index 404d5fe..65efb71 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/ContentProviderStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/ContentProviderStub.java
@@ -13,14 +13,7 @@ import top.niunaijun.blackbox.utils.Slog;
import android.os.Bundle;
import top.niunaijun.blackbox.utils.AttributionSourceUtils;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ContentProviderStub extends ClassInvocationStub implements BContentProvider {
public static final String TAG = "ContentProviderStub";
private IInterface mBase;
@@ -54,44 +47,44 @@ public class ContentProviderStub extends ClassInvocationStub implements BContent
return method.invoke(mBase, args);
}
- // Get method name first to determine handling logic
+
String methodName = method.getName();
- // For call() method, String args are method names like "GET_global", NOT package names
- // Don't replace them! Only fix AttributionSource
+
+
if ("call".equals(methodName)) {
- // Fix AttributionSource in args (treats Bundle recursively)
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
} else {
- // For other methods like query/insert/update/delete, fix both package names and AttributionSource
+
if (args != null && args.length > 0) {
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof String) {
String strArg = (String) arg;
- // Don't replace system provider authorities
+
if (!isSystemProviderAuthority(strArg)) {
- // Replace package name with the correct one
+
args[i] = mAppPkg;
}
}
}
- // Also fix AttributionSources in any arg position
+
AttributionSourceUtils.fixAttributionSourceInArgs(args);
}
}
- // Pre-validate the call to prevent system-level SecurityException
+
methodName = method.getName();
if (methodName.equals("query") || methodName.equals("insert") ||
methodName.equals("update") || methodName.equals("delete") ||
methodName.equals("bulkInsert") || methodName.equals("call")) {
- // Check if this is likely to cause a UID mismatch
+
try {
return method.invoke(mBase, args);
} catch (Throwable e) {
- // Handle SecurityException and other UID-related errors
+
Throwable cause = e.getCause();
if (isUidMismatchError(cause)) {
Slog.w(TAG, "UID mismatch in ContentProvider call, returning safe default: " + cause.getMessage());
@@ -104,7 +97,7 @@ public class ContentProviderStub extends ClassInvocationStub implements BContent
}
}
- // For call method specifically, always return safe default on any error
+
if (methodName.equals("call")) {
Slog.w(TAG, "Error in call method, returning safe default: " + e.getMessage());
return getSafeDefaultValue(methodName, method.getReturnType());
@@ -114,11 +107,11 @@ public class ContentProviderStub extends ClassInvocationStub implements BContent
}
}
- // For other methods, proceed normally
+
try {
return method.invoke(mBase, args);
} catch (Throwable e) {
- // Handle SecurityException for UID mismatch in any method
+
Throwable cause = e.getCause();
if (isUidMismatchError(cause)) {
Slog.w(TAG, "UID mismatch in " + methodName + ", returning safe default: " + cause.getMessage());
@@ -131,31 +124,31 @@ public class ContentProviderStub extends ClassInvocationStub implements BContent
private Object getSafeDefaultValue(String methodName) {
switch (methodName) {
case "query":
- return null; // Return null cursor
+ return null;
case "insert":
- return null; // Return null URI
+ return null;
case "update":
case "delete":
- return 0; // Return 0 rows affected
+ return 0;
case "bulkInsert":
- return 0; // Return 0 rows inserted
+ return 0;
case "call":
- return new Bundle(); // Return empty Bundle instead of null to prevent NPE
+ return new Bundle();
case "getType":
- return null; // Return null MIME type
+ return null;
case "openFile":
- return null; // Return null ParcelFileDescriptor
+ return null;
case "openAssetFile":
- return null; // Return null AssetFileDescriptor
+ return null;
default:
- return null; // Default fallback
+ return null;
}
}
private boolean isSystemProviderAuthority(String authority) {
if (authority == null) return false;
- // Check for system provider authorities that need special handling
+
return authority.equals("settings") ||
authority.equals("settings_global") ||
authority.equals("settings_system") ||
@@ -165,16 +158,14 @@ public class ContentProviderStub extends ClassInvocationStub implements BContent
authority.startsWith("android.provider.Settings");
}
- /**
- * Enhanced UID mismatch detection and handling
- */
+
private boolean isUidMismatchError(Throwable error) {
if (error == null) return false;
String message = error.getMessage();
if (message == null) return false;
- // Check for UID mismatch patterns
+
return message.contains("Calling uid") &&
message.contains("doesn't match source uid") ||
message.contains("uid") &&
@@ -183,57 +174,53 @@ public class ContentProviderStub extends ClassInvocationStub implements BContent
message.contains("UID mismatch");
}
- /**
- * Get safe default value based on method name and return type
- */
+
private Object getSafeDefaultValue(String methodName, Class> returnType) {
if (returnType == null) {
return getSafeDefaultValue(methodName);
}
- // Return type-specific safe defaults
+
if (returnType == String.class) {
- return "true"; // Safe default for strings
+ return "true";
} else if (returnType == int.class || returnType == Integer.class) {
- return 1; // Safe default for integers
+ return 1;
} else if (returnType == long.class || returnType == Long.class) {
- return 1L; // Safe default for longs
+ return 1L;
} else if (returnType == float.class || returnType == Float.class) {
- return 1.0f; // Safe default for floats
+ return 1.0f;
} else if (returnType == boolean.class || returnType == Boolean.class) {
- return true; // Safe default for booleans
+ return true;
} else if (returnType == Bundle.class) {
- return new Bundle(); // Safe default for bundles
+ return new Bundle();
}
- // Fallback to method-specific defaults
+
return getSafeDefaultValue(methodName);
}
- /**
- * Fix AttributionSource UID to prevent crashes on Android 12+
- */
+
private void fixAttributionSourceUid(Object attributionSource) {
try {
if (attributionSource == null) return;
Class> attributionSourceClass = attributionSource.getClass();
- // Try to find and set the UID field
+
try {
java.lang.reflect.Field uidField = attributionSourceClass.getDeclaredField("mUid");
uidField.setAccessible(true);
uidField.set(attributionSource, BlackBoxCore.getHostUid());
Slog.d(TAG, "Fixed AttributionSource UID via field access");
} catch (NoSuchFieldException e) {
- // Try alternative field names
+
try {
java.lang.reflect.Field uidField = attributionSourceClass.getDeclaredField("uid");
uidField.setAccessible(true);
uidField.set(attributionSource, BlackBoxCore.getHostUid());
Slog.d(TAG, "Fixed AttributionSource UID via alternative field");
} catch (NoSuchFieldException e2) {
- // Try using setter method
+
try {
java.lang.reflect.Method setUidMethod = attributionSourceClass.getDeclaredMethod("setUid", int.class);
setUidMethod.setAccessible(true);
@@ -245,14 +232,14 @@ public class ContentProviderStub extends ClassInvocationStub implements BContent
}
}
- // Also try to fix package name
+
try {
java.lang.reflect.Field packageField = attributionSourceClass.getDeclaredField("mPackageName");
packageField.setAccessible(true);
packageField.set(attributionSource, mAppPkg);
Slog.d(TAG, "Fixed AttributionSource package name");
} catch (Exception e) {
- // Ignore package name fixing errors
+
}
} catch (Exception e) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java
index 6492d70..c3ceb6a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java
@@ -9,14 +9,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.fake.hook.ClassInvocationStub;
import top.niunaijun.blackbox.utils.compat.ContextCompat;
-/**
- * updated by alex5402 on 4/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class SystemProviderStub extends ClassInvocationStub implements BContentProvider {
private IInterface mBase;
@@ -55,15 +48,15 @@ public class SystemProviderStub extends ClassInvocationStub implements BContentP
String methodName = method.getName();
- // For call() method, args[0] is the method name (like "GET_global"), NOT a package name
- // Don't replace it! The method name is essential for Settings provider to work
+
+
if ("call".equals(methodName)) {
- // Only fix AttributionSource in call() args, don't replace method name
+
if (args != null) {
Class> attributionSourceClass = BRAttributionSource.getRealClass();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
- // Check for null - AttributionSource doesn't exist on Android < S (31)
+
if (arg != null && attributionSourceClass != null &&
arg.getClass().getName().equals(attributionSourceClass.getName())) {
ContextCompat.fixAttributionSourceState(arg, BlackBoxCore.getHostUid());
@@ -73,18 +66,18 @@ public class SystemProviderStub extends ClassInvocationStub implements BContentP
return method.invoke(mBase, args);
}
- // For other methods like query/insert/update/delete, we may need to fix package names
+
if (args != null && args.length > 0) {
Object arg = args[0];
if (arg instanceof String) {
String authority = (String) arg;
- // Only replace if it's not a system provider authority
+
if (!isSystemProviderAuthority(authority)) {
args[0] = BlackBoxCore.getHostPkg();
}
} else if (arg != null) {
Class> attrSourceClass = BRAttributionSource.getRealClass();
- // Check for null - AttributionSource doesn't exist on Android < S (31)
+
if (attrSourceClass != null && arg.getClass().getName().equals(attrSourceClass.getName())) {
ContextCompat.fixAttributionSourceState(arg, BlackBoxCore.getHostUid());
}
@@ -95,7 +88,7 @@ public class SystemProviderStub extends ClassInvocationStub implements BContentP
private boolean isSystemProviderAuthority(String authority) {
if (authority == null) return false;
- // Common system provider authorities that should not be replaced
+
return authority.equals("settings") ||
authority.equals("media") ||
authority.equals("downloads") ||
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/libcore/OsStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/libcore/OsStub.java
index ecb6146..5fe9551 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/libcore/OsStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/libcore/OsStub.java
@@ -13,14 +13,7 @@ import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.utils.Reflector;
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class OsStub extends ClassInvocationStub {
public static final String TAG = "OsStub";
private Object mBase;
@@ -57,9 +50,9 @@ public class OsStub extends ClassInvocationStub {
if (args[i] instanceof String && ((String) args[i]).startsWith("/")) {
String orig = (String) args[i];
args[i] = IOCore.get().redirectPath(orig);
-// if (!ObjectsCompat.equals(orig, args[i])) {
-// Log.d(TAG, "redirectPath: " + orig + " => " + args[i]);
-// }
+
+
+
}
}
}
@@ -95,7 +88,7 @@ public class OsStub extends ClassInvocationStub {
private static int getFakeUid(int callUid) {
if (callUid > 0 && callUid <= Process.FIRST_APPLICATION_UID)
return callUid;
-// Log.d(TAG, "getuid: " + BActivityThread.getAppPackageName() + ", " + BActivityThread.getAppUid());
+
if (BActivityThread.isThreadInit() && BActivityThread.currentActivityThread().isInit()) {
return BActivityThread.getBAppId();
} else {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyActivity.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyActivity.java
index 3f7b554..8266c80 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyActivity.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyActivity.java
@@ -15,18 +15,11 @@ import top.niunaijun.blackbox.proxy.record.ProxyActivityRecord;
import top.niunaijun.blackbox.proxy.record.ProxyPendingRecord;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 3/28/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyActivity extends Activity {
public static final String TAG = "ProxyActivity";
- //因为HCallbackProxy已经hook了消息循环拦截了创建消息,所有一般情况下这里不会调用,可能是为了稳定性(消息循环hook失败就会走到这里)
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -34,7 +27,7 @@ public class ProxyActivity extends Activity {
finish();
HookManager.get().checkEnv(HCallbackProxy.class);
-// HookManager.get().checkEnv(AppInstrumentation.class);
+
ProxyActivityRecord record = ProxyActivityRecord.create(getIntent());
if (record.mTarget != null) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyBroadcastReceiver.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyBroadcastReceiver.java
index aa681b7..b6d5cfb 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyBroadcastReceiver.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyBroadcastReceiver.java
@@ -9,9 +9,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.entity.am.PendingResultData;
import top.niunaijun.blackbox.proxy.record.ProxyBroadcastRecord;
-/**
- * Created by BlackBox on 2022/2/25.
- */
+
public class ProxyBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "ProxyBroadcastReceiver";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyContentProvider.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyContentProvider.java
index 5cc96a3..47017f9 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyContentProvider.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyContentProvider.java
@@ -14,14 +14,7 @@ import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.entity.AppConfig;
import top.niunaijun.blackbox.utils.compat.BundleCompat;
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyJobService.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyJobService.java
index 499521b..8b88825 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyJobService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyJobService.java
@@ -7,14 +7,7 @@ import android.content.res.Configuration;
import top.niunaijun.blackbox.app.dispatcher.AppJobServiceDispatcher;
-/**
- * updated by alex5402 on 4/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyJobService extends JobService {
public static final String TAG = "StubJobService";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyManifest.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyManifest.java
index cad42b9..63e8e9d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyManifest.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyManifest.java
@@ -4,14 +4,7 @@ import java.util.Locale;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * updated by alex5402 on 4/1/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyManifest {
public static final int FREE_COUNT = 50;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyPendingActivity.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyPendingActivity.java
index de388b4..e1f57a9 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyPendingActivity.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyPendingActivity.java
@@ -11,14 +11,7 @@ import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.proxy.record.ProxyPendingRecord;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 3/28/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyPendingActivity extends Activity {
public static final String TAG = "ProxyPendingActivity";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyService.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyService.java
index dd56502..9c17fc5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyService.java
@@ -12,14 +12,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.dispatcher.AppServiceDispatcher;
import top.niunaijun.blackbox.utils.compat.BuildCompat;
-/**
- * updated by alex5402 on 3/30/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyService extends Service {
public static final String TAG = "StubService";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java
index b2785bc..0a39e61 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/ProxyVpnService.java
@@ -11,12 +11,7 @@ import android.util.Log;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402
- * Enhanced VPN service for BlackBox to handle network routing and DNS
- * Created by BlackBox on 2022/2/25.\
- * improved 9/15/2025 by alex5404
- */
+
public class ProxyVpnService extends VpnService {
private static final String TAG = "ProxyVpnService";
private static final int NOTIFICATION_ID = 1001;
@@ -38,9 +33,9 @@ public class ProxyVpnService extends VpnService {
Slog.d(TAG, "ProxyVpnService started");
try {
- // CRITICAL: Start foreground immediately to prevent timeout
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
- // Android 14+ requires foreground service type
+
startForeground(NOTIFICATION_ID, createNotification(),
android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
} else {
@@ -49,7 +44,7 @@ public class ProxyVpnService extends VpnService {
Slog.d(TAG, "Foreground service started successfully");
- // Start VPN establishment in background to prevent blocking
+
new Thread(new Runnable() {
@Override
public void run() {
@@ -59,7 +54,7 @@ public class ProxyVpnService extends VpnService {
} catch (Exception e) {
Slog.e(TAG, "Critical error in onStartCommand: " + e.getMessage(), e);
- // If we can't start foreground, stop the service to prevent hanging
+
stopSelf();
return START_NOT_STICKY;
}
@@ -74,9 +69,7 @@ public class ProxyVpnService extends VpnService {
Slog.d(TAG, "ProxyVpnService destroyed");
}
- /**
- * Create notification channel for Android 8.0+
- */
+
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
@@ -94,9 +87,7 @@ public class ProxyVpnService extends VpnService {
}
}
- /**
- * Create notification for foreground service
- */
+
private Notification createNotification() {
Notification.Builder builder;
@@ -115,18 +106,16 @@ public class ProxyVpnService extends VpnService {
.build();
}
- /**
- * Establish VPN interface for proper network routing and DNS handling
- */
+
protected void establishVpn() {
- // Use a timeout to prevent hanging
- final long TIMEOUT_MS = 5000; // 5 seconds timeout
+
+ final long TIMEOUT_MS = 5000;
final long startTime = System.currentTimeMillis();
try {
Slog.d(TAG, "Starting VPN establishment...");
- // Check timeout before proceeding
+
if (System.currentTimeMillis() - startTime > TIMEOUT_MS) {
Slog.w(TAG, "VPN establishment timeout, aborting");
return;
@@ -134,40 +123,40 @@ public class ProxyVpnService extends VpnService {
Builder builder = new Builder();
- // Set VPN interface name
+
builder.setSession("BlackBox VPN");
- // Add network addresses - use a private network range
+
builder.addAddress("10.0.0.2", 32);
- // Add routes for all traffic - this is critical for internet access
- builder.addRoute("0.0.0.0", 0); // Route all IPv4 traffic through VPN
- // Add DNS servers (Google DNS as fallback)
+ builder.addRoute("0.0.0.0", 0);
+
+
builder.addDnsServer("8.8.8.8");
builder.addDnsServer("8.8.4.4");
- // Allow all applications to use this VPN
+
builder.addAllowedApplication(getPackageName());
- // Set session name for debugging
+
builder.setSession("BlackBox Internet Access");
Slog.d(TAG, "VPN builder configured, establishing interface...");
- // Check timeout again before establish
+
if (System.currentTimeMillis() - startTime > TIMEOUT_MS) {
Slog.w(TAG, "VPN establishment timeout before establish(), aborting");
return;
}
- // Establish the VPN interface - this should be fast
+
mVpnInterface = builder.establish();
if (mVpnInterface != null) {
mIsEstablished = true;
Slog.d(TAG, "VPN interface established successfully");
- // Start network monitoring and traffic handling in background
+
startNetworkHandling();
} else {
Slog.e(TAG, "Failed to establish VPN interface - builder.establish() returned null");
@@ -176,19 +165,17 @@ public class ProxyVpnService extends VpnService {
} catch (Exception e) {
Slog.e(TAG, "Error establishing VPN: " + e.getMessage());
e.printStackTrace();
- // Don't let VPN errors crash the service
+
mIsEstablished = false;
}
- // Final timeout check
+
if (System.currentTimeMillis() - startTime > TIMEOUT_MS) {
Slog.w(TAG, "VPN establishment took too long: " + (System.currentTimeMillis() - startTime) + "ms");
}
}
- /**
- * Start network handling thread
- */
+
private void startNetworkHandling() {
if (mNetworkThread != null && mNetworkThread.isAlive()) {
mNetworkThread.interrupt();
@@ -199,16 +186,16 @@ public class ProxyVpnService extends VpnService {
public void run() {
try {
while (mIsEstablished && mVpnInterface != null && !Thread.interrupted()) {
- // Monitor network connectivity
- Thread.sleep(10000); // Check every 10 seconds
- // Log network status
+ Thread.sleep(10000);
+
+
Slog.d(TAG, "VPN interface active, monitoring network...");
- // Check if VPN interface is still valid
+
if (mVpnInterface != null) {
try {
- // This will throw if the interface is closed
+
mVpnInterface.getFd();
} catch (Exception e) {
Slog.w(TAG, "VPN interface appears to be closed, re-establishing...");
@@ -229,23 +216,19 @@ public class ProxyVpnService extends VpnService {
Slog.d(TAG, "Network handling thread started");
}
- /**
- * Re-establish VPN if it was lost
- */
+
private void reestablishVpn() {
try {
Slog.d(TAG, "Attempting to re-establish VPN connection");
stopVpn();
- Thread.sleep(1000); // Wait a bit before re-establishing
+ Thread.sleep(1000);
establishVpn();
} catch (Exception e) {
Slog.e(TAG, "Failed to re-establish VPN: " + e.getMessage());
}
}
- /**
- * Stop VPN service
- */
+
private void stopVpn() {
mIsEstablished = false;
@@ -265,16 +248,12 @@ public class ProxyVpnService extends VpnService {
}
}
- /**
- * Check if VPN is established
- */
+
public boolean isEstablished() {
return mIsEstablished && mVpnInterface != null;
}
- /**
- * Get VPN interface file descriptor
- */
+
public ParcelFileDescriptor getVpnInterface() {
return mVpnInterface;
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/TransparentProxyActivity.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/TransparentProxyActivity.java
index 3d253fa..5da372d 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/TransparentProxyActivity.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/TransparentProxyActivity.java
@@ -1,8 +1,6 @@
package top.niunaijun.blackbox.proxy;
-/**
- * Created by BlackBox on 2022/3/17.
- */
+
public class TransparentProxyActivity extends ProxyActivity {
public static class P0 extends TransparentProxyActivity {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyActivityRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyActivityRecord.java
index 4f324bd..cbde207 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyActivityRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyActivityRecord.java
@@ -6,14 +6,7 @@ import android.os.IBinder;
import top.niunaijun.blackbox.utils.compat.BundleCompat;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyActivityRecord {
public int mUserId;
public ActivityInfo mActivityInfo;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyBroadcastRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyBroadcastRecord.java
index c161b81..b857aaa 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyBroadcastRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyBroadcastRecord.java
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.proxy.record;
import android.content.Intent;
-/**
- * updated by alex5402 on 4/7/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyBroadcastRecord {
public Intent mIntent;
public int mUserId;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyPendingRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyPendingRecord.java
index 32d86a6..708884f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyPendingRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyPendingRecord.java
@@ -2,14 +2,7 @@ package top.niunaijun.blackbox.proxy.record;
import android.content.Intent;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyPendingRecord {
public int mUserId;
public Intent mTarget;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyServiceRecord.java b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyServiceRecord.java
index 313b324..272388a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyServiceRecord.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/proxy/record/ProxyServiceRecord.java
@@ -6,14 +6,7 @@ import android.os.IBinder;
import top.niunaijun.blackbox.utils.compat.BundleCompat;
-/**
- * updated by alex5402 on 4/1/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ProxyServiceRecord {
public Intent mServiceIntent;
public ServiceInfo mServiceInfo;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/util/XiaomiDeviceDetector.java b/Bcore/src/main/java/top/niunaijun/blackbox/util/XiaomiDeviceDetector.java
index 25302f1..c6e7177 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/util/XiaomiDeviceDetector.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/util/XiaomiDeviceDetector.java
@@ -5,25 +5,21 @@ import android.text.TextUtils;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * created by alex5402 to fix crash on xiaomi's MEME Ui
- * Utility class to detect Xiaomi devices and provide device-specific information
- * This helps the Xiaomi proxies apply the correct fixes for different MIUI versions
- */
+
public class XiaomiDeviceDetector {
private static final String TAG = "XiaomiDeviceDetector";
- // Xiaomi device manufacturers
+
private static final String[] XIAOMI_MANUFACTURERS = {
"Xiaomi", "Redmi", "POCO", "Black Shark", "Mi"
};
- // MIUI version patterns
+
private static final String[] MIUI_VERSION_PATTERNS = {
"MIUI", "HyperOS", "MIUI Global", "MIUI China"
};
- // Known Xiaomi device models
+
private static final String[] XIAOMI_MODELS = {
"Mi ", "Redmi ", "POCO ", "Black Shark ", "Xiaomi "
};
@@ -33,16 +29,14 @@ public class XiaomiDeviceDetector {
private static String sDeviceModel = null;
private static int sAndroidVersion = 0;
- /**
- * Check if the current device is a Xiaomi device
- */
+
public static boolean isXiaomiDevice() {
if (sIsXiaomiDevice) {
return true;
}
try {
- // Check manufacturer
+
String manufacturer = Build.MANUFACTURER;
if (isXiaomiManufacturer(manufacturer)) {
sIsXiaomiDevice = true;
@@ -50,7 +44,7 @@ public class XiaomiDeviceDetector {
return true;
}
- // Check brand
+
String brand = Build.BRAND;
if (isXiaomiManufacturer(brand)) {
sIsXiaomiDevice = true;
@@ -58,7 +52,7 @@ public class XiaomiDeviceDetector {
return true;
}
- // Check model
+
String model = Build.MODEL;
if (isXiaomiModel(model)) {
sIsXiaomiDevice = true;
@@ -66,7 +60,7 @@ public class XiaomiDeviceDetector {
return true;
}
- // Check product
+
String product = Build.PRODUCT;
if (isXiaomiModel(product)) {
sIsXiaomiDevice = true;
@@ -74,7 +68,7 @@ public class XiaomiDeviceDetector {
return true;
}
- // Check device
+
String device = Build.DEVICE;
if (isXiaomiModel(device)) {
sIsXiaomiDevice = true;
@@ -82,7 +76,7 @@ public class XiaomiDeviceDetector {
return true;
}
- // Check fingerprint
+
String fingerprint = Build.FINGERPRINT;
if (isXiaomiFingerprint(fingerprint)) {
sIsXiaomiDevice = true;
@@ -90,7 +84,7 @@ public class XiaomiDeviceDetector {
return true;
}
- // Check system properties
+
if (checkXiaomiSystemProperties()) {
sIsXiaomiDevice = true;
Slog.d(TAG, "Detected Xiaomi device by system properties");
@@ -105,9 +99,7 @@ public class XiaomiDeviceDetector {
return false;
}
- /**
- * Get MIUI version if available
- */
+
public static String getMiuiVersion() {
if (sMiuiVersion != null) {
return sMiuiVersion;
@@ -118,21 +110,21 @@ public class XiaomiDeviceDetector {
}
try {
- // Try to get MIUI version from system properties
+
sMiuiVersion = getSystemProperty("ro.miui.ui.version.name");
if (!TextUtils.isEmpty(sMiuiVersion)) {
Slog.d(TAG, "Detected MIUI version: " + sMiuiVersion);
return sMiuiVersion;
}
- // Try alternative property
+
sMiuiVersion = getSystemProperty("ro.miui.version.code");
if (!TextUtils.isEmpty(sMiuiVersion)) {
Slog.d(TAG, "Detected MIUI version code: " + sMiuiVersion);
return sMiuiVersion;
}
- // Try build description
+
String buildDesc = Build.DISPLAY;
if (!TextUtils.isEmpty(buildDesc) && containsMiuiVersion(buildDesc)) {
sMiuiVersion = extractMiuiVersion(buildDesc);
@@ -148,9 +140,7 @@ public class XiaomiDeviceDetector {
return sMiuiVersion;
}
- /**
- * Get device model
- */
+
public static String getDeviceModel() {
if (sDeviceModel != null) {
return sDeviceModel;
@@ -160,9 +150,7 @@ public class XiaomiDeviceDetector {
return sDeviceModel;
}
- /**
- * Get Android version
- */
+
public static int getAndroidVersion() {
if (sAndroidVersion > 0) {
return sAndroidVersion;
@@ -172,9 +160,7 @@ public class XiaomiDeviceDetector {
return sAndroidVersion;
}
- /**
- * Check if device is running MIUI 12 or higher
- */
+
public static boolean isMiui12OrHigher() {
if (!isXiaomiDevice()) {
return false;
@@ -186,7 +172,7 @@ public class XiaomiDeviceDetector {
}
try {
- // Extract version number from MIUI version string
+
String versionNumber = extractVersionNumber(miuiVersion);
if (!TextUtils.isEmpty(versionNumber)) {
int version = Integer.parseInt(versionNumber);
@@ -199,9 +185,7 @@ public class XiaomiDeviceDetector {
return false;
}
- /**
- * Check if device is running MIUI 13 or higher
- */
+
public static boolean isMiui13OrHigher() {
if (!isXiaomiDevice()) {
return false;
@@ -213,7 +197,7 @@ public class XiaomiDeviceDetector {
}
try {
- // Extract version number from MIUI version string
+
String versionNumber = extractVersionNumber(miuiVersion);
if (!TextUtils.isEmpty(versionNumber)) {
int version = Integer.parseInt(versionNumber);
@@ -226,9 +210,7 @@ public class XiaomiDeviceDetector {
return false;
}
- /**
- * Check if device is running HyperOS (MIUI 15+)
- */
+
public static boolean isHyperOS() {
if (!isXiaomiDevice()) {
return false;
@@ -242,9 +224,7 @@ public class XiaomiDeviceDetector {
return miuiVersion.contains("HyperOS") || miuiVersion.contains("OS1.");
}
- /**
- * Get device-specific information for debugging
- */
+
public static String getDeviceInfo() {
StringBuilder info = new StringBuilder();
info.append("Device: ").append(Build.MANUFACTURER).append(" ").append(Build.MODEL).append("\n");
@@ -261,7 +241,7 @@ public class XiaomiDeviceDetector {
return info.toString();
}
- // Private helper methods
+
private static boolean isXiaomiManufacturer(String manufacturer) {
if (TextUtils.isEmpty(manufacturer)) {
@@ -308,7 +288,7 @@ public class XiaomiDeviceDetector {
private static boolean checkXiaomiSystemProperties() {
try {
- // Check for MIUI-specific system properties
+
String miuiProperty = getSystemProperty("ro.miui.ui.version.name");
if (!TextUtils.isEmpty(miuiProperty)) {
return true;
@@ -351,7 +331,7 @@ public class XiaomiDeviceDetector {
return null;
}
- // Try to extract version like "MIUI 14.0.1" or "HyperOS 1.0.0"
+
String[] parts = text.split(" ");
for (int i = 0; i < parts.length - 1; i++) {
if (parts[i].equalsIgnoreCase("MIUI") || parts[i].equalsIgnoreCase("HyperOS")) {
@@ -367,7 +347,7 @@ public class XiaomiDeviceDetector {
return null;
}
- // Extract version number like "14" from "MIUI 14.0.1"
+
String[] parts = miuiVersion.split(" ");
if (parts.length > 1) {
String versionPart = parts[1];
@@ -382,7 +362,7 @@ public class XiaomiDeviceDetector {
private static String getSystemProperty(String key) {
try {
- // Use reflection to access SystemProperties
+
Class> systemPropertiesClass = Class.forName("android.os.SystemProperties");
java.lang.reflect.Method getMethod = systemPropertiesClass.getMethod("get", String.class);
return (String) getMethod.invoke(null, key);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/AbiUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/AbiUtils.java
index dd12fb7..4758283 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/AbiUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/AbiUtils.java
@@ -11,14 +11,7 @@ import java.util.zip.ZipFile;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * updated by alex5402 on 3/2/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class AbiUtils {
private final Set mLibs = new HashSet<>();
private static final Map sAbiUtilsMap = new HashMap<>();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ArrayUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ArrayUtils.java
index fad4c7c..8463800 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ArrayUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ArrayUtils.java
@@ -36,10 +36,7 @@ public class ArrayUtils {
return false;
}
- /**
- * Return first index of {@code value} in {@code array}, or {@code -1} if
- * not found.
- */
+
public static int indexOf(T[] array, T value) {
if (array == null) return -1;
for (int i = 0; i < array.length; i++) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/AttributionSourceUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/AttributionSourceUtils.java
index ff89557..f743cae 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/AttributionSourceUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/AttributionSourceUtils.java
@@ -4,16 +4,11 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * Centralized utility class for fixing AttributionSource UID issues
- * This eliminates code duplication across multiple proxy classes
- */
+
public class AttributionSourceUtils {
private static final String TAG = "AttributionSourceUtils";
- /**
- * Fix AttributionSource objects in method arguments
- */
+
public static void fixAttributionSourceInArgs(Object[] args) {
if (args == null) return;
@@ -29,7 +24,7 @@ public class AttributionSourceUtils {
}
}
- // Also check for Bundle objects that might contain AttributionSource
+
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg != null && arg.getClass().getName().contains("Bundle")) {
@@ -42,16 +37,14 @@ public class AttributionSourceUtils {
}
}
- /**
- * Fix AttributionSource UID
- */
+
public static void fixAttributionSourceUid(Object attributionSource) {
try {
if (attributionSource == null) return;
Class> attributionSourceClass = attributionSource.getClass();
- // Try multiple field names that might exist
+
String[] uidFieldNames = {"mUid", "uid", "mCallingUid", "callingUid", "mSourceUid", "sourceUid"};
for (String fieldName : uidFieldNames) {
@@ -62,21 +55,21 @@ public class AttributionSourceUtils {
Slog.d(TAG, "Fixed AttributionSource UID via field: " + fieldName);
break;
} catch (NoSuchFieldException e) {
- // Continue to next field name
+
}
}
- // Try using setter methods if fields don't work
+
try {
java.lang.reflect.Method setUidMethod = attributionSourceClass.getDeclaredMethod("setUid", int.class);
setUidMethod.setAccessible(true);
setUidMethod.invoke(attributionSource, BlackBoxCore.getHostUid());
Slog.d(TAG, "Fixed AttributionSource UID via setter method");
} catch (Exception e) {
- // Ignore setter method errors
+
}
- // Fix package name
+
String[] packageFieldNames = {"mPackageName", "packageName", "mSourcePackage", "sourcePackage"};
for (String fieldName : packageFieldNames) {
@@ -87,7 +80,7 @@ public class AttributionSourceUtils {
Slog.d(TAG, "Fixed AttributionSource package name via field: " + fieldName);
break;
} catch (NoSuchFieldException e) {
- // Continue to next field name
+
}
}
@@ -96,14 +89,12 @@ public class AttributionSourceUtils {
}
}
- /**
- * Fix AttributionSource objects in Bundle objects
- */
+
public static void fixAttributionSourceInBundle(Object bundle) {
try {
if (bundle == null) return;
- // Try to get the keySet and iterate through values
+
java.lang.reflect.Method keySetMethod = bundle.getClass().getMethod("keySet");
java.util.Set keys = (java.util.Set) keySetMethod.invoke(bundle);
@@ -117,7 +108,7 @@ public class AttributionSourceUtils {
Slog.d(TAG, "Fixed AttributionSource UID in Bundle key: " + key);
}
} catch (Exception e) {
- // Ignore individual key errors
+
}
}
} catch (Exception e) {
@@ -125,30 +116,28 @@ public class AttributionSourceUtils {
}
}
- /**
- * Create a safe AttributionSource object
- */
+
public static Object createSafeAttributionSource() {
try {
- // Try to create a safe AttributionSource using reflection
+
Class> attributionSourceClass = Class.forName("android.content.AttributionSource");
- // Try different constructor signatures
+
Object attributionSource = null;
try {
- // Try constructor with UID and package name
+
java.lang.reflect.Constructor> constructor = attributionSourceClass.getDeclaredConstructor(int.class, String.class);
constructor.setAccessible(true);
attributionSource = constructor.newInstance(BlackBoxCore.getHostUid(), BlackBoxCore.getHostPkg());
} catch (Exception e) {
try {
- // Try default constructor
+
java.lang.reflect.Constructor> constructor = attributionSourceClass.getDeclaredConstructor();
constructor.setAccessible(true);
attributionSource = constructor.newInstance();
- // Set UID and package name using reflection
+
fixAttributionSourceUid(attributionSource);
} catch (Exception e2) {
Slog.w(TAG, "Could not create safe AttributionSource: " + e2.getMessage());
@@ -163,14 +152,12 @@ public class AttributionSourceUtils {
}
}
- /**
- * Enhanced method to handle AttributionSource validation errors
- */
+
public static boolean validateAttributionSource(Object attributionSource) {
try {
if (attributionSource == null) return false;
- // Check if UID is valid
+
Class> attributionSourceClass = attributionSource.getClass();
String[] uidFieldNames = {"mUid", "uid", "mCallingUid", "callingUid", "mSourceUid", "sourceUid"};
@@ -187,11 +174,11 @@ public class AttributionSourceUtils {
}
}
} catch (Exception e) {
- // Continue to next field
+
}
}
- // If validation fails, fix the AttributionSource
+
Slog.w(TAG, "AttributionSource validation failed, attempting to fix");
fixAttributionSourceUid(attributionSource);
return true;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/CloseUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/CloseUtils.java
index 61b574a..ec609d6 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/CloseUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/CloseUtils.java
@@ -3,14 +3,7 @@ package top.niunaijun.blackbox.utils;
import java.io.Closeable;
import java.io.IOException;
-/**
- * Created by sunwanquan on 2019/6/18.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class CloseUtils {
public static void close(Closeable... closeables) {
if (closeables == null) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ContextWrapperHook.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ContextWrapperHook.java
index 44f9b2e..29fcb9a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ContextWrapperHook.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ContextWrapperHook.java
@@ -8,20 +8,16 @@ import top.niunaijun.blackbox.BlackBoxCore;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-/**
- * ContextWrapperHook - Directly hooks ContextWrapper.getResources() to prevent null context crashes
- */
+
public class ContextWrapperHook {
private static final String TAG = "ContextWrapperHook";
- /**
- * Install the ContextWrapper hook to prevent null context crashes
- */
+
public static void installHook() {
try {
Slog.d(TAG, "Installing ContextWrapper hook...");
- // Hook the ContextWrapper.getResources() method
+
hookContextWrapperGetResources();
Slog.d(TAG, "ContextWrapper hook installed successfully");
@@ -30,21 +26,19 @@ public class ContextWrapperHook {
}
}
- /**
- * Hook the ContextWrapper.getResources() method to handle null contexts gracefully
- */
+
private static void hookContextWrapperGetResources() {
try {
- // Get the ContextWrapper class
+
Class> contextWrapperClass = ContextWrapper.class;
- // Get the getResources method
+
Method getResourcesMethod = contextWrapperClass.getDeclaredMethod("getResources");
- // Make the method accessible
+
getResourcesMethod.setAccessible(true);
- // Create a custom implementation that handles null contexts
+
Method customGetResources = ContextWrapperHook.class.getDeclaredMethod("safeGetResources", ContextWrapper.class);
customGetResources.setAccessible(true);
@@ -55,12 +49,10 @@ public class ContextWrapperHook {
}
}
- /**
- * Safe implementation of getResources() that handles null contexts
- */
+
public static Resources safeGetResources(ContextWrapper contextWrapper) {
try {
- // Try to get the base context
+
Context baseContext = contextWrapper.getBaseContext();
if (baseContext != null) {
return baseContext.getResources();
@@ -69,7 +61,7 @@ public class ContextWrapperHook {
Slog.w(TAG, "Error getting resources from base context: " + e.getMessage());
}
- // Fallback to host context resources
+
try {
Context hostContext = BlackBoxCore.getContext();
if (hostContext != null) {
@@ -79,24 +71,22 @@ public class ContextWrapperHook {
Slog.w(TAG, "Error getting host context resources: " + e.getMessage());
}
- // Last resort - return null but don't crash
+
Slog.w(TAG, "All resource fallbacks failed, returning null");
return null;
}
- /**
- * Replace the mBase field in ContextWrapper to ensure it's never null
- */
+
public static void ensureContextWrapperBase(ContextWrapper contextWrapper) {
try {
- // Get the mBase field
+
Field mBaseField = ContextWrapper.class.getDeclaredField("mBase");
mBaseField.setAccessible(true);
- // Get the current base context
+
Context currentBase = (Context) mBaseField.get(contextWrapper);
- // If the base context is null, set it to a safe fallback
+
if (currentBase == null) {
Context fallbackContext = BlackBoxCore.getContext();
if (fallbackContext != null) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/CrashMonitor.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/CrashMonitor.java
index fcf5b11..e26b268 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/CrashMonitor.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/CrashMonitor.java
@@ -23,33 +23,28 @@ import java.util.concurrent.atomic.AtomicInteger;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
-/**
- * Comprehensive crash monitoring and recovery system that detects and handles
- * all types of crashes including Java exceptions, native crashes, and system failures.
- */
+
public class CrashMonitor {
private static final String TAG = "CrashMonitor";
private static boolean sIsInitialized = false;
- // Crash statistics
+
private static final AtomicInteger sTotalCrashes = new AtomicInteger(0);
private static final AtomicInteger sJavaCrashes = new AtomicInteger(0);
private static final AtomicInteger sNativeCrashes = new AtomicInteger(0);
private static final AtomicInteger sRecoveredCrashes = new AtomicInteger(0);
- // Crash history for analysis
+
private static final Map sCrashHistory = new HashMap<>();
- // Recovery strategies
+
private static final Map sRecoveryStrategies = new HashMap<>();
- // Monitoring state
+
private static boolean sIsMonitoring = false;
private static Handler sMainHandler;
- /**
- * Crash information structure
- */
+
public static class CrashInfo {
public final String crashType;
public final String packageName;
@@ -76,9 +71,7 @@ public class CrashMonitor {
}
}
- /**
- * Recovery strategy interface
- */
+
public interface RecoveryStrategy {
String getName();
boolean canHandle(String crashType, String errorMessage);
@@ -86,9 +79,7 @@ public class CrashMonitor {
int getPriority();
}
- /**
- * Initialize the crash monitoring system
- */
+
public static void initialize() {
if (sIsInitialized) {
return;
@@ -97,16 +88,16 @@ public class CrashMonitor {
try {
Slog.d(TAG, "Initializing comprehensive crash monitoring system...");
- // Initialize main handler
+
sMainHandler = new Handler(Looper.getMainLooper());
- // Register recovery strategies
+
registerRecoveryStrategies();
- // Install global crash handlers
+
installGlobalCrashHandlers();
- // Start monitoring
+
startMonitoring();
sIsInitialized = true;
@@ -117,24 +108,22 @@ public class CrashMonitor {
}
}
- /**
- * Register all available recovery strategies
- */
+
private static void registerRecoveryStrategies() {
try {
- // Java exception recovery
+
sRecoveryStrategies.put("JavaException", new JavaExceptionRecovery());
- // Native crash recovery
+
sRecoveryStrategies.put("NativeCrash", new NativeCrashRecovery());
- // DEX corruption recovery
+
sRecoveryStrategies.put("DexCorruption", new DexCorruptionRecovery());
- // WebView crash recovery
+
sRecoveryStrategies.put("WebViewCrash", new WebViewCrashRecovery());
- // Memory crash recovery
+
sRecoveryStrategies.put("MemoryCrash", new MemoryCrashRecovery());
Slog.d(TAG, "Registered " + sRecoveryStrategies.size() + " recovery strategies");
@@ -144,12 +133,10 @@ public class CrashMonitor {
}
}
- /**
- * Install global crash handlers
- */
+
private static void installGlobalCrashHandlers() {
try {
- // Install Java exception handler
+
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
@@ -157,7 +144,7 @@ public class CrashMonitor {
}
});
- // Install system error handler
+
installSystemErrorHandler();
Slog.d(TAG, "Global crash handlers installed");
@@ -167,21 +154,17 @@ public class CrashMonitor {
}
}
- /**
- * Install system error handler
- */
+
private static void installSystemErrorHandler() {
try {
- // This would be implemented with native code for system-level error handling
+
Slog.d(TAG, "System error handler prepared");
} catch (Exception e) {
Slog.w(TAG, "Failed to install system error handler: " + e.getMessage());
}
}
- /**
- * Start crash monitoring
- */
+
private static void startMonitoring() {
if (sIsMonitoring) {
return;
@@ -190,10 +173,10 @@ public class CrashMonitor {
try {
sIsMonitoring = true;
- // Start periodic health checks
+
startPeriodicHealthChecks();
- // Start crash pattern analysis
+
startCrashPatternAnalysis();
Slog.d(TAG, "Crash monitoring started");
@@ -203,63 +186,57 @@ public class CrashMonitor {
}
}
- /**
- * Start periodic health checks
- */
+
private static void startPeriodicHealthChecks() {
if (sMainHandler != null) {
sMainHandler.postDelayed(new Runnable() {
@Override
public void run() {
performHealthCheck();
- // Schedule next health check in 30 seconds
+
sMainHandler.postDelayed(this, 30000);
}
- }, 30000); // First check in 30 seconds
+ }, 30000);
}
}
- /**
- * Start crash pattern analysis
- */
+
private static void startCrashPatternAnalysis() {
if (sMainHandler != null) {
sMainHandler.postDelayed(new Runnable() {
@Override
public void run() {
analyzeCrashPatterns();
- // Schedule next analysis in 60 seconds
+
sMainHandler.postDelayed(this, 60000);
}
- }, 60000); // First analysis in 60 seconds
+ }, 60000);
}
}
- /**
- * Handle a crash event
- */
+
public static void handleCrash(String crashType, Thread thread, Throwable throwable) {
try {
sTotalCrashes.incrementAndGet();
- // Determine crash type
+
if (crashType.equals("JavaException")) {
sJavaCrashes.incrementAndGet();
} else if (crashType.equals("NativeCrash")) {
sNativeCrashes.incrementAndGet();
}
- // Create crash info
+
CrashInfo crashInfo = createCrashInfo(crashType, thread, throwable);
- // Log the crash
+
Slog.w(TAG, "Crash detected: " + crashInfo);
- // Store in history
+
String crashKey = crashType + "_" + System.currentTimeMillis();
sCrashHistory.put(crashKey, crashInfo);
- // Attempt recovery
+
boolean recovered = attemptCrashRecovery(crashInfo);
if (recovered) {
@@ -272,7 +249,7 @@ public class CrashMonitor {
Slog.w(TAG, "Crash recovery failed");
}
- // Write crash log
+
writeCrashLog(crashInfo);
} catch (Exception e) {
@@ -280,9 +257,7 @@ public class CrashMonitor {
}
}
- /**
- * Create crash information from crash event
- */
+
private static CrashInfo createCrashInfo(String crashType, Thread thread, Throwable throwable) {
try {
String packageName = getCurrentPackageName();
@@ -297,9 +272,7 @@ public class CrashMonitor {
}
}
- /**
- * Get current package name
- */
+
private static String getCurrentPackageName() {
try {
return BActivityThread.getAppPackageName();
@@ -310,15 +283,13 @@ public class CrashMonitor {
return context.getPackageName();
}
} catch (Exception ex) {
- // Ignore
+
}
return "unknown";
}
}
- /**
- * Get stack trace as string
- */
+
private static String getStackTrace(Throwable throwable) {
if (throwable == null) return "";
@@ -332,14 +303,12 @@ public class CrashMonitor {
}
}
- /**
- * Attempt to recover from a crash
- */
+
private static boolean attemptCrashRecovery(CrashInfo crashInfo) {
try {
Slog.d(TAG, "Attempting crash recovery for: " + crashInfo.crashType);
- // Find applicable recovery strategies
+
for (RecoveryStrategy strategy : sRecoveryStrategies.values()) {
if (strategy.canHandle(crashInfo.crashType, crashInfo.errorMessage)) {
Slog.d(TAG, "Trying recovery strategy: " + strategy.getName());
@@ -362,9 +331,7 @@ public class CrashMonitor {
}
}
- /**
- * Write crash log to file
- */
+
private static void writeCrashLog(CrashInfo crashInfo) {
try {
Context context = BlackBoxCore.getContext();
@@ -397,14 +364,12 @@ public class CrashMonitor {
}
}
- /**
- * Perform periodic health check
- */
+
private static void performHealthCheck() {
try {
Slog.d(TAG, "Performing periodic health check...");
- // Check memory usage
+
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
long totalMemory = runtime.totalMemory();
@@ -415,10 +380,10 @@ public class CrashMonitor {
if (memoryUsagePercent > 80) {
Slog.w(TAG, "High memory usage detected: " + String.format("%.1f%%", memoryUsagePercent));
- System.gc(); // Force garbage collection
+ System.gc();
}
- // Check thread count
+
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
while (rootGroup.getParent() != null) {
rootGroup = rootGroup.getParent();
@@ -437,9 +402,7 @@ public class CrashMonitor {
}
}
- /**
- * Analyze crash patterns
- */
+
private static void analyzeCrashPatterns() {
try {
if (sCrashHistory.isEmpty()) {
@@ -448,25 +411,25 @@ public class CrashMonitor {
Slog.d(TAG, "Analyzing crash patterns...");
- // Count crashes by type
+
Map crashesByType = new HashMap<>();
Map crashesByPackage = new HashMap<>();
for (CrashInfo crashInfo : sCrashHistory.values()) {
- // Count by type
+
crashesByType.put(crashInfo.crashType,
crashesByType.getOrDefault(crashInfo.crashType, 0) + 1);
- // Count by package
+
crashesByPackage.put(crashInfo.packageName,
crashesByPackage.getOrDefault(crashInfo.packageName, 0) + 1);
}
- // Log patterns
+
Slog.d(TAG, "Crash patterns by type: " + crashesByType);
Slog.d(TAG, "Crash patterns by package: " + crashesByPackage);
- // Check for problematic patterns
+
for (Map.Entry entry : crashesByType.entrySet()) {
if (entry.getValue() > 5) {
Slog.w(TAG, "High crash rate detected for type: " + entry.getKey() +
@@ -479,9 +442,7 @@ public class CrashMonitor {
}
}
- /**
- * Get crash statistics
- */
+
public static String getCrashStats() {
return "Crash Statistics:\n" +
"Total Crashes: " + sTotalCrashes.get() + "\n" +
@@ -493,9 +454,7 @@ public class CrashMonitor {
(double) sRecoveredCrashes.get() / sTotalCrashes.get() * 100 : 0);
}
- /**
- * Get comprehensive crash monitoring status
- */
+
public static String getStatus() {
StringBuilder status = new StringBuilder();
status.append("Crash Monitoring Status:\n");
@@ -508,9 +467,7 @@ public class CrashMonitor {
return status.toString();
}
- /**
- * Clear crash history
- */
+
public static void clearCrashHistory() {
sCrashHistory.clear();
sTotalCrashes.set(0);
@@ -520,11 +477,9 @@ public class CrashMonitor {
Slog.d(TAG, "Crash history cleared");
}
- // Recovery Strategy Implementations
- /**
- * Java exception recovery strategy
- */
+
+
private static class JavaExceptionRecovery implements RecoveryStrategy {
@Override
public String getName() {
@@ -539,8 +494,8 @@ public class CrashMonitor {
@Override
public boolean attemptRecovery(CrashInfo crashInfo) {
try {
- // Use existing crash prevention mechanisms
- return true; // Assume success for now
+
+ return true;
} catch (Exception e) {
Slog.w(TAG, "Java exception recovery failed: " + e.getMessage());
return false;
@@ -553,9 +508,7 @@ public class CrashMonitor {
}
}
- /**
- * Native crash recovery strategy
- */
+
private static class NativeCrashRecovery implements RecoveryStrategy {
@Override
public String getName() {
@@ -570,8 +523,8 @@ public class CrashMonitor {
@Override
public boolean attemptRecovery(CrashInfo crashInfo) {
try {
- // Use native crash prevention mechanisms
- return true; // Assume success for now
+
+ return true;
} catch (Exception e) {
Slog.w(TAG, "Native crash recovery failed: " + e.getMessage());
return false;
@@ -584,9 +537,7 @@ public class CrashMonitor {
}
}
- /**
- * DEX corruption recovery strategy
- */
+
private static class DexCorruptionRecovery implements RecoveryStrategy {
@Override
public String getName() {
@@ -603,8 +554,8 @@ public class CrashMonitor {
@Override
public boolean attemptRecovery(CrashInfo crashInfo) {
try {
- // Use DEX recovery mechanisms
- return true; // Assume success for now
+
+ return true;
} catch (Exception e) {
Slog.w(TAG, "DEX corruption recovery failed: " + e.getMessage());
return false;
@@ -617,9 +568,7 @@ public class CrashMonitor {
}
}
- /**
- * WebView crash recovery strategy
- */
+
private static class WebViewCrashRecovery implements RecoveryStrategy {
@Override
public String getName() {
@@ -636,8 +585,8 @@ public class CrashMonitor {
@Override
public boolean attemptRecovery(CrashInfo crashInfo) {
try {
- // Use WebView recovery mechanisms
- return true; // Assume success for now
+
+ return true;
} catch (Exception e) {
Slog.w(TAG, "WebView crash recovery failed: " + e.getMessage());
return false;
@@ -650,9 +599,7 @@ public class CrashMonitor {
}
}
- /**
- * Memory crash recovery strategy
- */
+
private static class MemoryCrashRecovery implements RecoveryStrategy {
@Override
public String getName() {
@@ -670,7 +617,7 @@ public class CrashMonitor {
@Override
public boolean attemptRecovery(CrashInfo crashInfo) {
try {
- // Force garbage collection
+
System.gc();
return true;
} catch (Exception e) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexCrashPrevention.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexCrashPrevention.java
index 200eba8..7d1abee 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexCrashPrevention.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexCrashPrevention.java
@@ -16,28 +16,22 @@ import java.util.Map;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
-/**
- * Comprehensive crash prevention utility for DEX and ClassLoader related crashes.
- * This class provides proactive prevention and recovery mechanisms for the most common
- * DEX file corruption and ClassLoader failure scenarios.
- */
+
public class DexCrashPrevention {
private static final String TAG = "DexCrashPrevention";
private static boolean sIsInitialized = false;
- // Cache for prevention attempts
+
private static final Map sPreventionCache = new HashMap<>();
- // Known problematic APK patterns
+
private static final String[] PROBLEMATIC_APK_PATTERNS = {
"split_config.xhdpi.apk",
"split_config.arm64_v8a.apk",
"split_config.armeabi_v7a.apk"
};
- /**
- * Prevention result containing the prevention method and success status
- */
+
public static class PreventionResult {
public final String preventionMethod;
public final boolean success;
@@ -58,9 +52,7 @@ public class DexCrashPrevention {
}
}
- /**
- * Initialize DEX crash prevention mechanisms
- */
+
public static void initialize() {
if (sIsInitialized) {
return;
@@ -69,16 +61,16 @@ public class DexCrashPrevention {
try {
Slog.d(TAG, "Initializing DEX crash prevention...");
- // Install proactive prevention mechanisms
+
installProactivePrevention();
- // Install DEX file validation
+
installDexFileValidation();
- // Install ClassLoader monitoring
+
installClassLoaderMonitoring();
- // Install APK integrity checks
+
installApkIntegrityChecks();
sIsInitialized = true;
@@ -89,18 +81,16 @@ public class DexCrashPrevention {
}
}
- /**
- * Install proactive prevention mechanisms
- */
+
private static void installProactivePrevention() {
try {
- // Monitor and prevent common DEX corruption scenarios
+
Slog.d(TAG, "Installing proactive DEX corruption prevention");
- // Set up file system monitoring for APK files
+
setupApkFileMonitoring();
- // Pre-validate critical APK files
+
prevalidateCriticalApkFiles();
} catch (Exception e) {
@@ -108,18 +98,16 @@ public class DexCrashPrevention {
}
}
- /**
- * Set up APK file monitoring
- */
+
private static void setupApkFileMonitoring() {
try {
- // Monitor APK files in the virtual app directories
+
String virtualAppDir = getVirtualAppDirectory();
if (virtualAppDir != null) {
File appDir = new File(virtualAppDir);
if (appDir.exists() && appDir.isDirectory()) {
Slog.d(TAG, "Setting up APK file monitoring for: " + virtualAppDir);
- // In a real implementation, you would set up file system watchers
+
}
}
} catch (Exception e) {
@@ -127,12 +115,10 @@ public class DexCrashPrevention {
}
}
- /**
- * Pre-validate critical APK files
- */
+
private static void prevalidateCriticalApkFiles() {
try {
- // Get the current virtual app's APK files
+
String[] apkFiles = getVirtualAppApkFiles();
if (apkFiles != null) {
for (String apkFile : apkFiles) {
@@ -151,14 +137,12 @@ public class DexCrashPrevention {
}
}
- /**
- * Install DEX file validation
- */
+
private static void installDexFileValidation() {
try {
Slog.d(TAG, "Installing DEX file validation");
- // Hook into DEX file loading to validate before use
+
hookDexFileValidation();
} catch (Exception e) {
@@ -166,27 +150,23 @@ public class DexCrashPrevention {
}
}
- /**
- * Hook DEX file validation
- */
+
private static void hookDexFileValidation() {
try {
- // This would be implemented with a proper hooking framework
- // For now, we'll use the existing DexFileRecovery utility
+
+
Slog.d(TAG, "DEX file validation hooks prepared");
} catch (Exception e) {
Slog.w(TAG, "Failed to hook DEX file validation: " + e.getMessage());
}
}
- /**
- * Install ClassLoader monitoring
- */
+
private static void installClassLoaderMonitoring() {
try {
Slog.d(TAG, "Installing ClassLoader monitoring");
- // Monitor ClassLoader operations for potential failures
+
setupClassLoaderMonitoring();
} catch (Exception e) {
@@ -194,30 +174,26 @@ public class DexCrashPrevention {
}
}
- /**
- * Set up ClassLoader monitoring
- */
+
private static void setupClassLoaderMonitoring() {
try {
- // Monitor the current ClassLoader for potential issues
+
ClassLoader currentClassLoader = DexCrashPrevention.class.getClassLoader();
if (currentClassLoader != null) {
Slog.d(TAG, "Monitoring ClassLoader: " + currentClassLoader.getClass().getName());
- // In a real implementation, you would set up monitoring hooks
+
}
} catch (Exception e) {
Slog.w(TAG, "Failed to setup ClassLoader monitoring: " + e.getMessage());
}
}
- /**
- * Install APK integrity checks
- */
+
private static void installApkIntegrityChecks() {
try {
Slog.d(TAG, "Installing APK integrity checks");
- // Set up periodic APK integrity validation
+
setupPeriodicIntegrityChecks();
} catch (Exception e) {
@@ -225,27 +201,23 @@ public class DexCrashPrevention {
}
}
- /**
- * Set up periodic integrity checks
- */
+
private static void setupPeriodicIntegrityChecks() {
try {
- // This would be implemented with a background service or timer
+
Slog.d(TAG, "Periodic APK integrity checks prepared");
} catch (Exception e) {
Slog.w(TAG, "Failed to setup periodic integrity checks: " + e.getMessage());
}
}
- /**
- * Validate and prevent APK corruption
- */
+
public static PreventionResult validateAndPreventCorruption(String apkFilePath) {
if (apkFilePath == null) {
return new PreventionResult("Validation", false, "APK file path is null");
}
- // Check cache first
+
if (sPreventionCache.containsKey(apkFilePath)) {
return sPreventionCache.get(apkFilePath);
}
@@ -258,7 +230,7 @@ public class DexCrashPrevention {
return result;
}
- // Check if it's a problematic split APK
+
if (isProblematicSplitApk(apkFile.getName())) {
Slog.w(TAG, "Detected problematic split APK: " + apkFile.getName());
PreventionResult result = handleProblematicSplitApk(apkFile);
@@ -266,13 +238,13 @@ public class DexCrashPrevention {
return result;
}
- // Validate APK integrity
+
if (DexFileRecovery.isValidApkFile(apkFile)) {
PreventionResult result = new PreventionResult("Validation", true, "APK file is valid");
sPreventionCache.put(apkFilePath, result);
return result;
} else {
- // APK is corrupted, attempt recovery
+
Slog.w(TAG, "APK file is corrupted: " + apkFilePath);
PreventionResult result = attemptCorruptionRecovery(apkFilePath);
sPreventionCache.put(apkFilePath, result);
@@ -286,9 +258,7 @@ public class DexCrashPrevention {
}
}
- /**
- * Check if this is a problematic split APK
- */
+
private static boolean isProblematicSplitApk(String fileName) {
if (fileName == null) return false;
@@ -301,17 +271,15 @@ public class DexCrashPrevention {
return false;
}
- /**
- * Handle problematic split APK files
- */
+
private static PreventionResult handleProblematicSplitApk(File splitApk) {
try {
Slog.d(TAG, "Handling problematic split APK: " + splitApk.getName());
- // Try to find the base APK
+
String baseApkPath = findBaseApkPath(splitApk);
if (baseApkPath != null) {
- // Validate the base APK
+
if (DexFileRecovery.isValidApkFile(new File(baseApkPath))) {
Slog.d(TAG, "Found valid base APK: " + baseApkPath);
return new PreventionResult("Split APK Handling", true,
@@ -319,7 +287,7 @@ public class DexCrashPrevention {
}
}
- // If no valid base APK, try to recover the split APK
+
DexFileRecovery.RecoveryResult recoveryResult = DexFileRecovery.recoverDexFile(splitApk.getAbsolutePath());
if (recoveryResult.success) {
return new PreventionResult("Split APK Recovery", true,
@@ -335,9 +303,7 @@ public class DexCrashPrevention {
}
}
- /**
- * Find the base APK path for a split APK
- */
+
private static String findBaseApkPath(File splitApk) {
try {
File parent = splitApk.getParentFile();
@@ -347,7 +313,7 @@ public class DexCrashPrevention {
);
if (files != null && files.length > 0) {
- // Return the first base APK found
+
return files[0].getAbsolutePath();
}
}
@@ -358,14 +324,12 @@ public class DexCrashPrevention {
return null;
}
- /**
- * Attempt to recover from corruption
- */
+
private static PreventionResult attemptCorruptionRecovery(String corruptedFilePath) {
try {
Slog.d(TAG, "Attempting corruption recovery for: " + corruptedFilePath);
- // Use the comprehensive DEX file recovery utility
+
DexFileRecovery.RecoveryResult recoveryResult = DexFileRecovery.recoverDexFile(corruptedFilePath);
if (recoveryResult.success) {
@@ -382,9 +346,7 @@ public class DexCrashPrevention {
}
}
- /**
- * Get virtual app directory
- */
+
private static String getVirtualAppDirectory() {
try {
Context context = BlackBoxCore.getContext();
@@ -401,9 +363,7 @@ public class DexCrashPrevention {
return null;
}
- /**
- * Get virtual app APK files
- */
+
private static String[] getVirtualAppApkFiles() {
try {
String appDir = getVirtualAppDirectory();
@@ -426,17 +386,13 @@ public class DexCrashPrevention {
return null;
}
- /**
- * Clear prevention cache
- */
+
public static void clearCache() {
sPreventionCache.clear();
Slog.d(TAG, "Prevention cache cleared");
}
- /**
- * Get prevention statistics
- */
+
public static String getPreventionStats() {
int successful = 0;
int failed = 0;
@@ -453,18 +409,14 @@ public class DexCrashPrevention {
", Total Attempts: " + sPreventionCache.size();
}
- /**
- * Force prevention attempt for a specific file
- */
+
public static PreventionResult forcePrevention(String filePath) {
- // Clear cache for this file to force retry
+
sPreventionCache.remove(filePath);
return validateAndPreventCorruption(filePath);
}
- /**
- * Get comprehensive DEX crash prevention status
- */
+
public static String getStatus() {
StringBuilder status = new StringBuilder();
status.append("DEX Crash Prevention Status:\n");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexFileRecovery.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexFileRecovery.java
index 942305f..07021f1 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexFileRecovery.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/DexFileRecovery.java
@@ -23,29 +23,24 @@ import java.util.zip.ZipInputStream;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
-/**
- * Comprehensive DEX file recovery utility to handle "classes.dex: Entry not found" errors.
- * This class provides multiple recovery strategies for corrupted or missing DEX files.
- */
+
public class DexFileRecovery {
private static final String TAG = "DexFileRecovery";
- // Cache for recovery attempts to avoid repeated work
+
private static final Map sRecoveryCache = new HashMap<>();
- // Recovery strategies
+
private static final List sRecoveryStrategies = new ArrayList<>();
- // Maximum recovery attempts per file
+
private static final int MAX_RECOVERY_ATTEMPTS = 3;
static {
initializeRecoveryStrategies();
}
- /**
- * Recovery result containing the recovered file path and method used
- */
+
public static class RecoveryResult {
public final String recoveredFilePath;
public final String recoveryMethod;
@@ -76,18 +71,14 @@ public class DexFileRecovery {
}
}
- /**
- * Recovery strategy interface
- */
+
public interface RecoveryStrategy {
String getName();
RecoveryResult attemptRecovery(String corruptedFilePath);
- int getPriority(); // Higher priority strategies are tried first
+ int getPriority();
}
- /**
- * Initialize all available recovery strategies
- */
+
private static void initializeRecoveryStrategies() {
sRecoveryStrategies.add(new AlternativeApkStrategy());
sRecoveryStrategies.add(new HostAppApkStrategy());
@@ -95,21 +86,19 @@ public class DexFileRecovery {
sRecoveryStrategies.add(new DexExtractionStrategy());
sRecoveryStrategies.add(new BackupRestoreStrategy());
- // Sort by priority (highest first)
+
sRecoveryStrategies.sort((a, b) -> Integer.compare(b.getPriority(), a.getPriority()));
Slog.d(TAG, "Initialized " + sRecoveryStrategies.size() + " recovery strategies");
}
- /**
- * Attempt to recover a corrupted DEX file
- */
+
public static RecoveryResult recoverDexFile(String corruptedFilePath) {
if (corruptedFilePath == null) {
return new RecoveryResult("Corrupted file path is null");
}
- // Check cache first
+
if (sRecoveryCache.containsKey(corruptedFilePath)) {
RecoveryResult cached = sRecoveryCache.get(corruptedFilePath);
Slog.d(TAG, "Using cached recovery result for " + corruptedFilePath + ": " + cached);
@@ -118,7 +107,7 @@ public class DexFileRecovery {
Slog.w(TAG, "Attempting to recover corrupted DEX file: " + corruptedFilePath);
- // Try each recovery strategy in order of priority
+
for (RecoveryStrategy strategy : sRecoveryStrategies) {
try {
Slog.d(TAG, "Trying recovery strategy: " + strategy.getName());
@@ -136,15 +125,13 @@ public class DexFileRecovery {
}
}
- // All strategies failed
+
RecoveryResult failure = new RecoveryResult("All recovery strategies failed for " + corruptedFilePath);
sRecoveryCache.put(corruptedFilePath, failure);
return failure;
}
- /**
- * Strategy 1: Find alternative APK files in the same directory
- */
+
private static class AlternativeApkStrategy implements RecoveryStrategy {
@Override
public String getName() {
@@ -153,7 +140,7 @@ public class DexFileRecovery {
@Override
public int getPriority() {
- return 100; // Highest priority
+ return 100;
}
@Override
@@ -167,10 +154,10 @@ public class DexFileRecovery {
if (files != null) {
for (File file : files) {
if (file.getName().endsWith(".apk") &&
- file.length() > 1000000 && // > 1MB
+ file.length() > 1000000 &&
!file.getAbsolutePath().equals(corruptedFilePath)) {
- // Validate this APK file
+
if (isValidApkFile(file)) {
Slog.d(TAG, "Found valid alternative APK: " + file.getAbsolutePath());
return new RecoveryResult(file.getAbsolutePath(), getName());
@@ -187,9 +174,7 @@ public class DexFileRecovery {
}
}
- /**
- * Strategy 2: Use host app's APK as fallback
- */
+
private static class HostAppApkStrategy implements RecoveryStrategy {
@Override
public String getName() {
@@ -223,9 +208,7 @@ public class DexFileRecovery {
}
}
- /**
- * Strategy 3: Use system APK files as fallback
- */
+
private static class SystemApkStrategy implements RecoveryStrategy {
@Override
public String getName() {
@@ -240,7 +223,7 @@ public class DexFileRecovery {
@Override
public RecoveryResult attemptRecovery(String corruptedFilePath) {
try {
- // Try to find system APK files
+
String[] systemPaths = {
"/system/app",
"/system/priv-app",
@@ -276,9 +259,7 @@ public class DexFileRecovery {
}
}
- /**
- * Strategy 4: Extract DEX from corrupted APK if possible
- */
+
private static class DexExtractionStrategy implements RecoveryStrategy {
@Override
public String getName() {
@@ -298,7 +279,7 @@ public class DexFileRecovery {
return new RecoveryResult("Not an APK file or file doesn't exist");
}
- // Try to extract classes.dex from the corrupted APK
+
String extractedDexPath = extractDexFromApk(corruptedFile);
if (extractedDexPath != null) {
Slog.d(TAG, "Successfully extracted DEX from corrupted APK: " + extractedDexPath);
@@ -315,13 +296,13 @@ public class DexFileRecovery {
try (ZipFile zipFile = new ZipFile(apkFile)) {
ZipEntry dexEntry = zipFile.getEntry("classes.dex");
if (dexEntry != null) {
- // Create extraction directory
+
File extractDir = new File(BlackBoxCore.getContext().getCacheDir(), "dex_recovery");
if (!extractDir.exists()) {
extractDir.mkdirs();
}
- // Extract the DEX file
+
File extractedDex = new File(extractDir, "classes_" + System.currentTimeMillis() + ".dex");
try (InputStream input = zipFile.getInputStream(dexEntry);
FileOutputStream output = new FileOutputStream(extractedDex)) {
@@ -344,9 +325,7 @@ public class DexFileRecovery {
}
}
- /**
- * Strategy 5: Restore from backup if available
- */
+
private static class BackupRestoreStrategy implements RecoveryStrategy {
@Override
public String getName() {
@@ -355,13 +334,13 @@ public class DexFileRecovery {
@Override
public int getPriority() {
- return 20; // Lowest priority
+ return 20;
}
@Override
public RecoveryResult attemptRecovery(String corruptedFilePath) {
try {
- // Look for backup files
+
String backupPath = findBackupFile(corruptedFilePath);
if (backupPath != null && isValidApkFile(new File(backupPath))) {
Slog.d(TAG, "Found valid backup file: " + backupPath);
@@ -378,7 +357,7 @@ public class DexFileRecovery {
try {
File original = new File(originalPath);
File parent = original.getParentFile();
- String baseName = original.getName().replaceFirst("[.][^.]+$", ""); // Remove extension
+ String baseName = original.getName().replaceFirst("[.][^.]+$", "");
if (parent != null && parent.exists()) {
File[] files = parent.listFiles((dir, name) ->
@@ -387,7 +366,7 @@ public class DexFileRecovery {
);
if (files != null && files.length > 0) {
- // Return the most recent backup
+
File mostRecent = files[0];
for (File file : files) {
if (file.lastModified() > mostRecent.lastModified()) {
@@ -405,21 +384,19 @@ public class DexFileRecovery {
}
}
- /**
- * Validate if an APK file is valid and contains classes.dex
- */
+
public static boolean isValidApkFile(File apkFile) {
if (apkFile == null || !apkFile.exists()) {
return false;
}
try {
- // Check file size (APK should be at least 1MB)
+
if (apkFile.length() < 1000000) {
return false;
}
- // Check if it's a valid ZIP file containing classes.dex
+
try (ZipFile zipFile = new ZipFile(apkFile)) {
ZipEntry dexEntry = zipFile.getEntry("classes.dex");
return dexEntry != null && dexEntry.getSize() > 0;
@@ -433,17 +410,13 @@ public class DexFileRecovery {
}
}
- /**
- * Clear recovery cache
- */
+
public static void clearCache() {
sRecoveryCache.clear();
Slog.d(TAG, "Recovery cache cleared");
}
- /**
- * Get recovery statistics
- */
+
public static String getRecoveryStats() {
int successful = 0;
int failed = 0;
@@ -460,11 +433,9 @@ public class DexFileRecovery {
", Total Attempts: " + sRecoveryCache.size();
}
- /**
- * Force recovery attempt for a specific file
- */
+
public static RecoveryResult forceRecovery(String filePath) {
- // Clear cache for this file to force retry
+
sRecoveryCache.remove(filePath);
return recoverDexFile(filePath);
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/FileUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/FileUtils.java
index e6340f6..e128ced 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/FileUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/FileUtils.java
@@ -86,17 +86,14 @@ public class FileUtils {
return in;
}
- /**
- * @param path
- * @param mode {@link FileMode}
- */
+
public static void chmod(String path, int mode) throws Exception {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
Os.chmod(path, mode);
return;
} catch (Exception e) {
- // ignore
+
}
}
@@ -115,7 +112,7 @@ public class FileUtils {
Os.link(oldPath, newPath);
return;
} catch (Throwable e) {
- //ignore
+
}
}
Runtime.getRuntime().exec("ln -s " + oldPath + " " + newPath).waitFor();
@@ -170,7 +167,7 @@ public class FileUtils {
try {
link = isSymlink(dir);
} catch (Exception e) {
- //ignore
+
}
if (!link) {
String[] children = dir.list();
@@ -233,7 +230,7 @@ public class FileUtils {
}
outputStream.flush();
} catch (Throwable e) {
- //ignore
+
} finally {
closeQuietly(inputStream);
closeQuietly(outputStream);
@@ -300,17 +297,12 @@ public class FileUtils {
}
}
- /**
- * Check if given filename is valid for an ext4 filesystem.
- */
+
public static boolean isValidExtFilename(String name) {
return (name != null) && name.equals(buildValidExtFilename(name));
}
- /**
- * Mutate the given filename to make it valid for an ext4 filesystem,
- * replacing any invalid characters with "_".
- */
+
public static String buildValidExtFilename(String name) {
if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) {
return "(invalid)";
@@ -363,9 +355,7 @@ public class FileUtils {
| MODE_IROTH | MODE_IXOTH;
}
- /**
- * Lock the specified fle
- */
+
public static class FileLock {
private static FileLock singleton;
private Map mRefCountMap = new ConcurrentHashMap();
@@ -430,9 +420,7 @@ public class FileUtils {
}
}
- /**
- * unlock odex file
- **/
+
public void unLock(File targetFile) {
File lockFile = new File(targetFile.getParentFile().getAbsolutePath().concat("/lock"));
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/GlobalContextWrapper.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/GlobalContextWrapper.java
index 0c986ee..16ef425 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/GlobalContextWrapper.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/GlobalContextWrapper.java
@@ -7,10 +7,7 @@ import android.content.res.AssetManager;
import android.content.res.Resources;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * GlobalContextWrapper - A safe ContextWrapper that prevents null context crashes
- * This class is designed to be used as a replacement for all ContextWrapper instances
- */
+
public class GlobalContextWrapper extends ContextWrapper {
private static final String TAG = "GlobalContextWrapper";
@@ -50,17 +47,17 @@ public class GlobalContextWrapper extends ContextWrapper {
Slog.w(TAG, "Error getting resources from base context: " + e.getMessage());
}
- // Fallback to host context resources
+
try {
return fallbackContext.getResources();
} catch (Exception e) {
Slog.w(TAG, "Error getting fallback resources: " + e.getMessage());
- // Return a minimal resources object to prevent crash
+
try {
return new Resources(null, null, null);
} catch (Exception e2) {
Slog.w(TAG, "Error creating minimal resources: " + e2.getMessage());
- // Last resort - return null but don't crash
+
return null;
}
}
@@ -77,7 +74,7 @@ public class GlobalContextWrapper extends ContextWrapper {
Slog.w(TAG, "Error getting package manager from base context: " + e.getMessage());
}
- // Fallback to host context package manager
+
try {
return fallbackContext.getPackageManager();
} catch (Exception e) {
@@ -156,9 +153,7 @@ public class GlobalContextWrapper extends ContextWrapper {
return fallbackContext.getSystemService(name);
}
- /**
- * Create a safe context wrapper for any context
- */
+
public static Context createSafeContext(Context context, String packageName) {
if (context == null) {
return new GlobalContextWrapper(null, packageName);
@@ -169,7 +164,7 @@ public class GlobalContextWrapper extends ContextWrapper {
}
if (context instanceof ContextWrapper) {
- // Check if the base context is null
+
try {
Context baseContext = ((ContextWrapper) context).getBaseContext();
if (baseContext == null) {
@@ -184,9 +179,7 @@ public class GlobalContextWrapper extends ContextWrapper {
return new GlobalContextWrapper(context, packageName);
}
- /**
- * Create a safe context wrapper for any context
- */
+
public static Context createSafeContext(Context context) {
String packageName = context != null ? context.getPackageName() : "unknown";
return createSafeContext(context, packageName);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/HackAppUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/HackAppUtils.java
index 1f9326f..f97e352 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/HackAppUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/HackAppUtils.java
@@ -2,12 +2,7 @@ package top.niunaijun.blackbox.utils;
public class HackAppUtils {
- /**
- * Enable the Log output of QQ.
- *
- * @param packageName package name
- * @param classLoader class loader
- */
+
public static void enableQQLogOutput(String packageName, ClassLoader classLoader) {
if ("com.tencent.mobileqq".equals(packageName)) {
try {
@@ -16,7 +11,7 @@ public class HackAppUtils {
.set(100);
} catch (Exception e) {
e.printStackTrace();
- // ignore
+
}
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/JarUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/JarUtils.java
index 5b9cb28..bed9a50 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/JarUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/JarUtils.java
@@ -13,16 +13,11 @@ import java.security.NoSuchAlgorithmException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
-/**
- * Utility class for JAR file operations
- * Provides enhanced functionality for JAR file handling
- */
+
public class JarUtils {
private static final String TAG = "JarUtils";
- /**
- * Copy file with progress tracking and error recovery
- */
+
public static void copyFileWithProgress(InputStream input, File target, String fileName) throws IOException {
if (input == null) {
throw new IOException("Input stream is null");
@@ -32,7 +27,7 @@ public class JarUtils {
throw new IOException("Target file is null");
}
- // Ensure target directory exists
+
File targetDir = target.getParentFile();
if (targetDir != null && !targetDir.exists() && !targetDir.mkdirs()) {
throw new IOException("Failed to create target directory: " + targetDir);
@@ -42,7 +37,7 @@ public class JarUtils {
File tempFile = null;
try {
- // Create temporary file for atomic write
+
tempFile = File.createTempFile(target.getName(), ".tmp", targetDir);
output = new FileOutputStream(tempFile);
@@ -56,7 +51,7 @@ public class JarUtils {
output.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
- // Log progress every 100KB
+
if (totalBytes % 102400 == 0 && System.currentTimeMillis() - lastLogTime > 1000) {
Log.d(TAG, "Copying " + fileName + ": " + (totalBytes / 1024) + "KB");
lastLogTime = System.currentTimeMillis();
@@ -67,7 +62,7 @@ public class JarUtils {
output.close();
output = null;
- // Atomic move to final location
+
if (!tempFile.renameTo(target)) {
throw new IOException("Failed to move temporary file to target: " + target);
}
@@ -75,7 +70,7 @@ public class JarUtils {
Log.d(TAG, "Successfully copied " + fileName + " (" + totalBytes + " bytes)");
} catch (IOException e) {
- // Clean up on failure
+
if (tempFile != null && tempFile.exists()) {
if (!tempFile.delete()) {
Log.w(TAG, "Failed to delete temporary file: " + tempFile);
@@ -93,9 +88,7 @@ public class JarUtils {
}
}
- /**
- * Calculate SHA-256 hash of a file
- */
+
public static String calculateFileHash(File file) {
if (file == null || !file.exists()) {
return null;
@@ -129,9 +122,7 @@ public class JarUtils {
}
}
- /**
- * Verify JAR file integrity
- */
+
public static boolean verifyJarFile(File jarFile) {
if (jarFile == null || !jarFile.exists()) {
return false;
@@ -141,14 +132,14 @@ public class JarUtils {
return false;
}
- // Try to open as ZIP to verify it's a valid JAR
+
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(jarFile))) {
ZipEntry entry;
int entryCount = 0;
while ((entry = zis.getNextEntry()) != null) {
entryCount++;
- // Just read a few entries to verify it's valid
+
if (entryCount > 10) {
break;
}
@@ -163,9 +154,7 @@ public class JarUtils {
}
}
- /**
- * Get JAR file information
- */
+
public static String getJarInfo(File jarFile) {
if (jarFile == null || !jarFile.exists()) {
return "File not found";
@@ -188,9 +177,7 @@ public class JarUtils {
return info.toString();
}
- /**
- * Safe file deletion with retry
- */
+
public static boolean safeDelete(File file) {
if (file == null || !file.exists()) {
return true;
@@ -205,7 +192,7 @@ public class JarUtils {
retryCount++;
if (retryCount < 3) {
try {
- Thread.sleep(100 * retryCount); // Exponential backoff
+ Thread.sleep(100 * retryCount);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
@@ -217,9 +204,7 @@ public class JarUtils {
return false;
}
- /**
- * Create directory with proper permissions
- */
+
public static boolean createDirectory(File dir) {
if (dir == null) {
return false;
@@ -230,7 +215,7 @@ public class JarUtils {
}
if (dir.mkdirs()) {
- // Set read/write permissions for owner
+
dir.setReadable(true, true);
dir.setWritable(true, true);
return true;
@@ -239,19 +224,17 @@ public class JarUtils {
return false;
}
- /**
- * Get optimal buffer size based on available memory
- */
+
public static int getOptimalBufferSize() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
- if (maxMemory > 512 * 1024 * 1024) { // > 512MB
- return 32768; // 32KB
- } else if (maxMemory > 256 * 1024 * 1024) { // > 256MB
- return 16384; // 16KB
+ if (maxMemory > 512 * 1024 * 1024) {
+ return 32768;
+ } else if (maxMemory > 256 * 1024 * 1024) {
+ return 16384;
} else {
- return 8192; // 8KB
+ return 8192;
}
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/LogSender.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/LogSender.java
index 2be704e..6c57cb6 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/LogSender.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/LogSender.java
@@ -8,9 +8,7 @@ import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
-/**
- * Utility to upload logs to logs-sender-api.
- */
+
public class LogSender {
private static final String TAG = "LogSender";
private static final String API_URL_TEMPLATE = "https://logs-sender-api.vercel.app/api/%s/upload";
@@ -44,18 +42,18 @@ public class LogSender {
DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
- // Add caption
+
if (caption != null) {
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"caption\"" + lineEnd);
dos.writeBytes(lineEnd);
- // Ensure text encoding if needed, but writeBytes handles ASCII which is typical for multipart headers
- // For body content, write(bytes) is safer for UTF-8
+
+
dos.write(caption.getBytes("UTF-8"));
dos.writeBytes(lineEnd);
}
- // Add file
+
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + logFile.getName() + "\"" + lineEnd);
dos.writeBytes("Content-Type: text/plain" + lineEnd);
@@ -76,7 +74,7 @@ public class LogSender {
int responseCode = connection.getResponseCode();
if (responseCode == 200 || responseCode == 201) {
Slog.d(TAG, "Logs sent successfully: " + responseCode);
- return null; // Success
+ return null;
} else {
String errorMsg = "HTTP " + responseCode;
try {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/Md5Utils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/Md5Utils.java
index 08e01cd..64b4747 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/Md5Utils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/Md5Utils.java
@@ -1,8 +1,6 @@
package top.niunaijun.blackbox.utils;
-/**
- * Created by admin on 2017/1/8.
- */
+
import java.io.File;
import java.io.FileInputStream;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeCrashPrevention.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeCrashPrevention.java
index e95b295..ea6be78 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeCrashPrevention.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeCrashPrevention.java
@@ -19,18 +19,15 @@ import java.util.Map;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.fake.service.ClassLoaderProxy;
-/**
- * Comprehensive native crash prevention utility to handle native crashes
- * like SIGSEGV, SIGABRT, and other native-level failures.
- */
+
public class NativeCrashPrevention {
private static final String TAG = "NativeCrashPrevention";
private static boolean sIsInitialized = false;
- // Cache for native crash prevention attempts
+
private static final Map sPreventionCache = new HashMap<>();
- // Known problematic native libraries
+
private static final String[] PROBLEMATIC_LIBS = {
"libart.so",
"libdvm.so",
@@ -38,9 +35,7 @@ public class NativeCrashPrevention {
"libm.so"
};
- /**
- * Prevention result containing the prevention method and success status
- */
+
public static class PreventionResult {
public final String preventionMethod;
public final boolean success;
@@ -61,9 +56,7 @@ public class NativeCrashPrevention {
}
}
- /**
- * Initialize native crash prevention mechanisms
- */
+
public static void initialize() {
if (sIsInitialized) {
return;
@@ -72,16 +65,16 @@ public class NativeCrashPrevention {
try {
Slog.d(TAG, "Initializing native crash prevention...");
- // Install signal handlers
+
installSignalHandlers();
- // Install native library monitoring
+
installNativeLibraryMonitoring();
- // Install memory protection
+
installMemoryProtection();
- // Install thread protection
+
installThreadProtection();
sIsInitialized = true;
@@ -92,16 +85,14 @@ public class NativeCrashPrevention {
}
}
- /**
- * Install signal handlers for native crashes
- */
+
private static void installSignalHandlers() {
try {
- // This would be implemented with native code (JNI)
- // For now, we'll use Java-based prevention
+
+
Slog.d(TAG, "Signal handlers prepared (requires native implementation)");
- // Set up thread-level crash prevention
+
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
@@ -114,9 +105,7 @@ public class NativeCrashPrevention {
}
}
- /**
- * Handle native crashes at the Java level
- */
+
private static void handleNativeCrash(Thread thread, Throwable throwable) {
try {
String threadName = thread.getName();
@@ -124,22 +113,22 @@ public class NativeCrashPrevention {
Slog.w(TAG, "Native crash detected in thread: " + threadName + " - " + errorMessage);
- // Check if this is a native crash
+
if (isNativeCrash(throwable)) {
Slog.w(TAG, "Native crash confirmed, attempting recovery");
- // Try to recover from native crash
+
boolean recovered = attemptNativeCrashRecovery(thread, throwable);
if (recovered) {
Slog.d(TAG, "Successfully recovered from native crash");
- return; // Prevent crash
+ return;
} else {
Slog.w(TAG, "Failed to recover from native crash");
}
}
- // If we can't recover, delegate to the original handler
+
Thread.UncaughtExceptionHandler originalHandler = getOriginalExceptionHandler();
if (originalHandler != null) {
originalHandler.uncaughtException(thread, throwable);
@@ -150,16 +139,14 @@ public class NativeCrashPrevention {
}
}
- /**
- * Check if the crash is a native crash
- */
+
private static boolean isNativeCrash(Throwable throwable) {
if (throwable == null) return false;
String message = throwable.getMessage();
if (message == null) return false;
- // Check for native crash indicators
+
String[] nativeCrashPatterns = {
"SIGSEGV",
"SIGABRT",
@@ -179,7 +166,7 @@ public class NativeCrashPrevention {
}
}
- // Check stack trace for native indicators
+
StackTraceElement[] stackTrace = throwable.getStackTrace();
if (stackTrace != null) {
for (StackTraceElement element : stackTrace) {
@@ -199,32 +186,30 @@ public class NativeCrashPrevention {
return false;
}
- /**
- * Attempt to recover from a native crash
- */
+
private static boolean attemptNativeCrashRecovery(Thread thread, Throwable throwable) {
try {
Slog.d(TAG, "Attempting native crash recovery...");
- // Strategy 1: Restart the crashed thread
+
if (restartCrashedThread(thread)) {
Slog.d(TAG, "Successfully restarted crashed thread");
return true;
}
- // Strategy 2: Clear native caches
+
if (clearNativeCaches()) {
Slog.d(TAG, "Successfully cleared native caches");
return true;
}
- // Strategy 3: Reinitialize native libraries
+
if (reinitializeNativeLibraries()) {
Slog.d(TAG, "Successfully reinitialized native libraries");
return true;
}
- // Strategy 4: Memory cleanup
+
if (performMemoryCleanup()) {
Slog.d(TAG, "Successfully performed memory cleanup");
return true;
@@ -239,33 +224,29 @@ public class NativeCrashPrevention {
}
}
- /**
- * Restart a crashed thread
- */
+
private static boolean restartCrashedThread(Thread thread) {
try {
- // This is a simplified approach - in a real implementation,
- // you would need to properly handle thread restart
+
+
Slog.d(TAG, "Thread restart strategy prepared for: " + thread.getName());
- return false; // Not implemented yet
+ return false;
} catch (Exception e) {
Slog.w(TAG, "Failed to restart thread: " + e.getMessage());
return false;
}
}
- /**
- * Clear native caches
- */
+
private static boolean clearNativeCaches() {
try {
- // Clear various caches that might be corrupted
- System.gc(); // Force garbage collection
- // Clear reflection caches
+ System.gc();
+
+
clearReflectionCaches();
- // Clear class caches
+
clearClassCaches();
Slog.d(TAG, "Native caches cleared");
@@ -277,15 +258,13 @@ public class NativeCrashPrevention {
}
}
- /**
- * Clear reflection caches
- */
+
private static void clearReflectionCaches() {
try {
- // Clear reflection caches to prevent corruption
+
Class> reflectionCacheClass = Class.forName("java.lang.reflect.ReflectionFactory");
if (reflectionCacheClass != null) {
- // This is a simplified approach
+
Slog.d(TAG, "Reflection caches cleared");
}
} catch (Exception e) {
@@ -293,12 +272,10 @@ public class NativeCrashPrevention {
}
}
- /**
- * Clear class caches
- */
+
private static void clearClassCaches() {
try {
- // Clear class caches from our utilities
+
if (ClassLoaderProxy.class != null) {
ClassLoaderProxy.clearClassCache();
}
@@ -317,33 +294,29 @@ public class NativeCrashPrevention {
}
}
- /**
- * Reinitialize native libraries
- */
+
private static boolean reinitializeNativeLibraries() {
try {
- // This would require native code implementation
- // For now, we'll use Java-based recovery
+
+
Slog.d(TAG, "Native library reinitialization prepared");
- return false; // Not implemented yet
+ return false;
} catch (Exception e) {
Slog.w(TAG, "Failed to reinitialize native libraries: " + e.getMessage());
return false;
}
}
- /**
- * Perform memory cleanup
- */
+
private static boolean performMemoryCleanup() {
try {
- // Force garbage collection multiple times
+
for (int i = 0; i < 3; i++) {
System.gc();
- Thread.sleep(100); // Small delay between GC calls
+ Thread.sleep(100);
}
- // Clear system properties that might be corrupted
+
clearCorruptedSystemProperties();
Slog.d(TAG, "Memory cleanup completed");
@@ -355,12 +328,10 @@ public class NativeCrashPrevention {
}
}
- /**
- * Clear corrupted system properties
- */
+
private static void clearCorruptedSystemProperties() {
try {
- // Clear potentially corrupted system properties
+
String[] propertiesToClear = {
"webview.data.dir",
"webview.cache.dir",
@@ -375,7 +346,7 @@ public class NativeCrashPrevention {
Slog.d(TAG, "Cleared corrupted property: " + property);
}
} catch (Exception e) {
- // Ignore individual property errors
+
}
}
} catch (Exception e) {
@@ -383,14 +354,12 @@ public class NativeCrashPrevention {
}
}
- /**
- * Install native library monitoring
- */
+
private static void installNativeLibraryMonitoring() {
try {
Slog.d(TAG, "Installing native library monitoring");
- // Monitor native library loading
+
monitorNativeLibraryLoading();
} catch (Exception e) {
@@ -398,26 +367,22 @@ public class NativeCrashPrevention {
}
}
- /**
- * Monitor native library loading
- */
+
private static void monitorNativeLibraryLoading() {
try {
- // This would be implemented with native code
+
Slog.d(TAG, "Native library monitoring prepared");
} catch (Exception e) {
Slog.w(TAG, "Failed to setup native library monitoring: " + e.getMessage());
}
}
- /**
- * Install memory protection
- */
+
private static void installMemoryProtection() {
try {
Slog.d(TAG, "Installing memory protection");
- // Set up memory monitoring
+
setupMemoryMonitoring();
} catch (Exception e) {
@@ -425,12 +390,10 @@ public class NativeCrashPrevention {
}
}
- /**
- * Set up memory monitoring
- */
+
private static void setupMemoryMonitoring() {
try {
- // Monitor memory usage
+
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
long totalMemory = runtime.totalMemory();
@@ -444,14 +407,12 @@ public class NativeCrashPrevention {
}
}
- /**
- * Install thread protection
- */
+
private static void installThreadProtection() {
try {
Slog.d(TAG, "Installing thread protection");
- // Set up thread monitoring
+
setupThreadMonitoring();
} catch (Exception e) {
@@ -459,12 +420,10 @@ public class NativeCrashPrevention {
}
}
- /**
- * Set up thread monitoring
- */
+
private static void setupThreadMonitoring() {
try {
- // Monitor thread count and health
+
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
while (rootGroup.getParent() != null) {
rootGroup = rootGroup.getParent();
@@ -478,12 +437,10 @@ public class NativeCrashPrevention {
}
}
- /**
- * Get the original exception handler
- */
+
private static Thread.UncaughtExceptionHandler getOriginalExceptionHandler() {
try {
- // Try to get the original handler
+
Field handlerField = Thread.class.getDeclaredField("defaultUncaughtExceptionHandler");
handlerField.setAccessible(true);
return (Thread.UncaughtExceptionHandler) handlerField.get(null);
@@ -493,17 +450,13 @@ public class NativeCrashPrevention {
}
}
- /**
- * Clear prevention cache
- */
+
public static void clearCache() {
sPreventionCache.clear();
Slog.d(TAG, "Native crash prevention cache cleared");
}
- /**
- * Get prevention statistics
- */
+
public static String getPreventionStats() {
int successful = 0;
int failed = 0;
@@ -520,9 +473,7 @@ public class NativeCrashPrevention {
", Failed: " + failed + ", Total Attempts: " + sPreventionCache.size();
}
- /**
- * Get comprehensive native crash prevention status
- */
+
public static String getStatus() {
StringBuilder status = new StringBuilder();
status.append("Native Crash Prevention Status:\n");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeUtils.java
index 20b752b..f21b8fd 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/NativeUtils.java
@@ -15,14 +15,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-/**
- * updated by alex5402 on 2/24/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class NativeUtils {
public static final String TAG = "VirtualM";
@@ -71,10 +64,10 @@ public class NativeUtils {
String libName = entryName.substring(entryName.lastIndexOf('/') + 1);
Log.d(TAG, "verify so " + libName);
-// File abiDir = new File(nativeLibDir, cpuArch);
-// if (!abiDir.exists()) {
-// abiDir.mkdirs();
-// }
+
+
+
+
File libFile = new File(nativeLibDir, libName);
if (libFile.exists() && libFile.length() == entry.getSize()) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/QQUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/QQUtils.java
index 2a0b9e9..52edad0 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/QQUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/QQUtils.java
@@ -5,9 +5,7 @@ import android.util.Log;
import java.lang.reflect.Field;
-/**
- * Created by BlackBox on 2022/2/20.
- */
+
public class QQUtils {
public static void hackLog(Context context) {
try {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ReflectionClass.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ReflectionClass.java
index a97128a..01cf6a8 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ReflectionClass.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ReflectionClass.java
@@ -5,14 +5,12 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-/**
- * Created by BlackBox on 2022/3/21.
- */
+
public class ReflectionClass {
@SuppressWarnings("rawtypes")
public static void print(String name) {
try {
- // print class name and super class name (if != object)
+
Class cl = Class.forName(name);
Class supercl = cl.getSuperclass();
Class[] interfaces = cl.getInterfaces();
@@ -21,7 +19,7 @@ public class ReflectionClass {
System.out.print(modifiers);
}
- // is class or interface
+
if (!cl.isInterface()) {
System.out.print(" class ");
}
@@ -59,11 +57,7 @@ public class ReflectionClass {
}
}
- /**
- * Prints all constructors of a class
- *
- * @param cl a class
- */
+
@SuppressWarnings("rawtypes")
private static void printConstructors(Class cl) {
Constructor[] constructors = cl.getDeclaredConstructors();
@@ -71,13 +65,13 @@ public class ReflectionClass {
for (Constructor c : constructors) {
String name = c.getName();
System.out.print(" ");
- // print modifiers.
+
String modifiers = Modifier.toString(c.getModifiers());
if (modifiers.length() > 0) {
System.out.print(modifiers + " ");
}
- // print name and parameter types.
+
System.out.print(name.substring(name.lastIndexOf(".") + 1) + " (");
Class[] paramTypes = c.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
@@ -88,7 +82,7 @@ public class ReflectionClass {
}
System.out.print(")");
- // print exceptions
+
Class[] exceptions = c.getExceptionTypes();
if (exceptions.length > 0) {
System.out.print(" throws ");
@@ -104,11 +98,7 @@ public class ReflectionClass {
}
}
- /**
- * Prints all methods of a class
- *
- * @param cl a class
- */
+
@SuppressWarnings("rawtypes")
private static void printMethods(Class cl) {
Method[] methods = cl.getDeclaredMethods();
@@ -117,7 +107,7 @@ public class ReflectionClass {
String name = m.getName();
System.out.print(" ");
- // print modifiers, return type and method name
+
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0) {
System.out.print(modifiers + " ");
@@ -125,7 +115,7 @@ public class ReflectionClass {
printType(retType);
System.out.print(" " + name + "(");
- // print parameter types
+
Class[] paramTypes = m.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
if (j > 0) {
@@ -136,7 +126,7 @@ public class ReflectionClass {
System.out.print(")");
- // print exceptions
+
Class[] exceptions = m.getExceptionTypes();
if (exceptions.length > 0) {
System.out.print(" throws ");
@@ -152,11 +142,7 @@ public class ReflectionClass {
}
}
- /**
- * Prints all fields of a class
- *
- * @param cl a class
- */
+
@SuppressWarnings("rawtypes")
private static void printFields(Class cl) {
Field[] fields = cl.getDeclaredFields();
@@ -174,11 +160,7 @@ public class ReflectionClass {
}
}
- /**
- * Prints a type.
- *
- * @param type a type.
- */
+
@SuppressWarnings("rawtypes")
private static void printType(Class type) {
String name = type.getName();
@@ -208,11 +190,7 @@ public class ReflectionClass {
}
}
- /**
- * Prints the extends chain for a class
- *
- * @param cl a class
- */
+
@SuppressWarnings("rawtypes")
public static void printExtendsChain(Class cl) {
System.out.print("\n\nExtends chain:\n ");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/Reflector.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/Reflector.java
index 9520162..8f61dff 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/Reflector.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/Reflector.java
@@ -8,9 +8,7 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-/**
- * Created by qiaopu on 2018/4/26.
- */
+
public class Reflector {
public static final String LOG_TAG = "Reflector";
@@ -124,7 +122,7 @@ public class Reflector {
try {
return cls.getDeclaredField(name);
} catch (NoSuchFieldException ex) {
- // Ignored
+
}
}
throw e;
@@ -180,7 +178,7 @@ public class Reflector {
try {
return cls.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException ex) {
- // Ignored
+
}
}
throw e;
@@ -221,7 +219,7 @@ public class Reflector {
cls = Class.forName(name, initialize, loader);
return on(cls, null);
} catch (Throwable e) {
-// Log.w(LOG_TAG, "Oops!", e);
+
return on(cls, e);
}
}
@@ -270,7 +268,7 @@ public class Reflector {
super.constructor(parameterTypes);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return this;
}
@@ -285,7 +283,7 @@ public class Reflector {
return super.newInstance(initargs);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return null;
}
@@ -300,7 +298,7 @@ public class Reflector {
super.bind(obj);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return this;
}
@@ -321,7 +319,7 @@ public class Reflector {
super.field(name);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return this;
}
@@ -336,7 +334,7 @@ public class Reflector {
return super.get();
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return null;
}
@@ -351,7 +349,7 @@ public class Reflector {
return super.get(caller);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return null;
}
@@ -366,7 +364,7 @@ public class Reflector {
super.set(value);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return this;
}
@@ -381,7 +379,7 @@ public class Reflector {
super.set(caller, value);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return this;
}
@@ -396,7 +394,7 @@ public class Reflector {
super.method(name, parameterTypes);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return this;
}
@@ -411,7 +409,7 @@ public class Reflector {
return super.call(args);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return null;
}
@@ -426,7 +424,7 @@ public class Reflector {
return super.callByCaller(caller, args);
} catch (Throwable e) {
mIgnored = e;
-// Log.w(LOG_TAG, "Oops!", e);
+
}
return null;
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SafeContextWrapper.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SafeContextWrapper.java
index fcd19d5..836211e 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SafeContextWrapper.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SafeContextWrapper.java
@@ -7,10 +7,7 @@ import android.content.res.AssetManager;
import android.content.res.Resources;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * A safe ContextWrapper that prevents NullPointerException when the base context is null
- * created by alex5402
- */
+
public class SafeContextWrapper extends ContextWrapper {
private static final String TAG = "SafeContextWrapper";
@@ -46,17 +43,17 @@ public class SafeContextWrapper extends ContextWrapper {
Slog.w(TAG, "Error getting resources from base context: " + e.getMessage());
}
- // Fallback to host context resources
+
try {
return fallbackContext.getResources();
} catch (Exception e) {
Slog.w(TAG, "Error getting fallback resources: " + e.getMessage());
- // Return a minimal resources object to prevent crash
+
try {
return new Resources(null, null, null);
} catch (Exception e2) {
Slog.w(TAG, "Error creating minimal resources: " + e2.getMessage());
- // Last resort - return null but don't crash
+
return null;
}
}
@@ -73,7 +70,7 @@ public class SafeContextWrapper extends ContextWrapper {
Slog.w(TAG, "Error getting package manager from base context: " + e.getMessage());
}
- // Fallback to host context package manager
+
try {
return fallbackContext.getPackageManager();
} catch (Exception e) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ShellUtils.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ShellUtils.java
index f8624f7..1e9d5a5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/ShellUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/ShellUtils.java
@@ -18,92 +18,41 @@ public class ShellUtils {
}
- /**
- * check whether has root permission
- *
- * @return
- */
+
public static boolean checkRootPermission() {
return execCommand("echo root", true, false).result == 0;
}
- /**
- * execute shell command, default return result msg
- *
- * @param command command
- * @param isRoot whether need to run with root
- * @return
- * @see ShellUtils#execCommand(String[], boolean, boolean)
- */
+
public static CommandResult execCommand(String command, boolean isRoot) {
return execCommand(new String[]{command}, isRoot, true);
}
- /**
- * execute shell commands, default return result msg
- *
- * @param commands command list
- * @param isRoot whether need to run with root
- * @return
- * @see ShellUtils#execCommand(String[], boolean, boolean)
- */
+
public static CommandResult execCommand(List commands, boolean isRoot) {
return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, true);
}
- /**
- * execute shell commands, default return result msg
- *
- * @param commands command array
- * @param isRoot whether need to run with root
- * @return
- * @see ShellUtils#execCommand(String[], boolean, boolean)
- */
+
public static CommandResult execCommand(String[] commands, boolean isRoot) {
return execCommand(commands, isRoot, true);
}
- /**
- * execute shell command
- *
- * @param command command
- * @param isRoot whether need to run with root
- * @param isNeedResultMsg whether need result msg
- * @return
- * @see ShellUtils#execCommand(String[], boolean, boolean)
- */
+
public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(new String[]{command}, isRoot, isNeedResultMsg);
}
- /**
- * execute shell commands
- *
- * @param commands command list
- * @param isRoot whether need to run with root
- * @param isNeedResultMsg whether need result msg
- * @return
- * @see ShellUtils#execCommand(String[], boolean, boolean)
- */
+
public static CommandResult execCommand(List commands, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg);
}
- /**
- * execute shell commands
- *
- * @param commands command array
- * @param isRoot whether need to run with root
- * @param isNeedResultMsg whether need result msg
- * @return
- * - if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and
- *
- if {@link CommandResult#result} is -1, there maybe some excepiton.
- *
- */
+
public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
int result = -1;
if (commands == null || commands.length == 0) {
@@ -158,26 +107,13 @@ public class ShellUtils {
}
- /**
- * result of command
- *
- * - {@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in
- * linux shell
- * - {@link CommandResult#successMsg} means success message of command result
- *
- *
- * @author Trinea 2013-5-16
- */
+
public static class CommandResult {
- /**
- * result of command
- **/
+
public int result;
- /**
- * success message of command result
- **/
+
public String successMsg;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SimpleCrashFix.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SimpleCrashFix.java
index 7775826..97d5002 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SimpleCrashFix.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SimpleCrashFix.java
@@ -7,17 +7,12 @@ import android.app.Application;
import top.niunaijun.blackbox.BlackBoxCore;
-/**
- * SimpleCrashFix - Essential crash prevention for app startup
- * Cleaned up version with only essential functionality
- */
+
public class SimpleCrashFix {
private static final String TAG = "SimpleCrashFix";
private static boolean sIsInstalled = false;
- /**
- * Install the essential crash fix
- */
+
public static void installSimpleFix() {
if (sIsInstalled) {
Slog.d(TAG, "Simple crash fix already installed");
@@ -27,10 +22,10 @@ public class SimpleCrashFix {
try {
Slog.d(TAG, "Installing essential crash fix...");
- // Install global exception handler
+
installGlobalExceptionHandler();
- // Install context wrapper hook
+
installContextWrapperHook();
sIsInstalled = true;
@@ -40,53 +35,51 @@ public class SimpleCrashFix {
}
}
- /**
- * Install a global exception handler to catch and handle null context crashes
- */
+
private static void installGlobalExceptionHandler() {
try {
- // Get the current default handler
+
Thread.UncaughtExceptionHandler currentHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
- // Check if this is the specific null context crash we're trying to prevent
+
if (isNullContextCrash(throwable)) {
Slog.w(TAG, "Caught null context crash, preventing crash: " + throwable.getMessage());
BlackBoxCore.get().sendLogs("CRASH DETECTED (Caught/NullContext): " + throwable.getMessage(), true);
- return; // Prevent crash
+ return;
}
- // Check for Google Play Services crashes
+
if (isGooglePlayServicesCrash(throwable)) {
Slog.w(TAG, "Caught Google Play Services crash, preventing crash: " + throwable.getMessage());
BlackBoxCore.get().sendLogs("CRASH DETECTED (Caught/GMS): " + throwable.getMessage(), true);
- return; // Prevent crash - Google Play Services crashes are not critical
+ return;
}
- // Check for WebView crashes
+
if (isWebViewCrash(throwable)) {
Slog.w(TAG, "Caught WebView crash, preventing crash: " + throwable.getMessage());
BlackBoxCore.get().sendLogs("CRASH DETECTED (Caught/WebView): " + throwable.getMessage(), true);
- return; // Prevent crash - WebView crashes can be handled gracefully
+ return;
}
- // Check for AttributionSource crashes
+
if (isAttributionSourceCrash(throwable)) {
Slog.w(TAG, "Caught AttributionSource crash, preventing crash: " + throwable.getMessage());
BlackBoxCore.get().sendLogs("CRASH DETECTED (Caught/Attribution): " + throwable.getMessage(), true);
- return; // Prevent crash - AttributionSource issues can be fixed
+ return;
}
- // Check for social media app specific crashes
+
if (isSocialMediaAppCrash(throwable)) {
Slog.w(TAG, "Caught social media app crash, preventing crash: " + throwable.getMessage());
BlackBoxCore.get().sendLogs("CRASH DETECTED (Caught/SocialMedia): " + throwable.getMessage(), true);
- return; // Prevent crash - Social media apps should not crash
+ return;
}
- // For other crashes, try to report before dying (Best Effort)
+
Slog.e(TAG, "Fatal crash detected, attempting to report before death...");
try {
BlackBoxCore.get().sendLogs("FATAL CRASH (Uncaught): " + throwable.getMessage(), false);
@@ -94,7 +87,7 @@ public class SimpleCrashFix {
Slog.e(TAG, "Failed to report fatal crash: " + e.getMessage());
}
- // For other crashes, delegate to the original handler
+
if (currentHandler != null) {
currentHandler.uncaughtException(thread, throwable);
}
@@ -107,12 +100,10 @@ public class SimpleCrashFix {
}
}
- /**
- * Install context wrapper hook to prevent null context crashes
- */
+
private static void installContextWrapperHook() {
try {
- // Install a simple context wrapper hook
+
ContextWrapperHook.installHook();
Slog.d(TAG, "Context wrapper hook installed");
} catch (Exception e) {
@@ -120,9 +111,7 @@ public class SimpleCrashFix {
}
}
- /**
- * Check if the crash is related to null context issues
- */
+
private static boolean isNullContextCrash(Throwable throwable) {
if (throwable == null) {
return false;
@@ -137,7 +126,7 @@ public class SimpleCrashFix {
message.contains("getClassLoader");
}
- // Check stack trace for context-related calls
+
StackTraceElement[] stackTrace = throwable.getStackTrace();
if (stackTrace != null) {
for (StackTraceElement element : stackTrace) {
@@ -157,9 +146,7 @@ public class SimpleCrashFix {
return false;
}
- /**
- * Check if the crash is related to Google Play Services
- */
+
private static boolean isGooglePlayServicesCrash(Throwable throwable) {
if (throwable == null) {
return false;
@@ -173,7 +160,7 @@ public class SimpleCrashFix {
message.contains("com.google.android.gms");
}
- // Check stack trace for Google Play Services related calls
+
StackTraceElement[] stackTrace = throwable.getStackTrace();
if (stackTrace != null) {
for (StackTraceElement element : stackTrace) {
@@ -189,9 +176,7 @@ public class SimpleCrashFix {
return false;
}
- /**
- * Check if the crash is related to WebView issues
- */
+
private static boolean isWebViewCrash(Throwable throwable) {
if (throwable == null) {
return false;
@@ -206,7 +191,7 @@ public class SimpleCrashFix {
message.contains("data directory");
}
- // Check stack trace for WebView related calls
+
StackTraceElement[] stackTrace = throwable.getStackTrace();
if (stackTrace != null) {
for (StackTraceElement element : stackTrace) {
@@ -225,9 +210,7 @@ public class SimpleCrashFix {
return false;
}
- /**
- * Check if the crash is related to AttributionSource issues
- */
+
private static boolean isAttributionSourceCrash(Throwable throwable) {
if (throwable == null) {
return false;
@@ -242,7 +225,7 @@ public class SimpleCrashFix {
message.contains("UID mismatch");
}
- // Check stack trace for AttributionSource related calls
+
StackTraceElement[] stackTrace = throwable.getStackTrace();
if (stackTrace != null) {
for (StackTraceElement element : stackTrace) {
@@ -260,9 +243,7 @@ public class SimpleCrashFix {
return false;
}
- /**
- * Check if the crash is related to social media apps
- */
+
private static boolean isSocialMediaAppCrash(Throwable throwable) {
if (throwable == null) {
return false;
@@ -281,7 +262,7 @@ public class SimpleCrashFix {
message.contains("LinkedIn");
}
- // Check stack trace for social media app related calls
+
StackTraceElement[] stackTrace = throwable.getStackTrace();
if (stackTrace != null) {
for (StackTraceElement element : stackTrace) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/Slog.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/Slog.java
index 5930753..61b8edf 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/Slog.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/Slog.java
@@ -1,28 +1,12 @@
-/*
- * 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 top.niunaijun.blackbox.utils;
import android.util.Log;
-/**
- * @hide
- */
+
public final class Slog {
- /** @hide */ public static final int LOG_ID_SYSTEM = 3;
+ public static final int LOG_ID_SYSTEM = 3;
private Slog() {
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SocialMediaAppCrashPrevention.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SocialMediaAppCrashPrevention.java
index 5a71a5b..ed6d2c9 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SocialMediaAppCrashPrevention.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SocialMediaAppCrashPrevention.java
@@ -17,39 +17,34 @@ import java.util.Map;
import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
-/**
- * Comprehensive crash prevention utility for social media apps
- * This class provides specialized handling for common crash scenarios in apps like Facebook, Instagram, etc.
- */
+
public class SocialMediaAppCrashPrevention {
private static final String TAG = "SocialMediaCrashPrevention";
private static boolean sIsInitialized = false;
- // Known social media app packages
+
private static final String[] SOCIAL_MEDIA_PACKAGES = {
- "com.facebook.katana", // Facebook
- "com.facebook.orca", // Facebook Messenger
- "com.instagram.android", // Instagram
- "com.whatsapp", // WhatsApp
- "org.telegram.messenger", // Telegram
- "com.twitter.android", // Twitter/X
- "com.zhiliaoapp.musically", // TikTok
- "com.snapchat.android", // Snapchat
- "com.google.android.youtube", // YouTube
- "com.linkedin.android", // LinkedIn
- "com.discord", // Discord
- "com.reddit.frontpage", // Reddit
- "com.spotify.music", // Spotify
- "com.netflix.mediaclient", // Netflix
- "com.amazon.avod.thirdpartyclient" // Prime Video
+ "com.facebook.katana",
+ "com.facebook.orca",
+ "com.instagram.android",
+ "com.whatsapp",
+ "org.telegram.messenger",
+ "com.twitter.android",
+ "com.zhiliaoapp.musically",
+ "com.snapchat.android",
+ "com.google.android.youtube",
+ "com.linkedin.android",
+ "com.discord",
+ "com.reddit.frontpage",
+ "com.spotify.music",
+ "com.netflix.mediaclient",
+ "com.amazon.avod.thirdpartyclient"
};
- // Crash prevention strategies
+
private static final Map sCrashPreventionStrategies = new HashMap<>();
- /**
- * Initialize crash prevention for social media apps
- */
+
public static void initialize() {
if (sIsInitialized) {
return;
@@ -58,19 +53,19 @@ public class SocialMediaAppCrashPrevention {
try {
Slog.d(TAG, "Initializing social media app crash prevention...");
- // Install WebView crash prevention
+
installWebViewCrashPrevention();
- // Install AttributionSource crash prevention
+
installAttributionSourceCrashPrevention();
- // Install context crash prevention
+
installContextCrashPrevention();
- // Install permission crash prevention
+
installPermissionCrashPrevention();
- // Install media crash prevention
+
installMediaCrashPrevention();
sIsInitialized = true;
@@ -81,9 +76,7 @@ public class SocialMediaAppCrashPrevention {
}
}
- /**
- * Check if the current app is a social media app
- */
+
public static boolean isSocialMediaApp() {
try {
String currentPackage = BActivityThread.getAppPackageName();
@@ -98,15 +91,13 @@ public class SocialMediaAppCrashPrevention {
return false;
}
- /**
- * Install WebView crash prevention
- */
+
private static void installWebViewCrashPrevention() {
try {
- // Hook WebView constructor to prevent data directory conflicts
+
hookWebViewConstructor();
- // Hook WebViewDatabase to prevent initialization failures
+
hookWebViewDatabase();
Slog.d(TAG, "WebView crash prevention installed");
@@ -115,28 +106,24 @@ public class SocialMediaAppCrashPrevention {
}
}
- /**
- * Hook WebView constructor to prevent crashes
- */
+
private static void hookWebViewConstructor() {
try {
- // Create a custom WebView constructor hook
+
Constructor originalConstructor = WebView.class.getDeclaredConstructor(Context.class);
originalConstructor.setAccessible(true);
- // This would be implemented with a proper hooking framework
+
Slog.d(TAG, "WebView constructor hook prepared");
} catch (Exception e) {
Slog.w(TAG, "Could not prepare WebView constructor hook: " + e.getMessage());
}
}
- /**
- * Hook WebViewDatabase to prevent crashes
- */
+
private static void hookWebViewDatabase() {
try {
- // Ensure WebViewDatabase directory exists and is accessible
+
Context context = BlackBoxCore.getContext();
if (context != null) {
String packageName = context.getPackageName();
@@ -149,7 +136,7 @@ public class SocialMediaAppCrashPrevention {
Slog.d(TAG, "Created WebView directory: " + webViewDir);
}
- // Set system properties for WebView
+
System.setProperty("webview.data.dir", webViewDir);
System.setProperty("webview.cache.dir", webViewDir + "/cache");
System.setProperty("webview.cookies.dir", webViewDir + "/cookies");
@@ -159,28 +146,24 @@ public class SocialMediaAppCrashPrevention {
}
}
- /**
- * Install AttributionSource crash prevention
- */
+
private static void installAttributionSourceCrashPrevention() {
try {
- // Use the existing AttributionSourceUtils
+
Slog.d(TAG, "AttributionSource crash prevention installed");
} catch (Exception e) {
Slog.w(TAG, "Failed to install AttributionSource crash prevention: " + e.getMessage());
}
}
- /**
- * Install context crash prevention
- */
+
private static void installContextCrashPrevention() {
try {
- // Ensure context is never null
+
Context context = BlackBoxCore.getContext();
if (context == null) {
Slog.w(TAG, "Host context is null, attempting to recover");
- // Try to recover context
+
recoverContext();
}
@@ -190,39 +173,33 @@ public class SocialMediaAppCrashPrevention {
}
}
- /**
- * Install permission crash prevention
- */
+
private static void installPermissionCrashPrevention() {
try {
- // Hook permission checks to prevent crashes
+
Slog.d(TAG, "Permission crash prevention installed");
} catch (Exception e) {
Slog.w(TAG, "Failed to install permission crash prevention: " + e.getMessage());
}
}
- /**
- * Install media crash prevention
- */
+
private static void installMediaCrashPrevention() {
try {
- // Hook media-related operations to prevent crashes
+
Slog.d(TAG, "Media crash prevention installed");
} catch (Exception e) {
Slog.w(TAG, "Failed to install media crash prevention: " + e.getMessage());
}
}
- /**
- * Attempt to recover context if it's null
- */
+
private static void recoverContext() {
try {
- // Try to get context from various sources
+
Context recoveredContext = null;
- // Try to get context from ActivityThread
+
try {
Class> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
@@ -238,8 +215,8 @@ public class SocialMediaAppCrashPrevention {
if (recoveredContext != null) {
Slog.d(TAG, "Successfully recovered context");
- // Set the recovered context
- // This would require access to BlackBoxCore's context setter
+
+
}
} catch (Exception e) {
@@ -247,16 +224,14 @@ public class SocialMediaAppCrashPrevention {
}
}
- /**
- * Apply crash prevention for a specific app
- */
+
public static void applyCrashPrevention(String packageName) {
if (packageName == null) {
return;
}
try {
- // Check if this is a social media app
+
boolean isSocialMedia = false;
for (String socialMediaPackage : SOCIAL_MEDIA_PACKAGES) {
if (socialMediaPackage.equals(packageName)) {
@@ -268,7 +243,7 @@ public class SocialMediaAppCrashPrevention {
if (isSocialMedia) {
Slog.d(TAG, "Applying crash prevention for social media app: " + packageName);
- // Apply specific strategies for this app
+
CrashPreventionStrategy strategy = sCrashPreventionStrategies.get(packageName);
if (strategy != null) {
strategy.apply();
@@ -280,16 +255,12 @@ public class SocialMediaAppCrashPrevention {
}
}
- /**
- * Crash prevention strategy interface
- */
+
public interface CrashPreventionStrategy {
void apply();
}
- /**
- * Get crash prevention status
- */
+
public static String getCrashPreventionStatus() {
StringBuilder status = new StringBuilder();
status.append("Social Media Crash Prevention Status:\n");
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/StoragePermissionHelper.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/StoragePermissionHelper.java
index 22c4265..9efae53 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/StoragePermissionHelper.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/StoragePermissionHelper.java
@@ -13,12 +13,7 @@ import android.provider.Settings;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
-/**
- * Helper class for managing storage permissions on Android 11+ (SDK 30+)
- * Provides utilities for requesting and checking MANAGE_EXTERNAL_STORAGE permission.
- *
- * Created by alex5402
- */
+
public class StoragePermissionHelper {
private static final String TAG = "StoragePermissionHelper";
@@ -26,24 +21,20 @@ public class StoragePermissionHelper {
public static final int REQUEST_CODE_STORAGE_PERMISSION = 1001;
public static final int REQUEST_CODE_MANAGE_STORAGE = 1002;
- /**
- * Check if the app has all files access permission (MANAGE_EXTERNAL_STORAGE on Android 11+)
- */
+
public static boolean hasAllFilesAccess() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
- // On older versions, regular storage permission is sufficient
+
return true;
}
}
- /**
- * Check if the app has basic storage permissions (READ/WRITE_EXTERNAL_STORAGE)
- */
+
public static boolean hasStoragePermission(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- // Android 13+ uses granular media permissions
+
return ContextCompat.checkSelfPermission(context,
Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(context,
@@ -51,12 +42,12 @@ public class StoragePermissionHelper {
ContextCompat.checkSelfPermission(context,
Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- // Android 11-12: Check MANAGE_EXTERNAL_STORAGE or fallback to READ
+
return Environment.isExternalStorageManager() ||
ContextCompat.checkSelfPermission(context,
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
} else {
- // Android 10 and below
+
return ContextCompat.checkSelfPermission(context,
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(context,
@@ -64,17 +55,12 @@ public class StoragePermissionHelper {
}
}
- /**
- * Check if full file access is available (either granted or not needed)
- */
+
public static boolean hasFullFileAccess(Context context) {
return hasAllFilesAccess() && hasStoragePermission(context);
}
- /**
- * Request MANAGE_EXTERNAL_STORAGE permission by opening system settings
- * Call this for Android 11+ when you need all files access
- */
+
public static void requestAllFilesAccess(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
@@ -83,7 +69,7 @@ public class StoragePermissionHelper {
intent.setData(Uri.parse("package:" + activity.getPackageName()));
activity.startActivityForResult(intent, REQUEST_CODE_MANAGE_STORAGE);
} catch (Exception e) {
- // Fallback: open general manage all files settings
+
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
activity.startActivityForResult(intent, REQUEST_CODE_MANAGE_STORAGE);
}
@@ -91,10 +77,7 @@ public class StoragePermissionHelper {
}
}
- /**
- * Request MANAGE_EXTERNAL_STORAGE permission with a custom package name
- * Useful for requesting on behalf of sandboxed apps
- */
+
public static void requestAllFilesAccessForPackage(Activity activity, String packageName) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
@@ -102,20 +85,17 @@ public class StoragePermissionHelper {
intent.setData(Uri.parse("package:" + packageName));
activity.startActivityForResult(intent, REQUEST_CODE_MANAGE_STORAGE);
} catch (Exception e) {
- // Fallback: open general manage all files settings
+
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
activity.startActivityForResult(intent, REQUEST_CODE_MANAGE_STORAGE);
}
}
}
- /**
- * Request basic storage permissions (READ/WRITE_EXTERNAL_STORAGE)
- * For Android 13+, requests granular media permissions
- */
+
public static void requestStoragePermission(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- // Android 13+: Request granular media permissions
+
ActivityCompat.requestPermissions(activity,
new String[]{
Manifest.permission.READ_MEDIA_IMAGES,
@@ -124,7 +104,7 @@ public class StoragePermissionHelper {
},
REQUEST_CODE_STORAGE_PERMISSION);
} else {
- // Android 12 and below
+
ActivityCompat.requestPermissions(activity,
new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
@@ -134,25 +114,20 @@ public class StoragePermissionHelper {
}
}
- /**
- * Request all necessary storage permissions for full file access
- * This includes MANAGE_EXTERNAL_STORAGE on Android 11+
- */
+
public static void requestFullFileAccess(Activity activity) {
- // First request basic permissions
+
if (!hasStoragePermission(activity)) {
requestStoragePermission(activity);
}
- // Then request all files access if on Android 11+
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
requestAllFilesAccess(activity);
}
}
- /**
- * Check if we need to show permission rationale for storage permission
- */
+
public static boolean shouldShowStorageRationale(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return ActivityCompat.shouldShowRequestPermissionRationale(activity,
@@ -163,9 +138,7 @@ public class StoragePermissionHelper {
}
}
- /**
- * Get a user-friendly message about why storage permission is needed
- */
+
public static String getPermissionRationale() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return "This app needs access to all files to properly manage sandboxed applications. " +
@@ -176,14 +149,11 @@ public class StoragePermissionHelper {
}
}
- /**
- * Handle the result from permission request
- * @return true if all required permissions are now granted
- */
+
public static boolean handlePermissionResult(Activity activity, int requestCode,
String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_CODE_STORAGE_PERMISSION) {
- // Check if any permission was granted
+
for (int result : grantResults) {
if (result == PackageManager.PERMISSION_GRANTED) {
Slog.d(TAG, "Storage permission granted");
@@ -196,10 +166,7 @@ public class StoragePermissionHelper {
return false;
}
- /**
- * Handle the result from MANAGE_EXTERNAL_STORAGE settings activity
- * Should be called in onActivityResult
- */
+
public static boolean handleAllFilesAccessResult(int requestCode) {
if (requestCode == REQUEST_CODE_MANAGE_STORAGE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SystemHookManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SystemHookManager.java
index 131639c..47bc9da 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/SystemHookManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/SystemHookManager.java
@@ -12,26 +12,22 @@ import android.content.Intent;
import android.util.Log;
import java.util.List;
-/**
- * SystemHookManager - Directly hooks problematic system methods to prevent null context crashes
- */
+
public class SystemHookManager {
private static final String TAG = "SystemHookManager";
- /**
- * Install all system hooks to prevent null context crashes
- */
+
public static void installAllHooks() {
try {
Log.d(TAG, "Installing system hooks...");
- // Hook ClientTransactionListenerController
+
hookClientTransactionListenerController();
- // Hook ConfigurationController
+
hookConfigurationController();
- // Hook ActivityThread directly
+
hookActivityThread();
Log.d(TAG, "System hooks installed successfully");
@@ -40,27 +36,25 @@ public class SystemHookManager {
}
}
- /**
- * Hook the ClientTransactionListenerController to prevent null context crashes
- */
+
private static void hookClientTransactionListenerController() {
try {
- // Try to find the ClientTransactionListenerController class
+
Class> controllerClass = Class.forName("android.app.servertransaction.ClientTransactionListenerController");
if (controllerClass != null) {
Log.d(TAG, "Found ClientTransactionListenerController class");
- // Create a proxy that handles null contexts gracefully
+
Object proxy = Proxy.newProxyInstance(
controllerClass.getClassLoader(),
new Class>[] { controllerClass },
(proxyObj, method, args) -> {
if ("onContextConfigurationPreChanged".equals(method.getName())) {
try {
- // Before calling the original method, ensure all activities have valid contexts
+
ensureAllActivitiesHaveContext();
- // Call the original method with null safety
+
if (args != null && args.length > 0) {
return method.invoke(proxyObj, args);
} else {
@@ -69,7 +63,7 @@ public class SystemHookManager {
}
} catch (Exception e) {
Log.w(TAG, "Error in ClientTransactionListenerController proxy: " + e.getMessage());
- // Return gracefully instead of crashing
+
return null;
}
}
@@ -77,7 +71,7 @@ public class SystemHookManager {
}
);
- // Try to replace the instance in ActivityThread
+
replaceControllerInstance(controllerClass, proxy, "ClientTransactionListenerController");
}
@@ -86,27 +80,25 @@ public class SystemHookManager {
}
}
- /**
- * Hook the ConfigurationController to prevent null context crashes
- */
+
private static void hookConfigurationController() {
try {
- // Try to find the ConfigurationController class
+
Class> controllerClass = Class.forName("android.app.ConfigurationController");
if (controllerClass != null) {
Log.d(TAG, "Found ConfigurationController class");
- // Create a proxy that handles null contexts gracefully
+
Object proxy = Proxy.newProxyInstance(
controllerClass.getClassLoader(),
new Class>[] { controllerClass },
(proxyObj, method, args) -> {
if ("handleConfigurationChanged".equals(method.getName())) {
try {
- // Before calling the original method, ensure all activities have valid contexts
+
ensureAllActivitiesHaveContext();
- // Call the original method with null safety
+
if (args != null && args.length > 0) {
return method.invoke(proxyObj, args);
} else {
@@ -115,7 +107,7 @@ public class SystemHookManager {
}
} catch (Exception e) {
Log.w(TAG, "Error in ConfigurationController proxy: " + e.getMessage());
- // Return gracefully instead of crashing
+
return null;
}
}
@@ -123,7 +115,7 @@ public class SystemHookManager {
}
);
- // Try to replace the instance in ActivityThread
+
replaceControllerInstance(controllerClass, proxy, "ConfigurationController");
}
@@ -132,49 +124,47 @@ public class SystemHookManager {
}
}
- /**
- * Hook ActivityThread directly to ensure contexts are valid
- */
+
private static void hookActivityThread() {
try {
- // Try to find the ActivityThread class
+
Class> activityThreadClass = Class.forName("android.app.ActivityThread");
if (activityThreadClass != null) {
Log.d(TAG, "Found ActivityThread class");
- // Get the current ActivityThread instance
+
Object activityThread = BlackBoxCore.mainThread();
if (activityThread != null) {
Log.d(TAG, "Found ActivityThread instance");
- // Try to hook the handleLaunchActivity method
+
try {
Method handleLaunchActivity = activityThreadClass.getDeclaredMethod(
"handleLaunchActivity",
- Object.class, // ActivityClientRecord
+ Object.class,
Intent.class,
- Object.class, // ActivityInfo
- Object.class, // Configuration
- Object.class, // CompatibilityInfo
- String.class, // referrer
- Object.class, // IVoiceInteractor
- Object.class, // Bundle
- Object.class, // PersistableBundle
- List.class, // List
- List.class, // List
- boolean.class, // notResumed
- boolean.class, // isForward
- Object.class // ProfilerInfo
+ Object.class,
+ Object.class,
+ Object.class,
+ String.class,
+ Object.class,
+ Object.class,
+ Object.class,
+ List.class,
+ List.class,
+ boolean.class,
+ boolean.class,
+ Object.class
);
if (handleLaunchActivity != null) {
Log.d(TAG, "Found handleLaunchActivity method");
- // Make the method accessible
+
handleLaunchActivity.setAccessible(true);
- // We can't easily replace this method, but we can ensure our context fixes are applied
- // The key is to make sure our context fixes are called before the original method
+
+
}
} catch (Exception e) {
@@ -187,15 +177,13 @@ public class SystemHookManager {
}
}
- /**
- * Replace a controller instance in ActivityThread
- */
+
private static void replaceControllerInstance(Class> controllerClass, Object proxy, String controllerName) {
try {
- // Look for the instance in ActivityThread
+
Object activityThread = BlackBoxCore.mainThread();
if (activityThread != null) {
- // Try to find the controller field
+
Field[] fields = activityThread.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getType().equals(controllerClass)) {
@@ -209,10 +197,10 @@ public class SystemHookManager {
}
}
- // If we couldn't find the field, try to create a new instance
+
Log.w(TAG, "Could not find " + controllerName + " field, trying to create new instance");
try {
- // Try to find a constructor
+
java.lang.reflect.Constructor>[] constructors = controllerClass.getDeclaredConstructors();
if (constructors.length > 0) {
constructors[0].setAccessible(true);
@@ -230,15 +218,13 @@ public class SystemHookManager {
}
}
- /**
- * Ensure all activities in the current process have valid contexts
- */
+
private static void ensureAllActivitiesHaveContext() {
try {
- // Get all activity records from ActivityThread
+
Object activityThread = BlackBoxCore.mainThread();
if (activityThread != null) {
- // Try to get the activity records
+
try {
Field[] fields = activityThread.getClass().getDeclaredFields();
for (Field field : fields) {
@@ -247,14 +233,14 @@ public class SystemHookManager {
field.setAccessible(true);
Object activityRecords = field.get(activityThread);
if (activityRecords != null) {
- // Try to iterate through the records
+
try {
Method valuesMethod = activityRecords.getClass().getMethod("values");
Object values = valuesMethod.invoke(activityRecords);
if (values instanceof java.util.Collection) {
for (Object record : (java.util.Collection>) values) {
if (record != null) {
- // Try to get the activity from the record
+
try {
Field activityField = record.getClass().getDeclaredField("activity");
activityField.setAccessible(true);
@@ -263,7 +249,7 @@ public class SystemHookManager {
BlackBoxCore.ensureActivityContext((android.app.Activity) activity);
}
} catch (Exception e) {
- // Ignore individual activity errors
+
}
}
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/TransactionThrottler.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/TransactionThrottler.java
index dda5c31..70d5d06 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/TransactionThrottler.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/TransactionThrottler.java
@@ -5,43 +5,37 @@ import android.util.Log;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
-/**
- * Utility class to throttle Binder transactions and prevent process freezing
- * due to too many failed transactions in a short time period.
- */
+
public class TransactionThrottler {
private static final String TAG = "TransactionThrottler";
- private static final int MAX_FAILURES_PER_WINDOW = 50; // Much less aggressive
- private static final long WINDOW_DURATION_MS = 15000; // Longer window
- private static final long THROTTLE_DURATION_MS = 1000; // Shorter throttle
+ private static final int MAX_FAILURES_PER_WINDOW = 50;
+ private static final long WINDOW_DURATION_MS = 15000;
+ private static final long THROTTLE_DURATION_MS = 1000;
private final AtomicInteger failureCount = new AtomicInteger(0);
private final AtomicLong windowStartTime = new AtomicLong(0);
private final AtomicLong lastThrottleTime = new AtomicLong(0);
- /**
- * Check if we should throttle transactions due to too many recent failures
- * @return true if transactions should be throttled
- */
+
public boolean shouldThrottle() {
long currentTime = System.currentTimeMillis();
long windowStart = windowStartTime.get();
- // Reset window if it has expired
+
if (currentTime - windowStart > WINDOW_DURATION_MS) {
failureCount.set(0);
windowStartTime.set(currentTime);
return false;
}
- // Check if we're in a throttle period
+
long lastThrottle = lastThrottleTime.get();
if (currentTime - lastThrottle < THROTTLE_DURATION_MS) {
return true;
}
- // Check if we've exceeded the failure threshold
+
if (failureCount.get() >= MAX_FAILURES_PER_WINDOW) {
lastThrottleTime.set(currentTime);
Log.w(TAG, "Throttling transactions due to " + failureCount.get() + " failures in window");
@@ -51,19 +45,17 @@ public class TransactionThrottler {
return false;
}
- /**
- * Record a transaction failure
- */
+
public void recordFailure() {
long currentTime = System.currentTimeMillis();
long windowStart = windowStartTime.get();
- // Initialize window if not set
+
if (windowStart == 0) {
windowStartTime.set(currentTime);
}
- // Reset window if it has expired
+
if (currentTime - windowStart > WINDOW_DURATION_MS) {
failureCount.set(1);
windowStartTime.set(currentTime);
@@ -74,9 +66,7 @@ public class TransactionThrottler {
Log.d(TAG, "Recorded transaction failure, count: " + failureCount.get());
}
- /**
- * Reset the failure count (call when transactions start succeeding)
- */
+
public void reset() {
failureCount.set(0);
windowStartTime.set(0);
@@ -84,9 +74,7 @@ public class TransactionThrottler {
Log.d(TAG, "Reset transaction throttler");
}
- /**
- * Get current failure count
- */
+
public int getFailureCount() {
return failureCount.get();
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/TrieTree.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/TrieTree.java
index 63d3226..e766a87 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/TrieTree.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/TrieTree.java
@@ -5,14 +5,14 @@ import java.util.List;
public class TrieTree {
- //The root node of TrieTree
+
private final TrieNode root = new TrieNode();
- //The node type of TrieTree
+
private static class TrieNode {
char content;
String word;
- boolean isEnd = false; // This node is whether the end of a word
+ boolean isEnd = false;
List children = new LinkedList<>();
public TrieNode() {}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/UIDSpoofingHelper.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/UIDSpoofingHelper.java
index aa305a2..1d694b5 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/UIDSpoofingHelper.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/UIDSpoofingHelper.java
@@ -8,47 +8,38 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * UID Spoofing Helper to handle UID validation issues in virtual environments
- * This provides utilities for bypassing UID checks in system services
- */
+
public class UIDSpoofingHelper {
private static final String TAG = "UIDSpoofingHelper";
- /**
- * Get the appropriate UID for system operations
- * This helps bypass UID validation issues
- */
+
public static int getSystemUID() {
try {
- // Return system UID (1000) for system-level operations
+
return Process.SYSTEM_UID;
} catch (Exception e) {
Slog.w(TAG, "Failed to get system UID, using fallback", e);
- return 1000; // Fallback to system UID
+ return 1000;
}
}
- /**
- * Get the appropriate UID for package operations
- * This helps bypass package UID validation issues
- */
+
public static int getPackageUID(String packageName) {
try {
Context context = BlackBoxCore.getContext();
if (context != null) {
- // Try to get the real UID for the package
+
PackageManager pm = context.getPackageManager();
if (pm != null) {
int uid = pm.getPackageUid(packageName, 0);
- if (uid > 0) { // Valid UIDs are positive numbers
+ if (uid > 0) {
Slog.d(TAG, "Found real UID for package " + packageName + ": " + uid);
return uid;
}
}
}
- // Fallback to system UID if package UID not found
+
Slog.w(TAG, "Package UID not found for " + packageName + ", using system UID");
return getSystemUID();
@@ -58,22 +49,19 @@ public class UIDSpoofingHelper {
}
}
- /**
- * Get the appropriate UID for job scheduling operations
- * This helps bypass job scheduler UID validation issues
- */
+
public static int getJobSchedulingUID(String targetPackage) {
try {
- // For job scheduling, we need to use the target package's UID
+
int packageUid = getPackageUID(targetPackage);
- // If we got a valid package UID, use it
- if (packageUid > 0) { // Valid UIDs are positive numbers
+
+ if (packageUid > 0) {
Slog.d(TAG, "Using package UID for job scheduling: " + packageUid);
return packageUid;
}
- // Fallback to system UID
+
Slog.w(TAG, "Using system UID for job scheduling as fallback");
return getSystemUID();
@@ -83,15 +71,13 @@ public class UIDSpoofingHelper {
}
}
- /**
- * Check if the current UID needs spoofing for a specific operation
- */
+
public static boolean needsUIDSpoofing(String operation, String targetPackage) {
try {
int currentUid = Process.myUid();
int targetUid = getPackageUID(targetPackage);
- // If current UID doesn't match target package UID, we need spoofing
+
boolean needsSpoofing = currentUid != targetUid;
Slog.d(TAG, "UID spoofing check: current=" + currentUid +
@@ -101,13 +87,11 @@ public class UIDSpoofingHelper {
} catch (Exception e) {
Slog.w(TAG, "Failed to check UID spoofing need, assuming yes", e);
- return true; // Assume we need spoofing if check fails
+ return true;
}
}
- /**
- * Get the best UID for a specific system operation
- */
+
public static int getBestUIDForOperation(String operation, String targetPackage) {
try {
switch (operation) {
@@ -123,9 +107,9 @@ public class UIDSpoofingHelper {
return getPackageUID(targetPackage);
default:
- // For unknown operations, try package UID first, then system UID
+
int packageUid = getPackageUID(targetPackage);
- if (packageUid > 0) { // Valid UIDs are positive numbers
+ if (packageUid > 0) {
return packageUid;
}
return getSystemUID();
@@ -136,9 +120,7 @@ public class UIDSpoofingHelper {
}
}
- /**
- * Log UID information for debugging
- */
+
public static void logUIDInfo(String operation, String targetPackage) {
try {
int currentUid = Process.myUid();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/AccountManagerCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/AccountManagerCompat.java
index 9100ecf..daddc5c 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/AccountManagerCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/AccountManagerCompat.java
@@ -4,39 +4,20 @@ import android.accounts.AccountManager;
public class AccountManagerCompat {
- /**
- * Boolean, if set and 'customTokens' the authenticator is responsible for
- * notifications.
- */
+
public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
- /**
- * The Android package of the caller will be set in the options bundle by the
- * {@link AccountManager} and will be passed to the AccountManagerService and
- * to the AccountAuthenticators. The vuid of the caller will be known by the
- * AccountManagerService as well as the AccountAuthenticators so they will be able to
- * verify that the package is consistent with the vuid (a vuid might be shared by many
- * packages).
- */
+
public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
public static final int ERROR_CODE_USER_RESTRICTED = 100;
public static final int ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE = 101;
- /**
- * Bundle key used for the {@code long} expiration time (in millis from the unix epoch) of the
- * associated auth token.
- *
- */
+
public static final String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
- /**
- * Bundle key used to supply the last time the credentials of the account
- * were authenticated successfully. Time is specified in milliseconds since
- * epoch. Associated time is updated on successful authentication of account
- * on adding account, confirming credentials, or updating credentials.
- */
+
public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityCompat.java
index 7bb0411..66652b1 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityCompat.java
@@ -20,18 +20,11 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.utils.DrawableUtils;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ActivityCompat {
public static void fix(Activity activity) {
- // mContentResolver
+
BRActivity.get(activity).mActivityInfo();
Context baseContext = activity.getBaseContext();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityManagerCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityManagerCompat.java
index abd58cf..87fe541 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityManagerCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ActivityManagerCompat.java
@@ -12,62 +12,50 @@ import black.android.app.BRIActivityManagerL;
import black.android.app.BRIActivityManagerN;
public class ActivityManagerCompat {
- /** Type for IActivityManager.serviceDoneExecuting: anonymous operation */
+
public static final int SERVICE_DONE_EXECUTING_ANON = 0;
- /** Type for IActivityManager.serviceDoneExecuting: done with an onStart call */
+
public static final int SERVICE_DONE_EXECUTING_START = 1;
- /** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */
+
public static final int SERVICE_DONE_EXECUTING_STOP = 2;
-//
-// public static final int START_SUCCESS = ActivityManager.START_SUCCESS == null ?
-// 0 : ActivityManager.START_SUCCESS.get();
-//
-// /**
-// * Result for IActivityManager.startActivity: an error where the
-// * given Intent could not be resolved to an activity.
-// */
-// public static final int START_INTENT_NOT_RESOLVED = ActivityManager.START_INTENT_NOT_RESOLVED == null ?
-// -1 : ActivityManager.START_INTENT_NOT_RESOLVED.get();
-//
-// /**
-// * Result for IActivityManager.startActivity: trying to start a background user
-// * activity that shouldn't be displayed for all users.
-// */
-// public static final int START_NOT_CURRENT_USER_ACTIVITY = ActivityManager.START_NOT_CURRENT_USER_ACTIVITY == null ?
-// -8 : ActivityManager.START_NOT_CURRENT_USER_ACTIVITY.get();
-//
-// /**
-// * Result for IActivityManaqer.startActivity: activity wasn't really started, but
-// * a task was simply brought to the foreground.
-// */
-// public static final int START_TASK_TO_FRONT = ActivityManager.START_TASK_TO_FRONT == null ?
-// 2 : ActivityManager.START_TASK_TO_FRONT.get();
- /**
- * Type for IActivityManaqer.getIntentSender: this PendingIntent is
- * for a sendBroadcast operation.
- */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
public static final int INTENT_SENDER_BROADCAST = 1;
- /**
- * Type for IActivityManaqer.getIntentSender: this PendingIntent is
- * for a startActivity operation.
- */
+
public static final int INTENT_SENDER_ACTIVITY = 2;
- /**
- * Type for IActivityManaqer.getIntentSender: this PendingIntent is
- * for an activity result operation.
- */
+
public static final int INTENT_SENDER_ACTIVITY_RESULT = 3;
- /**
- * Type for IActivityManaqer.getIntentSender: this PendingIntent is
- * for a startService operation.
- */
+
public static final int INTENT_SENDER_SERVICE = 4;
- /** User operation call: success! */
+
public static final int USER_OP_SUCCESS = 0;
public static final int START_FLAG_DEBUG = 1<<1;
@@ -91,7 +79,7 @@ public class ActivityManagerCompat {
activity.setRequestedOrientation(orientation);
} catch (Throwable e) {
e.printStackTrace();
- //samsung is WindowManager.setRequestedOrientation
+
Activity parent = BRActivity.get(activity).mParent();
while (true) {
Activity tmp = BRActivity.get(parent).mParent();
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BuildCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BuildCompat.java
index 47ecc1d..b3358c7 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BuildCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BuildCompat.java
@@ -9,63 +9,63 @@ public class BuildCompat {
try {
return Build.VERSION.PREVIEW_SDK_INT;
} catch (Throwable e) {
- // ignore
+
}
}
return 0;
}
- // 14
+
public static boolean isU() {
return Build.VERSION.SDK_INT >= 33 || (Build.VERSION.SDK_INT >= 32 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 13
+
public static boolean isTiramisu() {
return Build.VERSION.SDK_INT >= 32 || (Build.VERSION.SDK_INT >= 31 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 12
+
public static boolean isS() {
return Build.VERSION.SDK_INT >= 31 || (Build.VERSION.SDK_INT >= 30 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 11
+
public static boolean isR() {
return Build.VERSION.SDK_INT >= 30 || (Build.VERSION.SDK_INT >= 29 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 10
+
public static boolean isQ() {
return Build.VERSION.SDK_INT >= 29 || (Build.VERSION.SDK_INT >= 28 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 9
+
public static boolean isPie() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P || (Build.VERSION.SDK_INT >= 27 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 8
+
public static boolean isOreo() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O || (Build.VERSION.SDK_INT >= 25 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 7.1
+
public static boolean isN_MR1() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 || (Build.VERSION.SDK_INT >= 24 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 7
+
public static boolean isN() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N || (Build.VERSION.SDK_INT >= 23 && Build.VERSION.PREVIEW_SDK_INT == 1);
}
- // 6
+
public static boolean isM() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
- // 5
+
public static boolean isL() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BundleCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BundleCompat.java
index f9bfc63..7dbcf3b 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BundleCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/BundleCompat.java
@@ -38,23 +38,23 @@ public class BundleCompat {
return null;
}
-// public static void clearParcelledData(Bundle bundle) {
-// Parcel obtain = Parcel.obtain();
-// obtain.writeInt(0);
-// obtain.setDataPosition(0);
-// Parcel parcel;
-// if (BaseBundle.TYPE != null) {
-// parcel = BaseBundle.mParcelledData.get(bundle);
-// if (parcel != null) {
-// parcel.recycle();
-// }
-// BaseBundle.mParcelledData.set(bundle, obtain);
-// } else if (BundleICS.TYPE != null) {
-// parcel = BundleICS.mParcelledData.get(bundle);
-// if (parcel != null) {
-// parcel.recycle();
-// }
-// BundleICS.mParcelledData.set(bundle, obtain);
-// }
-// }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContentProviderCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContentProviderCompat.java
index 4a6f0d7..5ff600f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContentProviderCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContentProviderCompat.java
@@ -46,15 +46,15 @@ public class ContentProviderCompat {
if (client == null) {
int retry = 0;
long startTime = System.currentTimeMillis();
- long timeout = 2000; // 2 seconds total timeout
+ long timeout = 2000;
while (retry < retryCount && client == null) {
- // Check if we've exceeded total timeout
+
if (System.currentTimeMillis() - startTime > timeout) {
break;
}
- SystemClock.sleep(200); // Reduced from 400ms to 200ms
+ SystemClock.sleep(200);
retry++;
client = acquireContentProviderClient(context, uri);
}
@@ -67,15 +67,15 @@ public class ContentProviderCompat {
if (client == null) {
int retry = 0;
long startTime = System.currentTimeMillis();
- long timeout = 2000; // 2 seconds total timeout
+ long timeout = 2000;
while (retry < retryCount && client == null) {
- // Check if we've exceeded total timeout
+
if (System.currentTimeMillis() - startTime > timeout) {
break;
}
- SystemClock.sleep(200); // Reduced from 400ms to 200ms
+ SystemClock.sleep(200);
retry++;
client = acquireContentProviderClient(context, name);
}
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContextCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContextCompat.java
index a1ae39b..13681ba 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContextCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/ContextCompat.java
@@ -14,14 +14,7 @@ import top.niunaijun.blackbox.BlackBoxCore;
import top.niunaijun.blackbox.app.BActivityThread;
import top.niunaijun.blackbox.utils.Slog;
-/**
- * updated by alex5402 on 3/31/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ContextCompat {
public static final String TAG = "ContextCompat";
@@ -39,7 +32,7 @@ public class ContextCompat {
public static void fix(Context context) {
try {
- // Check if context is null
+
if (context == null) {
Slog.w(TAG, "Context is null, skipping ContextCompat.fix");
return;
@@ -54,7 +47,7 @@ public class ContextCompat {
}
}
- // Check if context is still null after unwrapping
+
if (context == null) {
Slog.w(TAG, "Base context is null after unwrapping, skipping ContextCompat.fix");
return;
@@ -78,8 +71,8 @@ public class ContextCompat {
if (BuildCompat.isS()) {
try {
- // Use getHostUid() instead of getBUid() - AttributionSource UID must match
- // the calling process's actual UID (host UID), not the virtual UID
+
+
fixAttributionSourceState(BRContextImpl.get(context).getAttributionSource(), BlackBoxCore.getHostUid());
} catch (Exception e) {
Slog.w(TAG, "Failed to fix attribution source state: " + e.getMessage());
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/DexFileCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/DexFileCompat.java
index aa89cbc..ae03b45 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/DexFileCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/DexFileCompat.java
@@ -6,14 +6,7 @@ import java.util.List;
import dalvik.system.DexFile;
import top.niunaijun.blackbox.utils.Reflector;
-/**
- * updated by alex5402 on 2021/5/16.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class DexFileCompat {
public static List getCookies(ClassLoader classLoader) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/PackageParserCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/PackageParserCompat.java
index 7f804e1..4638ca8 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/PackageParserCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/PackageParserCompat.java
@@ -52,7 +52,7 @@ public class PackageParserCompat {
public static void collectCertificates(PackageParser parser, Package p, int flags) throws Throwable {
if (BuildCompat.isPie()) {
- BRPackageParserPie.getWithException().collectCertificates(p, true/*skipVerify*/);
+ BRPackageParserPie.getWithException().collectCertificates(p, true);
} else if (API_LEVEL >= N) {
BRPackageParserNougat.getWithException().collectCertificates(p, flags);
} else if (API_LEVEL >= M) {
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/StartActivityCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/StartActivityCompat.java
index 5fc2c6e..89d1cd0 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/StartActivityCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/StartActivityCompat.java
@@ -4,14 +4,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class StartActivityCompat {
private static int index = 0;
private static int appThreadIndex;
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/TaskDescriptionCompat.java b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/TaskDescriptionCompat.java
index de165d8..022031a 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/TaskDescriptionCompat.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/utils/compat/TaskDescriptionCompat.java
@@ -21,14 +21,14 @@ public class TaskDescriptionCompat {
return td;
label = getTaskDescriptionLabel(BlackBoxCore.getUserId(), getApplicationLabel());
- // Skip icon loading to prevent resource loading errors
- // Drawable drawable = getApplicationIcon();
- // if (drawable == null)
- // return td;
+
+
+
+
- // ActivityManager am = (ActivityManager) BlackBoxCore.getContext().getSystemService(Context.ACTIVITY_SERVICE);
- // int iconSize = am.getLauncherLargeIconSize();
- // icon = DrawableUtils.drawableToBitmap(drawable, iconSize, iconSize);
+
+
+
td = new ActivityManager.TaskDescription(label, null, td.getPrimaryColor());
return td;
}
@@ -48,7 +48,7 @@ public class TaskDescriptionCompat {
private static Drawable getApplicationIcon() {
try {
- // Skip icon loading to prevent resource loading errors
+
return null;
} catch (Exception ignore) {
return null;
diff --git a/Bcore/src/main/java/top/niunaijun/jnihook/MethodUtils.java b/Bcore/src/main/java/top/niunaijun/jnihook/MethodUtils.java
index c22dd48..d3c0379 100644
--- a/Bcore/src/main/java/top/niunaijun/jnihook/MethodUtils.java
+++ b/Bcore/src/main/java/top/niunaijun/jnihook/MethodUtils.java
@@ -1,13 +1,6 @@
package top.niunaijun.jnihook;
-/**
- * updated by alex5402 on 3/8/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
import androidx.annotation.Keep;
@@ -16,17 +9,17 @@ 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("(");
diff --git a/Bcore/src/main/java/top/niunaijun/jnihook/ReflectCore.java b/Bcore/src/main/java/top/niunaijun/jnihook/ReflectCore.java
index 2285e77..28d96fe 100644
--- a/Bcore/src/main/java/top/niunaijun/jnihook/ReflectCore.java
+++ b/Bcore/src/main/java/top/niunaijun/jnihook/ReflectCore.java
@@ -5,14 +5,7 @@ import java.lang.reflect.Method;
import top.niunaijun.jnihook.jni.JniHook;
-/**
- * updated by alex5402 on 2021/5/7.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public class ReflectCore {
public static void set(Class> clazz) {
diff --git a/Bcore/src/main/java/top/niunaijun/jnihook/jni/JniHook.java b/Bcore/src/main/java/top/niunaijun/jnihook/jni/JniHook.java
index 6de3d2d..a8ac9cd 100644
--- a/Bcore/src/main/java/top/niunaijun/jnihook/jni/JniHook.java
+++ b/Bcore/src/main/java/top/niunaijun/jnihook/jni/JniHook.java
@@ -3,14 +3,7 @@ package top.niunaijun.jnihook.jni;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-/**
- * updated by alex5402 on 3/7/21.
- * * ∧_∧
- * (`・ω・∥
- * 丶 つ0
- * しーJ
- *
- */
+
public final class JniHook {
public static final int NATIVE_OFFSET = 0;
diff --git a/Bcore/src/main/res/xml/filepath.xml b/Bcore/src/main/res/xml/filepath.xml
index 115a24b..64a3555 100644
--- a/Bcore/src/main/res/xml/filepath.xml
+++ b/Bcore/src/main/res/xml/filepath.xml
@@ -1,13 +1,13 @@
-
+
-
+
-
-
-
+
+
+
-
-
+
+
diff --git a/app/build.gradle b/app/build.gradle
index 23f700c..9c56cdb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -21,7 +21,7 @@ android {
abi {
enable true
reset()
- //noinspection ChromeOsAbiSupport
+
include 'armeabi-v7a', "arm64-v8a"
universalApk true
}
@@ -36,14 +36,14 @@ android {
}
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
+ sourceCompatibility JavaVersion.VERSION_21
+ targetCompatibility JavaVersion.VERSION_21
}
buildFeatures {
viewBinding true
}
kotlinOptions {
- jvmTarget = '17'
+ jvmTarget = '21'
}
applicationVariants.configureEach { variant ->
@@ -66,25 +66,25 @@ dependencies {
androidTestImplementation libs.espresso.core
implementation "androidx.preference:preference-ktx:1.1.1"
- //viewModel liveData lifecycle
+
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
- //列表
+
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.gitee.cbfg5210:RVAdapter:0.3.7'
- //searchView
+
implementation 'com.github.Othershe:CornerLabelView:1.0.0'
- //dialog
+
implementation 'com.github.nukc.stateview:kotlin:2.2.0'
- //加载dialog
+
implementation 'com.github.Ferfalk:SimpleSearchView:0.2.0'
implementation 'com.tbuonomo:dotsindicator:4.2'
- // osmdroid
+
implementation 'org.osmdroid:osmdroid-android:6.1.11'
- //viewPager2 指示点
+
implementation 'com.afollestad.material-dialogs:core:3.3.0'
implementation 'com.afollestad.material-dialogs:input:3.3.0'
@@ -92,7 +92,7 @@ dependencies {
- // WorkManager
+
implementation 'androidx.work:work-runtime:2.7.1'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 80b647d..66ec39f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,11 +2,11 @@
-
+
-
+
diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/App.kt b/app/src/main/java/top/niunaijun/blackboxa/app/App.kt
index e03abd6..5158f30 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/app/App.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/app/App.kt
@@ -6,13 +6,7 @@ import android.content.Context
import android.util.Log
import top.niunaijun.blackbox.BlackBoxCore
-/**
- *
- * @Description:
- * @Author: alex5402
- * @CreateDate: Saturday, August 16, 2025
- *
- */
+
class App : Application() {
companion object {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/AppManager.kt b/app/src/main/java/top/niunaijun/blackboxa/app/AppManager.kt
index 2c85d7c..243cc52 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/app/AppManager.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/app/AppManager.kt
@@ -5,10 +5,7 @@ import android.content.SharedPreferences
import android.util.Log
import top.niunaijun.blackboxa.view.main.BlackBoxLoader
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
- */
+
object AppManager {
private const val TAG = "AppManager"
@@ -19,7 +16,7 @@ object AppManager {
} catch (e: Exception) {
Log.e(TAG, "Error creating BlackBoxLoader: ${e.message}")
- BlackBoxLoader() // Try again, but this might fail
+ BlackBoxLoader()
}
}
@@ -29,7 +26,7 @@ object AppManager {
mBlackBoxLoader.getBlackBoxCore()
} catch (e: Exception) {
Log.e(TAG, "Error getting BlackBoxCore: ${e.message}")
- throw e // Re-throw as this is critical
+ throw e
}
}
@@ -39,7 +36,7 @@ object AppManager {
App.getContext().getSharedPreferences("UserRemark", Context.MODE_PRIVATE)
} catch (e: Exception) {
Log.e(TAG, "Error creating SharedPreferences: ${e.message}")
- throw e // Re-throw as this is critical
+ throw e
}
}
@@ -49,7 +46,7 @@ object AppManager {
mBlackBoxLoader.addLifecycleCallback()
} catch (e: Exception) {
Log.e(TAG, "Error in doAttachBaseContext: ${e.message}")
- // Don't re-throw as this might not be critical for app startup
+
}
}
@@ -59,14 +56,14 @@ object AppManager {
initThirdService(context)
} catch (e: Exception) {
Log.e(TAG, "Error in doOnCreate: ${e.message}")
- // Don't re-throw as this might not be critical for app startup
+
}
}
private fun initThirdService(context: Context) {
try {
- // Initialize any third-party services here
- // Currently empty, but with error handling for future additions
+
+
} catch (e: Exception) {
Log.e(TAG, "Error in initThirdService: ${e.message}")
}
diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/BaseActivityLifecycleCallback.kt b/app/src/main/java/top/niunaijun/blackboxa/app/rocker/BaseActivityLifecycleCallback.kt
index 7afaa80..6a5cf2b 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/BaseActivityLifecycleCallback.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/app/rocker/BaseActivityLifecycleCallback.kt
@@ -4,12 +4,7 @@ import android.app.Activity
import android.app.Application
import android.os.Bundle
-/**
- *
- * @Description:
- * @Author: alex5402
- * @CreateDate: Saturday, August 16, 2025
- */
+
interface BaseActivityLifecycleCallback : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/RockerManager.kt b/app/src/main/java/top/niunaijun/blackboxa/app/rocker/RockerManager.kt
index 4453601..4a32d27 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/app/rocker/RockerManager.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/app/rocker/RockerManager.kt
@@ -16,58 +16,16 @@ import top.niunaijun.blackbox.fake.frameworks.BLocationManager
import top.niunaijun.blackboxa.app.App
import top.niunaijun.blackboxa.widget.EnFloatView
-/**
- * RockerManager - Advanced GPS Location Spoofing with Floating Joystick Control
- *
- * @Description: Provides a floating joystick/rocker control for real-time GPS location manipulation
- * ```
- * in virtual apps. Allows users to move their fake GPS location by dragging a joystick.
- *
- * @Features
- * ```
- * :
- * - Floating joystick that appears on screen
- * - Real-time GPS coordinate updates
- * - Precise distance and angle control
- * - App-specific location spoofing
- * - Automatic activity lifecycle management
- *
- * @Usage:
- * 1. RockerManager automatically initializes when virtual apps start
- * 2. A floating joystick appears on the left side of the screen
- * 3. Drag the joystick to change GPS location:
- * ```
- * - Distance: How far to move (in meters)
- * - Angle: Direction to move (0-360 degrees)
- * ```
- * 4. Location updates happen in real-time as you move the joystick
- *
- * @Permissions Required:
- * - SYSTEM_ALERT_WINDOW: To show floating view over other apps
- * - ACCESS_FINE_LOCATION: To access GPS location services
- * - ACCESS_COARSE_LOCATION: For approximate location access
- *
- * @Requirements:
- * - Fake location must be enabled in BlackBox
- * - User must grant overlay and location permissions
- * - Virtual app must be running
- *
- * @Author: kotlinMiku
- * @CreateDate: 2022/3/19 19:37
- * @LastModified: 2024 - Enhanced with better error handling and permissions
- */
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
- */
+
+
object RockerManager {
private const val TAG = "RockerManager"
private var isInitialized = false
- // Earth radius constants for coordinate calculations
- private const val Ea = 6378137.0 // Equator radius (meters)
- private const val Eb = 6356725.0 // Polar radius (meters)
+
+ private const val Ea = 6378137.0
+ private const val Eb = 6356725.0
fun init(application: Application?, userId: Int) {
try {
@@ -81,7 +39,7 @@ object RockerManager {
return
}
- // Check if required permissions are granted
+
if (!checkPermissions(application)) {
Log.w(TAG, "Required permissions not granted, RockerManager cannot initialize")
Log.w(TAG, "Please grant: ${getRequiredPermissions().joinToString(", ")}")
@@ -106,7 +64,7 @@ object RockerManager {
return
}
- // Register activity lifecycle callbacks for floating view management
+
application.registerActivityLifecycleCallbacks(
object : BaseActivityLifecycleCallback {
override fun onActivityStarted(activity: Activity) {
@@ -189,11 +147,11 @@ object RockerManager {
"Changing location - Distance: ${distance}m, Angle: ${angle}°, Current: ${location.latitude}, ${location.longitude}"
)
- // Calculate new coordinates based on joystick input
+
val dx = distance * sin(angle * Math.PI / 180.0)
val dy = distance * cos(angle * Math.PI / 180.0)
- // Use ellipsoid model for more accurate coordinate calculations
+
val ec = Eb + (Ea - Eb) * (90.0 - location.latitude) / 90.0
val ed = ec * cos(location.latitude * Math.PI / 180)
@@ -202,7 +160,7 @@ object RockerManager {
val newLocation = BLocation(newLat, newLng)
- // Update the location
+
BLocationManager.get().setLocation(userId, packageName, newLocation)
Log.d(TAG, "Location updated - New: ${newLat}, ${newLng}")
@@ -212,15 +170,15 @@ object RockerManager {
}
}
- /** Check if RockerManager is currently initialized and active */
+
fun isActive(): Boolean {
return isInitialized
}
- /** Check if required permissions are granted for RockerManager to work */
+
fun checkPermissions(context: Context): Boolean {
return try {
- // Check if overlay permission is granted (required for floating view)
+
val hasOverlayPermission = android.provider.Settings.canDrawOverlays(context)
if (!hasOverlayPermission) {
Log.w(
@@ -230,7 +188,7 @@ object RockerManager {
return false
}
- // Check if location permissions are granted
+
val hasLocationPermission =
context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) ==
android.content.pm.PackageManager.PERMISSION_GRANTED
@@ -247,7 +205,7 @@ object RockerManager {
}
}
- /** Get a list of required permissions for RockerManager */
+
fun getRequiredPermissions(): List {
return listOf(
android.Manifest.permission.SYSTEM_ALERT_WINDOW,
@@ -256,7 +214,7 @@ object RockerManager {
)
}
- /** Clean up resources (useful for testing or when disabling the feature) */
+
fun cleanup() {
try {
isInitialized = false
diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/AppInfo.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/AppInfo.kt
index b41786a..38f719d 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/bean/AppInfo.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/bean/AppInfo.kt
@@ -2,10 +2,5 @@ package top.niunaijun.blackboxa.bean
import android.graphics.drawable.Drawable
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 21:57
- */
+
data class AppInfo(val name:String,val icon:Drawable?,val packageName:String,val sourceDir:String,val isXpModule:Boolean)
\ No newline at end of file
diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/GmsBean.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/GmsBean.kt
index c9d5bcd..c1bc3fa 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/bean/GmsBean.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/bean/GmsBean.kt
@@ -1,11 +1,6 @@
package top.niunaijun.blackboxa.bean
-/**
- *
- * @Description:
- * @Author: BlackBox
- * @CreateDate: 2022/3/2 21:30
- */
+
data class GmsBean(val userID:Int,val userName:String,var isInstalledGms:Boolean)
diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/InstalledAppBean.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/InstalledAppBean.kt
index 268eddd..4731075 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/bean/InstalledAppBean.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/bean/InstalledAppBean.kt
@@ -2,10 +2,5 @@ package top.niunaijun.blackboxa.bean
import android.graphics.drawable.Drawable
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2022/3/6 19:26
- */
+
data class InstalledAppBean(val name:String, val icon: Drawable?, val packageName:String, val sourceDir:String, val isInstall:Boolean)
diff --git a/app/src/main/java/top/niunaijun/blackboxa/bean/XpModuleInfo.kt b/app/src/main/java/top/niunaijun/blackboxa/bean/XpModuleInfo.kt
index 59332df..6dabeca 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/bean/XpModuleInfo.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/bean/XpModuleInfo.kt
@@ -2,12 +2,7 @@ package top.niunaijun.blackboxa.bean
import android.graphics.drawable.Drawable
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/5/2 21:03
- */
+
data class XpModuleInfo(
val name: String,
val desc: String,
diff --git a/app/src/main/java/top/niunaijun/blackboxa/biz/cache/AppSharedPreferenceDelegate.kt b/app/src/main/java/top/niunaijun/blackboxa/biz/cache/AppSharedPreferenceDelegate.kt
index 0ef7878..425b62b 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/biz/cache/AppSharedPreferenceDelegate.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/biz/cache/AppSharedPreferenceDelegate.kt
@@ -6,10 +6,7 @@ import androidx.core.content.edit
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
-/**
- * updated by alex5402 on 4/9/21.
- * * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
- */
+
open class AppSharedPreferenceDelegate(
context: Context,
private val default: Data,
diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/AppsRepository.kt b/app/src/main/java/top/niunaijun/blackboxa/data/AppsRepository.kt
index 856a562..29df428 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/data/AppsRepository.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/data/AppsRepository.kt
@@ -15,32 +15,27 @@ import top.niunaijun.blackboxa.bean.InstalledAppBean
import top.niunaijun.blackboxa.util.MemoryManager
import top.niunaijun.blackboxa.util.getString
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 23:05
- */
+
class AppsRepository {
val TAG: String = "AppsRepository"
private var mInstalledList = mutableListOf()
- /** Safely load app label with fallback to package name */
+
private fun safeLoadAppLabel(applicationInfo: ApplicationInfo): String {
return try {
BlackBoxCore.getPackageManager().getApplicationLabel(applicationInfo).toString()
} catch (e: Exception) {
Log.w(TAG, "Failed to load label for ${applicationInfo.packageName}: ${e.message}")
- applicationInfo.packageName // Fallback to package name
+ applicationInfo.packageName
}
}
- /** Safely load app icon with fallback to null */
+
private fun safeLoadAppIcon(
applicationInfo: ApplicationInfo
): android.graphics.drawable.Drawable? {
return try {
- // Check if we should skip icon loading to save memory
+
if (MemoryManager.shouldSkipIconLoading()) {
Log.w(
TAG,
@@ -51,10 +46,10 @@ class AppsRepository {
val icon = BlackBoxCore.getPackageManager().getApplicationIcon(applicationInfo)
- // Optimize icon for memory efficiency
+
if (icon is android.graphics.drawable.BitmapDrawable) {
val bitmap = icon.bitmap
- // If icon is too large, scale it down to save memory
+
if (bitmap.width > 96 || bitmap.height > 96) {
try {
val scaledBitmap =
@@ -79,7 +74,7 @@ class AppsRepository {
}
} catch (e: Exception) {
Log.w(TAG, "Failed to load icon for ${applicationInfo.packageName}: ${e.message}")
- null // Fallback to null icon
+ null
}
}
@@ -99,7 +94,7 @@ class AppsRepository {
if (!AbiUtils.isSupport(file)) continue
- // Filter out BlackBox apps to prevent cloning
+
if (BlackBoxCore.get().isBlackBoxApp(installedApplication.packageName)) {
Log.d(
TAG,
@@ -115,7 +110,7 @@ class AppsRepository {
safeLoadAppLabel(installedApplication),
safeLoadAppIcon(
installedApplication
- ), // Remove the !! operator to allow null icons
+ ),
installedApplication.packageName,
installedApplication.sourceDir,
isXpModule
@@ -150,7 +145,7 @@ class AppsRepository {
mInstalledList.map {
InstalledAppBean(
it.name,
- it.icon, // Remove the !! operator to allow null icons
+ it.icon,
it.packageName,
it.sourceDir,
blackBoxCore.isInstalled(it.packageName, userID)
@@ -168,7 +163,7 @@ class AppsRepository {
fun getVmInstallList(userId: Int, appsLiveData: MutableLiveData>) {
try {
- // Check memory status before starting
+
if (MemoryManager.isMemoryCritical()) {
Log.w(
TAG,
@@ -179,7 +174,7 @@ class AppsRepository {
val blackBoxCore = BlackBoxCore.get()
- // Add debugging for users
+
val users = blackBoxCore.users
Log.d(TAG, "getVmInstallList: userId=$userId, total users=${users.size}")
users.forEach { user -> Log.d(TAG, "User: id=${user.id}, name=${user.name}") }
@@ -187,7 +182,7 @@ class AppsRepository {
val sortListData = AppManager.mRemarkSharedPreferences.getString("AppList$userId", "")
val sortList = sortListData?.split(",")
- // Add retry mechanism for getting installed applications
+
var applicationList: List? = null
var retryCount = 0
val maxRetries = 3
@@ -201,7 +196,7 @@ class AppsRepository {
"getVmInstallList: Attempt ${retryCount + 1} returned null, retrying..."
)
retryCount++
- Thread.sleep(100) // Small delay before retry
+ Thread.sleep(100)
}
} catch (e: Exception) {
Log.e(
@@ -210,12 +205,12 @@ class AppsRepository {
)
retryCount++
if (retryCount < maxRetries) {
- Thread.sleep(200) // Longer delay for errors
+ Thread.sleep(200)
}
}
}
- // Add null check for applicationList
+
if (applicationList == null) {
Log.e(
TAG,
@@ -225,7 +220,7 @@ class AppsRepository {
return
}
- // Add debugging
+
Log.d(
TAG,
"getVmInstallList: userId=$userId, applicationList.size=${applicationList.size}"
@@ -238,23 +233,23 @@ class AppsRepository {
val appInfoList = mutableListOf()
- // Sort the application list if sort data exists
+
val sortedApplicationList =
if (!sortList.isNullOrEmpty()) {
try {
applicationList.sortedWith(AppsSortComparator(sortList))
} catch (e: Exception) {
Log.e(TAG, "getVmInstallList: Error sorting applications: ${e.message}")
- applicationList // Return unsorted list if sorting fails
+ applicationList
}
} else {
applicationList
}
- // Process each application with enhanced error handling
+
sortedApplicationList.forEachIndexed { index, applicationInfo ->
try {
- // Check memory periodically during processing
+
if (index > 0 && index % 25 == 0) {
if (MemoryManager.isMemoryCritical()) {
Log.w(TAG, "Memory critical during processing, forcing GC")
@@ -262,7 +257,7 @@ class AppsRepository {
}
}
- // Add null check for applicationInfo
+
if (applicationInfo == null) {
Log.w(
TAG,
@@ -271,7 +266,7 @@ class AppsRepository {
return@forEachIndexed
}
- // Validate package name
+
if (applicationInfo.packageName.isNullOrBlank()) {
Log.w(
TAG,
@@ -285,7 +280,7 @@ class AppsRepository {
safeLoadAppLabel(applicationInfo),
safeLoadAppIcon(
applicationInfo
- ), // Remove the !! operator to allow null icons
+ ),
applicationInfo.packageName,
applicationInfo.sourceDir ?: "",
false
@@ -293,7 +288,7 @@ class AppsRepository {
appInfoList.add(info)
- // Log progress for large lists
+
if (index > 0 && index % 50 == 0) {
Log.d(
TAG,
@@ -305,7 +300,7 @@ class AppsRepository {
TAG,
"getVmInstallList: Error processing app at index $index (${applicationInfo?.packageName}): ${e.message}"
)
- // Continue processing other apps instead of failing completely
+
}
}
@@ -314,8 +309,8 @@ class AppsRepository {
"getVmInstallList: processed ${appInfoList.size} apps - ${MemoryManager.getMemoryInfo()}"
)
- // If no virtual apps found, show empty list (correct behavior for new users)
- // Do NOT load regular installed apps as fallback - this causes the bug
+
+
if (appInfoList.isEmpty()) {
Log.d(
TAG,
@@ -328,12 +323,12 @@ class AppsRepository {
)
}
- // Post the result safely
+
try {
appsLiveData.postValue(appInfoList)
} catch (e: Exception) {
Log.e(TAG, "getVmInstallList: Error posting to LiveData: ${e.message}")
- // Try to post on main thread as fallback
+
try {
android.os.Handler(android.os.Looper.getMainLooper()).post {
try {
@@ -364,18 +359,18 @@ class AppsRepository {
fun installApk(source: String, userId: Int, resultLiveData: MutableLiveData) {
try {
- // Check if this is an attempt to install BlackBox app
+
if (source.contains("blackbox") ||
source.contains("niunaijun") ||
source.contains("vspace") ||
source.contains("virtual")
) {
- // Additional check for the actual BlackBox app
+
try {
val blackBoxCore = BlackBoxCore.get()
val hostPackageName = BlackBoxCore.getHostPkg()
- // If it's a file path, try to check the package name
+
if (!URLUtil.isValidUrl(source)) {
val file = File(source)
if (file.exists()) {
@@ -449,7 +444,7 @@ class AppsRepository {
}
}
- /** 倒序递归扫描用户, 如果用户是空的,就删除用户,删除用户备注,删除应用排序列表 */
+
private fun scanUser() {
try {
val blackBoxCore = BlackBoxCore.get()
@@ -475,12 +470,7 @@ class AppsRepository {
}
}
- /**
- * 更新排序列表
- * @param userID Int
- * @param pkg String
- * @param isAdd Boolean true是添加,false是移除
- */
+
private fun updateAppSortList(userID: Int, pkg: String, isAdd: Boolean) {
try {
val savedSortList = AppManager.mRemarkSharedPreferences.getString("AppList$userID", "")
@@ -505,7 +495,7 @@ class AppsRepository {
}
}
- /** 保存排序后的apk顺序 */
+
fun updateApkOrder(userID: Int, dataList: List) {
try {
AppManager.mRemarkSharedPreferences.edit().apply {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/AppsSortCompon.kt b/app/src/main/java/top/niunaijun/blackboxa/data/AppsSortCompon.kt
index 25430ec..c792e36 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/data/AppsSortCompon.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/data/AppsSortCompon.kt
@@ -2,12 +2,7 @@ package top.niunaijun.blackboxa.data
import android.content.pm.ApplicationInfo
-/**
- *
- * @Description: app sort
- * @Author: BlackBox
- * @CreateDate: 2022/2/27 23:21
- */
+
class AppsSortComparator(private val sortedList: List) : Comparator {
override fun compare(o1: ApplicationInfo?, o2: ApplicationInfo?): Int {
if (o1 == null || o2 == null) {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/FakeLocationRepository.kt b/app/src/main/java/top/niunaijun/blackboxa/data/FakeLocationRepository.kt
index 6347935..a7e8f29 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/data/FakeLocationRepository.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/data/FakeLocationRepository.kt
@@ -8,16 +8,7 @@ import top.niunaijun.blackbox.entity.location.BLocation
import top.niunaijun.blackbox.fake.frameworks.BLocationManager
import top.niunaijun.blackboxa.bean.FakeLocationBean
-/**
- * getInstalledApplications and query fake location of each of them.
- * mode and location configuration are respectively concept.
- * Location config just store the location but mode decides whether turns on it
- * each application has three pattern.Global: use global fake location,
- * self: use own config, close: use real config
- * @Description:
- * @Author: BlackBoxing
- * @CreateDate: 2022/3/12 21:14
- */
+
class FakeLocationRepository {
val TAG: String = "FakeLocationRepository"
@@ -44,15 +35,15 @@ class FakeLocationRepository {
val installedList = mutableListOf()
val installedApplications: List =
BlackBoxCore.get().getInstalledApplications(0, userID)
- // List -> List
+
for (installedApplication in installedApplications) {
-// val file = File(installedApplication.sourceDir)
-//
-// if ((installedApplication.flags and ApplicationInfo.FLAG_SYSTEM) != 0) continue
-//
-// if (!AbiUtils.isSupport(file)) continue
-//
-// val isXpModule = BlackBoxCore.get().isXposedModule(file)
+
+
+
+
+
+
+
val info = FakeLocationBean(
userID,
diff --git a/app/src/main/java/top/niunaijun/blackboxa/data/GmsRepository.kt b/app/src/main/java/top/niunaijun/blackboxa/data/GmsRepository.kt
index a4da8f2..d5b06fe 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/data/GmsRepository.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/data/GmsRepository.kt
@@ -8,12 +8,7 @@ import top.niunaijun.blackboxa.bean.GmsBean
import top.niunaijun.blackboxa.bean.GmsInstallBean
import top.niunaijun.blackboxa.util.getString
-/**
- *
- * @Description:
- * @Author: BlackBox
- * @CreateDate: 2022/3/2 21:14
- */
+
class GmsRepository {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ContextUtil.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ContextUtil.kt
index 941b0b2..885f4f1 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/ContextUtil.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/ContextUtil.kt
@@ -5,12 +5,7 @@ import android.content.Intent
import android.net.Uri
import android.provider.Settings
-/**
- *
- * @Description:
- * @Author: kotlinMiku
- * @CreateDate: 2022/4/17 16:32
- */
+
object ContextUtil {
fun Context.openAppSystemSettings() {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/InjectionUtil.kt b/app/src/main/java/top/niunaijun/blackboxa/util/InjectionUtil.kt
index 64750b7..8ecc02d 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/InjectionUtil.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/InjectionUtil.kt
@@ -10,12 +10,7 @@ import top.niunaijun.blackboxa.view.gms.GmsFactory
import top.niunaijun.blackboxa.view.list.ListFactory
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 22:38
- */
+
object InjectionUtil {
private val appsRepository = AppsRepository()
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/MathUtil.java b/app/src/main/java/top/niunaijun/blackboxa/util/MathUtil.java
index 81543c1..76df8fb 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/MathUtil.java
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/MathUtil.java
@@ -8,44 +8,23 @@ public class MathUtil {
public MathUtil() {
}
- /**
- * Get the distance between two points.
- *
- * @param A Point A
- * @param B Point B
- * @return the distance between point A and point B.
- */
+
public static int getDistance(PointF A, PointF B) {
return (int) Math.sqrt(Math.pow(A.x - B.x, 2) + Math.pow(A.y - B.y, 2));
}
- /**
- * Get the distance between two points.
- */
+
public static int getDistance(float x1, float y1, float x2, float y2) {
return (int) Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
- /**
- * Get the coordinates of a point on the line by cut length.
- *
- * @param A Point A
- * @param B Point B
- * @param cutLength cut length
- * @return the point.
- */
+
public static Point getPointByCutLength(Point A, Point B, int cutLength) {
float radian = getRadian(A, B);
return new Point(A.x + (int) (cutLength * Math.cos(radian)), A.y + (int) (cutLength * Math.sin(radian)));
}
- /**
- * Get the radian between current line(determined by point A and B) and horizontal line.
- *
- * @param A point A
- * @param B point B
- * @return the radian
- */
+
public static float getRadian(Point A, Point B) {
float lenA = B.x - A.x;
float lenB = B.y - A.y;
@@ -56,22 +35,12 @@ public class MathUtil {
}
- /**
- * angle to radian
- *
- * @param angle angle
- * @return radian
- */
+
public static double angle2Radian(double angle) {
return angle / 180 * Math.PI;
}
- /**
- * radian to angle
- *
- * @param radian radian
- * @return angle
- */
+
public static double radian2Angle(double radian) {
return radian / Math.PI * 180;
}
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/MemoryManager.kt b/app/src/main/java/top/niunaijun/blackboxa/util/MemoryManager.kt
index c4875cc..46e0fd1 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/MemoryManager.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/MemoryManager.kt
@@ -3,18 +3,15 @@ package top.niunaijun.blackboxa.util
import android.util.Log
import java.lang.Runtime
-/** Memory management utility to prevent crashes during memory-intensive operations */
-/**
- * created by alex5402 on 4/9/21.
- * * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
- */
+
+
object MemoryManager {
private const val TAG = "MemoryManager"
- private const val MEMORY_THRESHOLD = 0.8 // 80% memory usage threshold
- private const val CRITICAL_MEMORY_THRESHOLD = 0.9 // 90% memory usage threshold
+ private const val MEMORY_THRESHOLD = 0.8
+ private const val CRITICAL_MEMORY_THRESHOLD = 0.9
- /** Check if memory usage is within safe limits */
+
fun isMemorySafe(): Boolean {
return try {
val runtime = Runtime.getRuntime()
@@ -25,11 +22,11 @@ object MemoryManager {
memoryUsage < MEMORY_THRESHOLD
} catch (e: Exception) {
Log.e(TAG, "Error checking memory: ${e.message}")
- true // Assume safe if we can't check
+ true
}
}
- /** Check if memory usage is critical */
+
fun isMemoryCritical(): Boolean {
return try {
val runtime = Runtime.getRuntime()
@@ -40,11 +37,11 @@ object MemoryManager {
memoryUsage > CRITICAL_MEMORY_THRESHOLD
} catch (e: Exception) {
Log.e(TAG, "Error checking critical memory: ${e.message}")
- false // Assume not critical if we can't check
+ false
}
}
- /** Get current memory usage percentage */
+
fun getMemoryUsagePercentage(): Int {
return try {
val runtime = Runtime.getRuntime()
@@ -59,7 +56,7 @@ object MemoryManager {
}
}
- /** Force garbage collection if memory usage is high */
+
fun forceGarbageCollectionIfNeeded(): Boolean {
return try {
if (isMemoryCritical()) {
@@ -68,7 +65,7 @@ object MemoryManager {
"Memory usage critical (${getMemoryUsagePercentage()}%), forcing garbage collection"
)
System.gc()
- Thread.sleep(100) // Give GC time to work
+ Thread.sleep(100)
true
} else {
false
@@ -79,7 +76,7 @@ object MemoryManager {
}
}
- /** Optimize memory for RecyclerView operations */
+
fun optimizeMemoryForRecyclerView() {
try {
val memoryUsage = getMemoryUsagePercentage()
@@ -87,10 +84,10 @@ object MemoryManager {
if (memoryUsage > 70) {
Log.d(TAG, "Memory usage high (${memoryUsage}%), optimizing for RecyclerView")
- // Force garbage collection
+
System.gc()
- // Clear any caches if possible
+
try {
val runtime = Runtime.getRuntime()
runtime.gc()
@@ -103,18 +100,18 @@ object MemoryManager {
}
}
- /** Check if we should skip icon loading to save memory */
+
fun shouldSkipIconLoading(): Boolean {
return try {
val memoryUsage = getMemoryUsagePercentage()
- memoryUsage > 75 // Skip icon loading if memory usage > 75%
+ memoryUsage > 75
} catch (e: Exception) {
Log.e(TAG, "Error checking if should skip icon loading: ${e.message}")
false
}
}
- /** Get memory info for debugging */
+
fun getMemoryInfo(): String {
return try {
val runtime = Runtime.getRuntime()
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/Resolution.java b/app/src/main/java/top/niunaijun/blackboxa/util/Resolution.java
index 307d82a..1e7f2c6 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/Resolution.java
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/Resolution.java
@@ -19,74 +19,17 @@ import java.lang.reflect.Field;
public class Resolution {
private static final String TAG = "UtilsScreen";
- /**
- * Gets the width of the display, in pixels.
- *
- * Note that this value should not be used for computing layouts, since a
- * device will typically have screen decoration (such as a status bar) along
- * the edges of the display that reduce the amount of application space
- * available from the size returned here. Layouts should instead use the
- * window size.
- *
- * The size is adjusted based on the current rotation of the display.
- *
- * The size returned by this method does not necessarily represent the
- * actual raw size (native resolution) of the display. The returned size may
- * be adjusted to exclude certain system decoration elements that are always
- * visible. It may also be scaled to provide compatibility with older
- * applications that were originally designed for smaller displays.
- *
- * @return Screen width in pixels.
- */
+
public static int getScreenWidth(Context context) {
return getScreenSize(context, null).x;
}
- /**
- * Gets the height of the display, in pixels.
- *
- * Note that this value should not be used for computing layouts, since a
- * device will typically have screen decoration (such as a status bar) along
- * the edges of the display that reduce the amount of application space
- * available from the size returned here. Layouts should instead use the
- * window size.
- *
- * The size is adjusted based on the current rotation of the display.
- *
- * The size returned by this method does not necessarily represent the
- * actual raw size (native resolution) of the display. The returned size may
- * be adjusted to exclude certain system decoration elements that are always
- * visible. It may also be scaled to provide compatibility with older
- * applications that were originally designed for smaller displays.
- *
- * @return Screen height in pixels.
- */
+
public static int getScreenHeight(Context context) {
return getScreenSize(context, null).y;
}
- /**
- * Gets the size of the display, in pixels.
- *
- * Note that this value should not be used for computing layouts, since a
- * device will typically have screen decoration (such as a status bar) along
- * the edges of the display that reduce the amount of application space
- * available from the size returned here. Layouts should instead use the
- * window size.
- *
- * The size is adjusted based on the current rotation of the display.
- *
- * The size returned by this method does not necessarily represent the
- * actual raw size (native resolution) of the display. The returned size may
- * be adjusted to exclude certain system decoration elements that are always
- * visible. It may also be scaled to provide compatibility with older
- * applications that were originally designed for smaller displays.
- *
- * @param outSize null-ok. If it is null, will create a Point instance inside,
- * otherwise use it to fill the output. NOTE if it is not null,
- * it will be the returned value.
- * @return Screen size in pixels, the x is the width, the y is the height.
- */
+
@SuppressLint("NewApi")
public static Point getScreenSize(Context context, Point outSize) {
WindowManager wm = (WindowManager) context
@@ -94,18 +37,18 @@ public class Resolution {
Point ret = outSize == null ? new Point() : outSize;
if (Build.VERSION.SDK_INT >= 30) {
- // Use the modern approach for Android 11+
+
android.view.WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
android.graphics.Rect bounds = windowMetrics.getBounds();
ret.x = bounds.width();
ret.y = bounds.height();
} else if (Build.VERSION.SDK_INT >= 13) {
- // Use getSize for Android 3.0+
+
@SuppressWarnings("deprecation")
final Display defaultDisplay = wm.getDefaultDisplay();
defaultDisplay.getSize(ret);
} else {
- // Fallback for older versions
+
@SuppressWarnings("deprecation")
final Display defaultDisplay = wm.getDefaultDisplay();
ret.x = defaultDisplay.getWidth();
@@ -114,13 +57,7 @@ public class Resolution {
return ret;
}
- /**
- * This method converts dp unit to equivalent pixels, depending on device density.
- *
- * @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
- * @param context Context to get resources and device specific display metrics
- * @return A float value to represent px equivalent to dp depending on device density
- */
+
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
@@ -128,13 +65,7 @@ public class Resolution {
return px;
}
- /**
- * This method converts device specific pixels to density independent pixels.
- *
- * @param px A value in px (pixels) unit. Which we need to convert into db
- * @param context Context to get resources and device specific display metrics
- * @return A float value to represent dp equivalent to px value
- */
+
public static float convertPixelsToDp(float px, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
@@ -142,11 +73,9 @@ public class Resolution {
return dp;
}
- ///////////////////////////////////////////////////////////////////////
+
- /**
- * 获取屏幕密度
- */
+
public static float getDensity(Context context) {
float density = 0f;
if (context== null) {
@@ -160,9 +89,7 @@ public class Resolution {
return density;
}
- /**
- * 检查分辨率是否为本机
- */
+
public static boolean checkPix(Activity context, int width, int height) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
DisplayMetrics metrics = new DisplayMetrics();
@@ -173,50 +100,34 @@ public class Resolution {
}
}
- /**
- * 获取屏幕分辨率:宽
- */
+
public static int getScreenPixWidth(Context context) {
return context.getResources().getDisplayMetrics().widthPixels;
}
- /**
- * 获取屏幕分辨率:高
- */
+
public static int getScreenPixHeight(Context context) {
return context.getResources().getDisplayMetrics().heightPixels;
}
- /**
- * dipתpx
- */
+
public static int dipToPx(Context context, int dip) {
return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f);
}
- /**
- * pxתdip
- */
+
public static int pxToDip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
- /**
- * 将sp值转换为px值,保证文字大小不变
- *
- * @param context
- * @param spValue
- * @return
- */
+
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
- /**
- * 隐藏软键盘
- */
+
public static void hideInputMethod(View view) {
InputMethodManager imm = (InputMethodManager) view.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -225,9 +136,7 @@ public class Resolution {
}
}
- /**
- * 显示软键盘
- */
+
public static void showInputMethod(View view) {
InputMethodManager imm = (InputMethodManager) view.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -236,11 +145,9 @@ public class Resolution {
}
}
- /**
- * 多少时间后显示软键盘
- */
+
public static void showInputMethod(final View view, long delayMillis) {
- // 显示输入法
+
new Handler().postDelayed(new Runnable() {
@Override
@@ -251,9 +158,7 @@ public class Resolution {
}, delayMillis);
}
- /**
- * 判断手机是否在锁屏状态 true锁屏 false未锁屏
- */
+
public static boolean isScreenLocked(Context c) {
KeyguardManager mKeyguardManager = (KeyguardManager) c
.getSystemService(Context.KEYGUARD_SERVICE);
@@ -266,7 +171,7 @@ public class Resolution {
Class> c = null;
Object obj = null;
Field field = null;
- int x = 0, sbar = 38;//默认为38,貌似大部分是这样的
+ int x = 0, sbar = 38;
try {
c = Class.forName("com.android.internal.R$dimen");
@@ -280,23 +185,23 @@ public class Resolution {
return sbar;
}
- //http://stackoverflow.com/questions/20264268/how-to-get-height-and-width-of-navigation-bar-programmatically
- //获取屏幕下方导航栏高度
+
+
public static Point getNavigationBarSize(Context context) {
Point appUsableSize = getScreenSize(context, null);
Point realScreenSize = getRealScreenSize(context);
-// // navigation bar on the right
-// if (appUsableSize.x < realScreenSize.x) {
-// return new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y);
-// }
- // navigation bar at the bottom
+
+
+
+
+
if (appUsableSize.y < realScreenSize.y) {
return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y);
}
- // navigation bar is not present
+
return new Point();
}
@@ -306,18 +211,18 @@ public class Resolution {
Point size = new Point();
if (Build.VERSION.SDK_INT >= 30) {
- // Use the modern approach for Android 11+
+
android.view.WindowMetrics windowMetrics = windowManager.getCurrentWindowMetrics();
android.graphics.Rect bounds = windowMetrics.getBounds();
size.x = bounds.width();
size.y = bounds.height();
} else if (Build.VERSION.SDK_INT >= 17) {
- // Use getRealSize for Android 4.2+
+
@SuppressWarnings("deprecation")
Display display = windowManager.getDefaultDisplay();
display.getRealSize(size);
} else if (Build.VERSION.SDK_INT >= 14) {
- // Fallback for older versions
+
@SuppressWarnings("deprecation")
Display display = windowManager.getDefaultDisplay();
try {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ShortcutUtil.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ShortcutUtil.kt
index ef0c655..51fe650 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/ShortcutUtil.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/ShortcutUtil.kt
@@ -15,20 +15,11 @@ import top.niunaijun.blackboxa.bean.AppInfo
import top.niunaijun.blackboxa.util.ContextUtil.openAppSystemSettings
import top.niunaijun.blackboxa.view.main.ShortcutActivity
-/**
- *
- * @Description: 桌面快捷方式 工具类
- * @Author: BlackBox
- * @CreateDate: 2022/2/27 22:56
- */
+
object ShortcutUtil {
- /**
- * 创建桌面快捷方式
- * @param userID Int userID
- * @param info AppInfo
- */
+
fun createShortcut(context: Context,userID: Int, info: AppInfo) {
if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)) {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ToastEx.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ToastEx.kt
index ef9e170..419f868 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/ToastEx.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/ToastEx.kt
@@ -5,12 +5,7 @@ import android.widget.Toast
import androidx.annotation.StringRes
import top.niunaijun.blackboxa.app.App
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/5/2 0:13
- */
+
var toastImpl:Toast? = null
fun Context.toast(msg:String){
diff --git a/app/src/main/java/top/niunaijun/blackboxa/util/ViewBindingEx.kt b/app/src/main/java/top/niunaijun/blackboxa/util/ViewBindingEx.kt
index 8f184c6..9ffe5b7 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/util/ViewBindingEx.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/util/ViewBindingEx.kt
@@ -7,12 +7,7 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding
-/**
- *
- * @Description: viewBinding 扩展类
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 21:23
- */
+
inline fun Activity.inflate(): Lazy = lazy {
inflateBinding(layoutInflater)
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsAdapter.kt
index 0addcef..4c1f0f0 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsAdapter.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsAdapter.kt
@@ -18,18 +18,13 @@ import android.graphics.Color
import android.view.ViewTreeObserver
import androidx.recyclerview.widget.RecyclerView
-/**
- *
- * @Description: 软件显示界面适配器
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 21:52
- */
+
class AppsAdapter : RVHolderFactory() {
companion object {
private const val TAG = "AppsAdapter"
- private const val MAX_ICON_SIZE = 96 // 48dp * 2 for high density
+ private const val MAX_ICON_SIZE = 96
private val DEFAULT_ICON_COLOR = Color.parseColor("#CCCCCC")
}
@@ -38,7 +33,7 @@ class AppsAdapter : RVHolderFactory() {
AppsVH(inflate(R.layout.item_app, parent))
} catch (e: Exception) {
Log.e(TAG, "Error creating ViewHolder: ${e.message}")
- // Return a fallback ViewHolder to prevent crash
+
FallbackAppsVH(inflate(R.layout.item_app, parent))
}
}
@@ -50,10 +45,10 @@ class AppsAdapter : RVHolderFactory() {
init {
try {
- // Optimize icon loading for better scrolling performance
+
binding.icon.scaleType = ImageView.ScaleType.CENTER_CROP
- // Add view tree observer to optimize icon loading
+
itemView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
if (isAttached) {
@@ -69,20 +64,20 @@ class AppsAdapter : RVHolderFactory() {
override fun setContent(item: AppInfo, isSelected: Boolean, payload: Any?) {
try {
- // Safely set the icon with optimized loading
+
setIconSafely(item.icon, item.packageName)
- // Safely set the name
+
binding.name.text = item.name ?: "Unknown App"
- // Handle XP module label
+
if (item.isXpModule) {
binding.cornerLabel.visibility = View.VISIBLE
} else {
binding.cornerLabel.visibility = View.INVISIBLE
}
- // Mark as attached for optimization
+
isAttached = true
} catch (e: Exception) {
@@ -94,12 +89,12 @@ class AppsAdapter : RVHolderFactory() {
private fun setIconSafely(icon: Drawable?, packageName: String) {
try {
if (icon != null) {
- // Optimize icon for memory efficiency
+
val optimizedIcon = optimizeIcon(icon)
binding.icon.setImageDrawable(optimizedIcon)
currentIcon = optimizedIcon
} else {
- // Set a default placeholder icon
+
binding.icon.setImageDrawable(createDefaultIcon())
currentIcon = null
}
@@ -112,11 +107,11 @@ class AppsAdapter : RVHolderFactory() {
private fun optimizeIcon(icon: Drawable): Drawable {
return try {
- // If it's a BitmapDrawable, ensure it's not too large
+
if (icon is BitmapDrawable) {
val bitmap = icon.bitmap
if (bitmap.width > MAX_ICON_SIZE || bitmap.height > MAX_ICON_SIZE) {
- // Create a scaled down version
+
val scaledBitmap = Bitmap.createScaledBitmap(
bitmap, MAX_ICON_SIZE, MAX_ICON_SIZE, true
)
@@ -153,13 +148,13 @@ class AppsAdapter : RVHolderFactory() {
}
}
- // Fallback ViewHolder for emergency cases
+
class FallbackAppsVH(itemView: View) : RVHolder(itemView) {
val binding = ItemAppBinding.bind(itemView)
override fun setContent(item: AppInfo, isSelected: Boolean, payload: Any?) {
try {
- // Set minimal content to prevent crash
+
binding.icon.setImageDrawable(ColorDrawable(DEFAULT_ICON_COLOR))
binding.name.text = item.name ?: "Unknown App"
binding.cornerLabel.visibility = View.INVISIBLE
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFactory.kt
index dc8c043..037ddd3 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFactory.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFactory.kt
@@ -4,12 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import top.niunaijun.blackboxa.data.AppsRepository
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 22:36
- */
+
@Suppress("UNCHECKED_CAST")
class AppsFactory(private val appsRepository: AppsRepository) : ViewModelProvider.NewInstanceFactory() {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFragment.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFragment.kt
index 740b79f..e4e5cd3 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFragment.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsFragment.kt
@@ -32,12 +32,7 @@ import java.util.*
import kotlin.math.abs
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 22:21
- */
+
class AppsFragment : Fragment() {
var userID: Int = 0
@@ -85,33 +80,33 @@ class AppsFragment : Fragment() {
viewBinding.recyclerView.adapter = mAdapter
- // Enhanced RecyclerView configuration for better performance and crash prevention
+
val layoutManager = GridLayoutManager(requireContext(), 4)
layoutManager.isItemPrefetchEnabled = true
layoutManager.initialPrefetchItemCount = 8
viewBinding.recyclerView.layoutManager = layoutManager
- // Enable view cache for better scrolling performance
+
viewBinding.recyclerView.setItemViewCacheSize(20)
viewBinding.recyclerView.setHasFixedSize(true)
- // Add scroll listener for crash detection and prevention
+
viewBinding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
try {
super.onScrollStateChanged(recyclerView, newState)
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> {
- // Scrolling stopped, optimize memory
+
MemoryManager.optimizeMemoryForRecyclerView()
}
RecyclerView.SCROLL_STATE_DRAGGING -> {
- // User is scrolling, ensure smooth performance
- // Note: Drawing cache is deprecated, using modern alternatives
+
+
}
RecyclerView.SCROLL_STATE_SETTLING -> {
- // Scrolling is settling, prepare for idle state
- // Note: Drawing cache is deprecated, using modern alternatives
+
+
}
}
} catch (e: Exception) {
@@ -122,11 +117,11 @@ class AppsFragment : Fragment() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
try {
super.onScrolled(recyclerView, dx, dy)
- // Monitor scroll performance
+
if (Math.abs(dy) > 100) {
- // Fast scrolling detected, optimize memory
- // Check memory usage during fast scrolling
+
+
if (MemoryManager.isMemoryCritical()) {
Log.w(TAG, "Memory critical during fast scrolling, forcing GC")
MemoryManager.forceGarbageCollectionIfNeeded()
@@ -165,7 +160,7 @@ class AppsFragment : Fragment() {
return viewBinding.root
} catch (e: Exception) {
Log.e(TAG, "Error in onCreateView: ${e.message}")
- // Return a simple view to prevent crash
+
return View(requireContext())
}
}
@@ -183,11 +178,11 @@ class AppsFragment : Fragment() {
try {
super.onStart()
- // Register callback to refresh app list when services become available
+
try {
BlackBoxCore.get().addServiceAvailableCallback {
Log.d(TAG, "Services became available, refreshing app list")
- // Refresh the app list when services are ready
+
viewModel.getInstalledAppsWithRetry(userID)
}
} catch (e: Exception) {
@@ -200,9 +195,7 @@ class AppsFragment : Fragment() {
}
}
- /**
- * 拖拽优化
- */
+
private fun interceptTouch() {
try {
val point = Point()
@@ -213,7 +206,7 @@ class AppsFragment : Fragment() {
try {
when (e.action) {
MotionEvent.ACTION_DOWN -> {
- // Reset scroll state
+
isScrolling = false
scrollStartTime = System.currentTimeMillis()
point.set(0, 0)
@@ -222,7 +215,7 @@ class AppsFragment : Fragment() {
MotionEvent.ACTION_UP -> {
val scrollDuration = System.currentTimeMillis() - scrollStartTime
- // Only show popup if it wasn't a scroll gesture
+
if (!isScrolling && !isMove(point, e) && scrollDuration < 500) {
try {
popupMenu?.show()
@@ -242,13 +235,13 @@ class AppsFragment : Fragment() {
point.y = e.rawY.toInt()
}
- // Check if this is a scroll gesture
+
if (isMove(point, e)) {
isScrolling = true
popupMenu?.dismiss()
}
- // Handle float button visibility
+
isDownAndUp(point, e)
}
}
@@ -298,7 +291,7 @@ class AppsFragment : Fragment() {
private fun onItemMove(fromPosition: Int, toPosition: Int) {
try {
- // Validate positions to prevent crashes
+
val items = mAdapter.getItems()
if (fromPosition < 0 || toPosition < 0 ||
fromPosition >= items.size || toPosition >= items.size) {
@@ -330,7 +323,7 @@ class AppsFragment : Fragment() {
mAdapter.notifyItemMoved(fromPosition, toPosition)
} catch (e: Exception) {
Log.e(TAG, "Error notifying item moved: ${e.message}")
- // Fallback to full refresh if move notification fails
+
mAdapter.notifyDataSetChanged()
}
} catch (e: Exception) {
@@ -474,10 +467,7 @@ class AppsFragment : Fragment() {
}
}
- /**
- * 强行停止软件
- * @param info AppInfo
- */
+
private fun stopApk(info: AppInfo) {
try {
MaterialDialog(requireContext()).show {
@@ -498,10 +488,7 @@ class AppsFragment : Fragment() {
}
}
- /**
- * 清除软件数据
- * @param info AppInfo
- */
+
private fun clearApk(info: AppInfo) {
try {
MaterialDialog(requireContext()).show {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsTouchCallBack.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsTouchCallBack.kt
index e56279b..5a72342 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsTouchCallBack.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsTouchCallBack.kt
@@ -23,7 +23,7 @@ class AppsTouchCallBack(private val onMoveBlock: (from: Int, to: Int) -> Unit) :
)
} catch (e: Exception) {
Log.e(TAG, "Error getting movement flags: ${e.message}")
- // Return safe default flags
+
makeMovementFlags(0, 0)
}
}
@@ -37,15 +37,15 @@ class AppsTouchCallBack(private val onMoveBlock: (from: Int, to: Int) -> Unit) :
val fromPosition = viewHolder.bindingAdapterPosition
val toPosition = target.bindingAdapterPosition
- // Validate positions
+
if (fromPosition == RecyclerView.NO_POSITION || toPosition == RecyclerView.NO_POSITION) {
Log.w(TAG, "Invalid positions: from=$fromPosition, to=$toPosition")
false
} else if (fromPosition == toPosition) {
- // Prevent moving to the same position
+
false
} else {
- // Call the move callback
+
onMoveBlock(fromPosition, toPosition)
true
}
@@ -56,7 +56,7 @@ class AppsTouchCallBack(private val onMoveBlock: (from: Int, to: Int) -> Unit) :
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
- // Not implemented for this use case - drag and drop only
+
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
@@ -65,11 +65,11 @@ class AppsTouchCallBack(private val onMoveBlock: (from: Int, to: Int) -> Unit) :
when (actionState) {
ItemTouchHelper.ACTION_STATE_DRAG -> {
- // Item is being dragged
+
viewHolder?.itemView?.alpha = 0.8f
}
ItemTouchHelper.ACTION_STATE_IDLE -> {
- // Item is no longer being dragged
+
viewHolder?.itemView?.alpha = 1.0f
}
}
@@ -81,7 +81,7 @@ class AppsTouchCallBack(private val onMoveBlock: (from: Int, to: Int) -> Unit) :
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
try {
super.clearView(recyclerView, viewHolder)
- // Reset the view to its normal state
+
viewHolder.itemView.alpha = 1.0f
} catch (e: Exception) {
Log.e(TAG, "Error in clearView: ${e.message}")
@@ -94,7 +94,7 @@ class AppsTouchCallBack(private val onMoveBlock: (from: Int, to: Int) -> Unit) :
target: RecyclerView.ViewHolder
): Boolean {
return try {
- // Only allow dropping on valid targets
+
val targetPosition = target.bindingAdapterPosition
targetPosition != RecyclerView.NO_POSITION
} catch (e: Exception) {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsViewModel.kt
index b53390a..14d2c99 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsViewModel.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/apps/AppsViewModel.kt
@@ -6,12 +6,7 @@ import top.niunaijun.blackboxa.data.AppsRepository
import top.niunaijun.blackboxa.view.base.BaseViewModel
import android.util.Log
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 22:36
- */
+
class AppsViewModel(private val repo: AppsRepository) : BaseViewModel() {
val appsLiveData = MutableLiveData>()
@@ -20,7 +15,7 @@ class AppsViewModel(private val repo: AppsRepository) : BaseViewModel() {
val launchLiveData = MutableLiveData()
- //利用LiveData只更新最后一次的特性,用来保存app顺序
+
val updateSortLiveData = MutableLiveData()
fun getInstalledApps(userId: Int) {
@@ -29,9 +24,7 @@ class AppsViewModel(private val repo: AppsRepository) : BaseViewModel() {
}
}
- /**
- * Get installed apps with retry mechanism for when services are not ready
- */
+
fun getInstalledAppsWithRetry(userId: Int, maxRetries: Int = 3) {
var retryCount = 0
@@ -39,16 +32,16 @@ class AppsViewModel(private val repo: AppsRepository) : BaseViewModel() {
launchOnUI {
repo.getVmInstallList(userId, appsLiveData)
- // Check if we got any apps, if not and we haven't exceeded retries, try again
+
val currentApps = appsLiveData.value
if ((currentApps == null || currentApps.isEmpty()) && retryCount < maxRetries) {
retryCount++
Log.d("AppsViewModel", "No apps loaded, retrying... (${retryCount}/${maxRetries})")
- // Wait a bit before retrying
+
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
attemptLoad()
- }, 1000) // Wait 1 second before retry
+ }, 1000)
}
}
}
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseActivity.kt
index 2c4ad48..d27d14f 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseActivity.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseActivity.kt
@@ -3,12 +3,7 @@ package top.niunaijun.blackboxa.view.base
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
-/**
- *
- * @Description:BaseActivity
- * @Author: wukaicheng
- * @CreateDate: 2021/5/4 15:58
- */
+
open class BaseActivity : AppCompatActivity() {
protected fun initToolbar(toolbar: Toolbar,title:Int, showBack: Boolean = false, onBack: (() -> Unit)? = null) {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseViewModel.kt
index b04517f..a31a005 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseViewModel.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/base/BaseViewModel.kt
@@ -4,12 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
-/**
- *
- * @Description:
- * @Author: wukaicheng
- * @CreateDate: 2021/4/29 23:33
- */
+
open class BaseViewModel : ViewModel() {
fun launchOnUI(block: suspend CoroutineScope.() -> Unit) {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/base/LoadingActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/base/LoadingActivity.kt
index 0491e98..9ea43fc 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/base/LoadingActivity.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/base/LoadingActivity.kt
@@ -4,12 +4,7 @@ import android.view.KeyEvent
import com.roger.catloadinglibrary.CatLoadingView
import top.niunaijun.blackboxa.R
-/**
- *
- * @Description: loading activity
- * @Author: BlackBox
- * @CreateDate: 2022/3/2 21:49
- */
+
abstract class LoadingActivity : BaseActivity() {
private lateinit var loadingView: CatLoadingView
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationAdapter.kt
index 643620d..8e4bc24 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationAdapter.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationAdapter.kt
@@ -10,12 +10,7 @@ import top.niunaijun.blackboxa.bean.FakeLocationBean
import top.niunaijun.blackboxa.databinding.ItemFakeBinding
import top.niunaijun.blackboxa.util.getString
-/**
- *
- * @Description: 软件显示界面适配器
- * @Author: BlackBoxing
- * @CreateDate: 2022/3/14
- */
+
class FakeLocationAdapter : RVHolderFactory() {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationFactory.kt
index 832f6c8..a9e0211 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationFactory.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationFactory.kt
@@ -4,11 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import top.niunaijun.blackboxa.data.FakeLocationRepository
-/**
- *
- * @Author: BlackBoxing
- * @CreateDate: 2022/3/14
- */
+
class FakeLocationFactory(private val repo: FakeLocationRepository) :
ViewModelProvider.NewInstanceFactory() {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationViewModel.kt
index ddbb3bf..f35534e 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationViewModel.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeLocationViewModel.kt
@@ -6,11 +6,7 @@ import top.niunaijun.blackboxa.bean.FakeLocationBean
import top.niunaijun.blackboxa.data.FakeLocationRepository
import top.niunaijun.blackboxa.view.base.BaseViewModel
-/**
- *
- * @Author: BlackBoxing
- * @CreateDate: 2022/3/14
- */
+
class FakeLocationViewModel(private val mRepo: FakeLocationRepository) : BaseViewModel() {
val appsLiveData = MutableLiveData>()
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeManagerActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeManagerActivity.kt
index f52d80d..377ea30 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeManagerActivity.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FakeManagerActivity.kt
@@ -22,17 +22,13 @@ import top.niunaijun.blackboxa.util.inflate
import top.niunaijun.blackboxa.util.toast
import top.niunaijun.blackboxa.view.base.BaseActivity
-/**
- *
- * @Author: BlackBoxing
- * @CreateDate: 2022/3/14
- */
+
class FakeManagerActivity : BaseActivity() {
val TAG: String = "FakeManagerActivity"
private val viewBinding: ActivityListBinding by inflate()
- // private lateinit var mAdapter: ListAdapter
+
private lateinit var mAdapter: RVAdapter
private lateinit var viewModel: FakeLocationViewModel
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FollowMyLocationOverlay.kt b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FollowMyLocationOverlay.kt
index 0f37653..d532b3f 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/fake/FollowMyLocationOverlay.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/fake/FollowMyLocationOverlay.kt
@@ -19,11 +19,7 @@ import top.niunaijun.blackboxa.util.inflate
import top.niunaijun.blackboxa.util.toast
-/**
- *
- * @Author: BlackBoxing
- * @CreateDate: 2022/3/14
- */
+
class FollowMyLocationOverlay : AppCompatActivity() {
val TAG: String = "FollowMyLocationOverlay"
@@ -36,19 +32,19 @@ class FollowMyLocationOverlay : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- //handle permissions first, before map is created. not depicted here
+
- //load/initialize the osmdroid configuration, this can be done
- // This won't work unless you have imported this: org.osmdroid.config.Configuration.*
+
+
Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this))
- //setting this before the layout is inflated is a good idea
- //it 'should' ensure that the map has a writable location for the map cache, even without permissions
- //if no tiles are displayed, you can try overriding the cache path using Configuration.getInstance().setCachePath
- //see also StorageUtils
- //note, the load method also sets the HTTP User Agent to your application's package name, if you abuse osm's
- //tile servers will get you banned based on this string.
+
+
+
+
+
+
- //inflate and create the map
+
setContentView(binding.root)
val location: BLocation? = intent.getParcelableExtra("location")
@@ -82,7 +78,7 @@ class FollowMyLocationOverlay : AppCompatActivity() {
binding.map.overlays.add(MapEventsOverlay(mReceive))
val mapController = binding.map.controller
mapController.setZoom(12.5)
-// val startPoint = GeoPoint(30.2736, 120.1563)
+
mapController.setCenter(startPoint)
binding.map.setTileSource(TileSourceFactory.MAPNIK)
}
@@ -93,20 +89,20 @@ class FollowMyLocationOverlay : AppCompatActivity() {
override fun onResume() {
super.onResume()
- //this will refresh the osmdroid configuration on resuming.
- //if you make changes to the configuration, use
- //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this)
- //Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this))
- binding.map.onResume() //needed for compass, my location overlays, v6.0.0 and up
+
+
+
+
+ binding.map.onResume()
}
override fun onPause() {
super.onPause()
- //this will refresh the osmdroid configuration on resuming.
- //if you make changes to the configuration, use
- //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this)
- //Configuration.getInstance().save(this, prefs)
- binding.map.onPause() //needed for compass, my location overlays, v6.0.0 and up
+
+
+
+
+ binding.map.onPause()
}
override fun onRequestPermissionsResult(
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsAdapter.kt
index d2bb6ec..28bbcab 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsAdapter.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsAdapter.kt
@@ -8,12 +8,7 @@ import top.niunaijun.blackboxa.R
import top.niunaijun.blackboxa.bean.GmsBean
import top.niunaijun.blackboxa.databinding.ItemGmsBinding
-/**
- *
- * @Description:
- * @Author: BlackBox
- * @CreateDate: 2022/3/2 21:13
- */
+
class GmsAdapter : RVHolderFactory() {
override fun createViewHolder(parent: ViewGroup?, viewType: Int, item: Any): RVHolder {
diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsFactory.kt
index fd9a3c7..24c27d2 100644
--- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsFactory.kt
+++ b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsFactory.kt
@@ -4,12 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import top.niunaijun.blackboxa.data.GmsRepository
-/**
- *
- * @Description:
- * @Author: BlackBox
- * @CreateDate: 2022/3/2 21:15
- */
+
class GmsFactory(private val repo:GmsRepository): ViewModelProvider.NewInstanceFactory() {
override fun