From 9c744770f8b9568aa93805085ec7f7846e89653d Mon Sep 17 00:00:00 2001 From: ArtRuntime Date: Wed, 4 Feb 2026 22:09:34 +0530 Subject: [PATCH] feat: Enhance core framework with improved service faking, package management, and build system updates. intigrated disable flag secure remove comments cleanup codes --- Bcore/build.gradle | 14 +- Bcore/src/main/AndroidManifest.xml | 140 ++-- Bcore/src/main/cpp/BoxCore.cpp | 17 +- Bcore/src/main/cpp/BoxCore.h | 8 +- Bcore/src/main/cpp/Dobby/dobby.h | 42 +- Bcore/src/main/cpp/Hook/BaseHook.cpp | 4 - Bcore/src/main/cpp/Hook/BaseHook.h | 6 +- Bcore/src/main/cpp/Hook/BinderHook.cpp | 6 +- Bcore/src/main/cpp/Hook/BinderHook.h | 8 +- Bcore/src/main/cpp/Hook/DexFileHook.cpp | 14 +- Bcore/src/main/cpp/Hook/DexFileHook.h | 2 +- Bcore/src/main/cpp/Hook/FileSystemHook.cpp | 34 +- Bcore/src/main/cpp/Hook/FileSystemHook.h | 8 +- Bcore/src/main/cpp/Hook/RuntimeHook.cpp | 6 +- Bcore/src/main/cpp/Hook/RuntimeHook.h | 8 +- .../src/main/cpp/Hook/UnixFileSystemHook.cpp | 76 +-- Bcore/src/main/cpp/Hook/UnixFileSystemHook.h | 8 +- Bcore/src/main/cpp/Hook/VMClassLoaderHook.cpp | 14 +- Bcore/src/main/cpp/Hook/VMClassLoaderHook.h | 8 +- Bcore/src/main/cpp/IO.cpp | 49 +- Bcore/src/main/cpp/IO.h | 8 +- Bcore/src/main/cpp/JniHook/ArtMethod.h | 60 +- Bcore/src/main/cpp/JniHook/JniHook.cpp | 22 +- Bcore/src/main/cpp/JniHook/JniHook.h | 8 +- Bcore/src/main/cpp/Utils/AntiDetection.cpp | 40 +- Bcore/src/main/cpp/Utils/HexDump.cpp | 6 +- Bcore/src/main/cpp/Utils/HexDump.h | 8 +- Bcore/src/main/cpp/Utils/VirtualSpoof.cpp | 13 +- Bcore/src/main/cpp/Utils/elf_util.cpp | 36 +- Bcore/src/main/cpp/Utils/elf_util.h | 30 +- Bcore/src/main/cpp/hidden_api.cpp | 33 +- Bcore/src/main/cpp/hidden_api.h | 2 +- Bcore/src/main/cpp/xdl.h | 106 +-- Bcore/src/main/cpp/xdl/xdl.c | 251 ++++--- Bcore/src/main/cpp/xdl/xdl_iterate.c | 119 ++-- Bcore/src/main/cpp/xdl/xdl_iterate.h | 42 +- Bcore/src/main/cpp/xdl/xdl_linker.c | 68 +- Bcore/src/main/cpp/xdl/xdl_linker.h | 42 +- Bcore/src/main/cpp/xdl/xdl_lzma.c | 72 +- Bcore/src/main/cpp/xdl/xdl_lzma.h | 42 +- Bcore/src/main/cpp/xdl/xdl_util.c | 44 +- Bcore/src/main/cpp/xdl/xdl_util.h | 42 +- .../main/java/android/app/ActivityThread.java | 9 +- .../android/app/ContentProviderHolder.java | 9 +- .../android/content/IContentProvider.java | 9 +- .../main/java/android/content/SyncInfo.java | 57 +- .../java/android/content/SyncStatusInfo.java | 8 +- .../android/content/pm/ManifestDigest.java | 9 +- .../android/content/pm/PackageParser.java | 169 ++--- .../android/content/pm/PackageUserState.java | 11 +- .../java/android/content/pm/VerifierInfo.java | 9 +- .../java/android/os/ParcelableException.java | 15 +- .../black/android/app/ActivityClient.java | 4 +- .../android/content/AttributionSource.java | 4 +- .../content/AttributionSourceState.java | 4 +- .../android/content/pm/PackageParser.java | 28 +- .../content/pm/PackageParserLollipop.java | 28 +- .../content/pm/PackageParserLollipop22.java | 28 +- .../content/pm/PackageParserMarshmallow.java | 28 +- .../black/android/graphics/Compatibility.java | 4 +- .../hardware/location/IContextHubService.java | 4 +- .../android/location/LocationManager.java | 20 +- .../java/black/android/net/IVpnManager.java | 4 +- .../android/os/IVibratorManagerService.java | 4 +- .../android/telephony/TelephonyManager.java | 4 +- .../com/android/internal/net/VpnConfig.java | 4 +- .../top/niunaijun/blackbox/BlackBoxCore.java | 630 ++++++++---------- .../blackbox/app/BActivityThread.java | 217 +++--- .../blackbox/app/LauncherActivity.java | 39 +- .../configuration/AppLifecycleCallback.java | 21 +- .../configuration/ClientConfiguration.java | 29 +- .../dispatcher/AppJobServiceDispatcher.java | 19 +- .../app/dispatcher/AppServiceDispatcher.java | 23 +- .../niunaijun/blackbox/closecode/Entry.java | 2 +- .../niunaijun/blackbox/core/CrashHandler.java | 9 +- .../top/niunaijun/blackbox/core/GmsCore.java | 13 +- .../top/niunaijun/blackbox/core/IOCore.java | 25 +- .../niunaijun/blackbox/core/NativeCore.java | 111 ++- .../blackbox/core/env/AppSystemEnv.java | 23 +- .../blackbox/core/env/BEnvironment.java | 9 +- .../core/system/BProcessManagerService.java | 13 +- .../blackbox/core/system/BlackBoxSystem.java | 19 +- .../blackbox/core/system/DaemonService.java | 33 +- .../blackbox/core/system/ISystemService.java | 9 +- .../blackbox/core/system/JarConfig.java | 55 +- .../blackbox/core/system/JarManager.java | 93 +-- .../blackbox/core/system/JarManagerTest.java | 41 +- .../blackbox/core/system/ServiceManager.java | 9 +- .../core/system/SystemCallProvider.java | 11 +- .../core/system/accounts/BAccount.java | 4 +- .../accounts/BAccountManagerService.java | 288 ++++---- .../core/system/accounts/BUserAccounts.java | 4 +- .../core/system/accounts/TokenCache.java | 4 +- .../core/system/am/ActiveServices.java | 17 +- .../core/system/am/ActivityRecord.java | 9 +- .../core/system/am/ActivityStack.java | 29 +- .../system/am/BActivityManagerService.java | 9 +- .../core/system/am/BJobManagerService.java | 13 +- .../core/system/am/BroadcastManager.java | 8 +- .../core/system/am/PendingIntentRecord.java | 4 +- .../blackbox/core/system/am/TaskRecord.java | 9 +- .../blackbox/core/system/am/UserSpace.java | 9 +- .../location/BLocationManagerService.java | 9 +- .../core/system/location/LocationRecord.java | 4 +- .../BNotificationManagerService.java | 8 +- .../NotificationChannelManager.java | 4 +- .../notification/NotificationRecord.java | 4 +- .../system/os/BStorageManagerService.java | 9 +- .../permission/XiaomiPermissionManager.java | 107 ++- .../blackbox/core/system/pm/BPackage.java | 19 +- .../system/pm/BPackageInstallerService.java | 23 +- .../system/pm/BPackageManagerService.java | 133 ++-- .../core/system/pm/BPackageSettings.java | 11 +- .../core/system/pm/BPackageUserState.java | 9 +- .../core/system/pm/ComponentResolver.java | 67 +- .../core/system/pm/FastImmutableArraySet.java | 25 +- .../core/system/pm/IntentResolver.java | 148 ++-- .../core/system/pm/PackageManagerCompat.java | 41 +- .../core/system/pm/PackageMonitor.java | 9 +- .../blackbox/core/system/pm/Settings.java | 37 +- .../core/system/pm/SharedUserSetting.java | 42 +- .../system/pm/installer/CopyExecutor.java | 16 +- .../pm/installer/CreatePackageExecutor.java | 12 +- .../pm/installer/CreateUserExecutor.java | 26 +- .../core/system/pm/installer/Executor.java | 9 +- .../pm/installer/RemoveAppExecutor.java | 9 +- .../pm/installer/RemoveUserExecutor.java | 12 +- .../core/system/user/BUserHandle.java | 290 ++------ .../blackbox/core/system/user/BUserInfo.java | 9 +- .../core/system/user/BUserManagerService.java | 9 +- .../core/system/user/BUserStatus.java | 9 +- .../niunaijun/blackbox/entity/AppConfig.java | 9 +- .../niunaijun/blackbox/entity/JobRecord.java | 9 +- .../blackbox/entity/ServiceRecord.java | 11 +- .../blackbox/entity/UnbindRecord.java | 9 +- .../blackbox/entity/am/PendingResultData.java | 4 +- .../blackbox/entity/am/ReceiverData.java | 4 +- .../entity/am/RunningAppProcessInfo.java | 4 +- .../entity/am/RunningServiceInfo.java | 4 +- .../blackbox/entity/location/BCell.java | 45 +- .../blackbox/entity/location/BLocation.java | 30 +- .../entity/location/BLocationConfig.java | 4 +- .../blackbox/entity/pm/InstallOption.java | 9 +- .../blackbox/entity/pm/InstallResult.java | 9 +- .../blackbox/entity/pm/InstalledPackage.java | 9 +- .../top/niunaijun/blackbox/fake/FakeCore.java | 9 +- .../delegate/BaseInstrumentationDelegate.java | 26 +- .../delegate/ContentProviderDelegate.java | 9 +- .../fake/delegate/InnerReceiverDelegate.java | 9 +- .../delegate/ServiceConnectionDelegate.java | 9 +- .../fake/frameworks/BAccountManager.java | 10 +- .../fake/frameworks/BActivityManager.java | 21 +- .../blackbox/fake/frameworks/BJobManager.java | 9 +- .../fake/frameworks/BLocationManager.java | 4 +- .../fake/frameworks/BNotificationManager.java | 4 +- .../fake/frameworks/BPackageManager.java | 189 +++--- .../fake/frameworks/BResourcesManager.java | 67 +- .../fake/frameworks/BStorageManager.java | 9 +- .../fake/frameworks/BUserManager.java | 9 +- .../fake/frameworks/BlackManager.java | 40 +- .../fake/hook/BinderInvocationStub.java | 9 +- .../fake/hook/ClassInvocationStub.java | 31 +- .../blackbox/fake/hook/HookManager.java | 65 +- .../blackbox/fake/hook/IInjectHook.java | 9 +- .../blackbox/fake/hook/MethodHook.java | 9 +- .../blackbox/fake/hook/ProxyMethod.java | 9 +- .../blackbox/fake/hook/ProxyMethods.java | 9 +- .../blackbox/fake/hook/ScanClass.java | 9 +- .../blackbox/fake/provider/FileProvider.java | 194 +----- .../fake/provider/FileProviderHandler.java | 9 +- .../service/ActivityManagerCommonProxy.java | 19 +- .../blackbox/fake/service/AndroidIdProxy.java | 18 +- .../blackbox/fake/service/ApkAssetsProxy.java | 16 +- .../fake/service/AudioPermissionProxy.java | 62 +- .../fake/service/AudioRecordProxy.java | 20 +- .../fake/service/AuthenticationProxy.java | 8 +- .../fake/service/BrowserEngineProxy.java | 26 +- .../fake/service/ClassLoaderProxy.java | 177 +++-- .../fake/service/ContentResolverProxy.java | 30 +- .../blackbox/fake/service/DeviceIdProxy.java | 20 +- .../fake/service/FeatureFlagUtilsProxy.java | 29 +- .../fake/service/FileSystemProxy.java | 32 +- .../blackbox/fake/service/GmsProxy.java | 32 +- .../service/GoogleAccountManagerProxy.java | 35 +- .../blackbox/fake/service/HCallbackProxy.java | 17 +- .../service/IAccessibilityManagerProxy.java | 9 +- .../fake/service/IAccountManagerProxy.java | 9 +- .../fake/service/IActivityClientProxy.java | 6 +- .../fake/service/IActivityManagerProxy.java | 93 ++- .../service/IActivityTaskManagerProxy.java | 11 +- .../fake/service/IAlarmManagerProxy.java | 9 +- .../fake/service/IAppOpsManagerProxy.java | 51 +- .../fake/service/IAppWidgetManagerProxy.java | 9 +- .../fake/service/IAttributionSourceProxy.java | 49 +- .../fake/service/IAudioServiceProxy.java | 46 +- .../fake/service/IAutofillManagerProxy.java | 9 +- .../service/IConnectivityManagerProxy.java | 403 ++++++----- .../fake/service/IContentProviderProxy.java | 77 +-- .../fake/service/IContextHubServiceProxy.java | 4 +- .../IDeviceIdentifiersPolicyProxy.java | 13 +- .../service/IDevicePolicyManagerProxy.java | 9 +- .../fake/service/IDisplayManagerProxy.java | 9 +- .../fake/service/IDnsResolverProxy.java | 43 +- .../service/IFingerprintManagerProxy.java | 6 +- .../fake/service/IGraphicsStatsProxy.java | 9 +- .../service/IInputMethodManagerProxy.java | 8 +- .../fake/service/IJobServiceProxy.java | 133 ++-- .../fake/service/ILauncherAppsProxy.java | 11 +- .../fake/service/ILocationManagerProxy.java | 25 +- .../service/IMediaRouterServiceProxy.java | 4 +- .../service/IMediaSessionManagerProxy.java | 9 +- .../service/IMiuiSecurityManagerProxy.java | 37 +- .../INetworkManagementServiceProxy.java | 5 +- .../service/INotificationManagerProxy.java | 11 +- .../fake/service/IPackageManagerProxy.java | 114 ++-- .../fake/service/IPermissionManagerProxy.java | 6 +- .../IPersistentDataBlockServiceProxy.java | 4 +- .../fake/service/IPhoneSubInfoProxy.java | 4 +- .../fake/service/IPowerManagerProxy.java | 4 +- ...ensitiveContentProtectionManagerProxy.java | 7 +- .../service/ISensorPrivacyManagerProxy.java | 22 +- .../fake/service/ISettingsProviderProxy.java | 33 +- .../fake/service/ISettingsSystemProxy.java | 45 +- .../fake/service/IShortcutManagerProxy.java | 12 +- .../fake/service/IStorageManagerProxy.java | 9 +- .../service/IStorageStatsManagerProxy.java | 4 +- .../service/ISystemSensorManagerProxy.java | 37 +- .../fake/service/ISystemUpdateProxy.java | 6 +- .../fake/service/ITelephonyManagerProxy.java | 27 +- .../fake/service/ITelephonyRegistryProxy.java | 9 +- .../fake/service/IUserManagerProxy.java | 9 +- .../fake/service/IVibratorServiceProxy.java | 4 +- .../fake/service/IVpnManagerProxy.java | 9 +- .../service/IWebViewUpdateServiceProxy.java | 55 +- .../fake/service/IWifiManagerProxy.java | 21 +- .../fake/service/IWifiScannerProxy.java | 6 +- .../fake/service/IWindowManagerProxy.java | 9 +- .../fake/service/IWindowSessionProxy.java | 34 +- .../IXiaomiAttributionSourceProxy.java | 39 +- .../service/IXiaomiMiuiServicesProxy.java | 87 ++- .../fake/service/IXiaomiSettingsProxy.java | 81 +-- .../blackbox/fake/service/LevelDbProxy.java | 24 +- .../fake/service/MediaRecorderClassProxy.java | 28 +- .../fake/service/MediaRecorderProxy.java | 42 +- .../blackbox/fake/service/ReLinkerProxy.java | 22 +- .../fake/service/ResourcesManagerProxy.java | 20 +- .../fake/service/SQLiteDatabaseProxy.java | 20 +- .../blackbox/fake/service/StubHelper.java | 46 +- .../fake/service/SystemLibraryProxy.java | 28 +- .../blackbox/fake/service/VpnCommonProxy.java | 4 +- .../fake/service/WebViewFactoryProxy.java | 61 +- .../blackbox/fake/service/WebViewProxy.java | 92 ++- .../fake/service/WorkManagerProxy.java | 87 +-- .../fake/service/base/UidMethodProxy.java | 4 +- .../service/context/ContentServiceStub.java | 9 +- .../context/RestrictionsManagerStub.java | 9 +- .../context/providers/BContentProvider.java | 9 +- .../providers/ContentProviderStub.java | 97 ++- .../context/providers/SystemProviderStub.java | 25 +- .../blackbox/fake/service/libcore/OsStub.java | 17 +- .../blackbox/proxy/ProxyActivity.java | 13 +- .../proxy/ProxyBroadcastReceiver.java | 4 +- .../blackbox/proxy/ProxyContentProvider.java | 9 +- .../blackbox/proxy/ProxyJobService.java | 9 +- .../blackbox/proxy/ProxyManifest.java | 9 +- .../blackbox/proxy/ProxyPendingActivity.java | 9 +- .../blackbox/proxy/ProxyService.java | 9 +- .../blackbox/proxy/ProxyVpnService.java | 89 +-- .../proxy/TransparentProxyActivity.java | 4 +- .../proxy/record/ProxyActivityRecord.java | 9 +- .../proxy/record/ProxyBroadcastRecord.java | 9 +- .../proxy/record/ProxyPendingRecord.java | 9 +- .../proxy/record/ProxyServiceRecord.java | 9 +- .../blackbox/util/XiaomiDeviceDetector.java | 78 +-- .../niunaijun/blackbox/utils/AbiUtils.java | 9 +- .../niunaijun/blackbox/utils/ArrayUtils.java | 5 +- .../utils/AttributionSourceUtils.java | 59 +- .../niunaijun/blackbox/utils/CloseUtils.java | 9 +- .../blackbox/utils/ContextWrapperHook.java | 42 +- .../blackbox/utils/CrashMonitor.java | 201 ++---- .../blackbox/utils/DexCrashPrevention.java | 154 ++--- .../blackbox/utils/DexFileRecovery.java | 101 +-- .../niunaijun/blackbox/utils/FileUtils.java | 30 +- .../blackbox/utils/GlobalContextWrapper.java | 23 +- .../blackbox/utils/HackAppUtils.java | 9 +- .../niunaijun/blackbox/utils/JarUtils.java | 61 +- .../niunaijun/blackbox/utils/LogSender.java | 14 +- .../niunaijun/blackbox/utils/Md5Utils.java | 4 +- .../blackbox/utils/NativeCrashPrevention.java | 185 ++--- .../niunaijun/blackbox/utils/NativeUtils.java | 17 +- .../top/niunaijun/blackbox/utils/QQUtils.java | 4 +- .../blackbox/utils/ReflectionClass.java | 50 +- .../niunaijun/blackbox/utils/Reflector.java | 32 +- .../blackbox/utils/SafeContextWrapper.java | 13 +- .../niunaijun/blackbox/utils/ShellUtils.java | 84 +-- .../blackbox/utils/SimpleCrashFix.java | 79 +-- .../top/niunaijun/blackbox/utils/Slog.java | 22 +- .../utils/SocialMediaAppCrashPrevention.java | 135 ++-- .../utils/StoragePermissionHelper.java | 79 +-- .../blackbox/utils/SystemHookManager.java | 114 ++-- .../blackbox/utils/TransactionThrottler.java | 38 +- .../niunaijun/blackbox/utils/TrieTree.java | 6 +- .../blackbox/utils/UIDSpoofingHelper.java | 58 +- .../utils/compat/AccountManagerCompat.java | 27 +- .../blackbox/utils/compat/ActivityCompat.java | 11 +- .../utils/compat/ActivityManagerCompat.java | 78 +-- .../blackbox/utils/compat/BuildCompat.java | 24 +- .../blackbox/utils/compat/BundleCompat.java | 38 +- .../utils/compat/ContentProviderCompat.java | 12 +- .../blackbox/utils/compat/ContextCompat.java | 17 +- .../blackbox/utils/compat/DexFileCompat.java | 9 +- .../utils/compat/PackageParserCompat.java | 2 +- .../utils/compat/StartActivityCompat.java | 9 +- .../utils/compat/TaskDescriptionCompat.java | 16 +- .../top/niunaijun/jnihook/MethodUtils.java | 15 +- .../top/niunaijun/jnihook/ReflectCore.java | 9 +- .../top/niunaijun/jnihook/jni/JniHook.java | 9 +- Bcore/src/main/res/xml/filepath.xml | 14 +- app/build.gradle | 24 +- app/src/main/AndroidManifest.xml | 4 +- .../java/top/niunaijun/blackboxa/app/App.kt | 8 +- .../top/niunaijun/blackboxa/app/AppManager.kt | 19 +- .../rocker/BaseActivityLifecycleCallback.kt | 7 +- .../blackboxa/app/rocker/RockerManager.kt | 74 +- .../top/niunaijun/blackboxa/bean/AppInfo.kt | 7 +- .../top/niunaijun/blackboxa/bean/GmsBean.kt | 7 +- .../blackboxa/bean/InstalledAppBean.kt | 7 +- .../niunaijun/blackboxa/bean/XpModuleInfo.kt | 7 +- .../biz/cache/AppSharedPreferenceDelegate.kt | 5 +- .../blackboxa/data/AppsRepository.kt | 84 +-- .../blackboxa/data/AppsSortCompon.kt | 7 +- .../blackboxa/data/FakeLocationRepository.kt | 27 +- .../niunaijun/blackboxa/data/GmsRepository.kt | 7 +- .../niunaijun/blackboxa/util/ContextUtil.kt | 7 +- .../niunaijun/blackboxa/util/InjectionUtil.kt | 7 +- .../niunaijun/blackboxa/util/MathUtil.java | 43 +- .../niunaijun/blackboxa/util/MemoryManager.kt | 37 +- .../niunaijun/blackboxa/util/Resolution.java | 161 +---- .../niunaijun/blackboxa/util/ShortcutUtil.kt | 13 +- .../top/niunaijun/blackboxa/util/ToastEx.kt | 7 +- .../niunaijun/blackboxa/util/ViewBindingEx.kt | 7 +- .../blackboxa/view/apps/AppsAdapter.kt | 35 +- .../blackboxa/view/apps/AppsFactory.kt | 7 +- .../blackboxa/view/apps/AppsFragment.kt | 61 +- .../blackboxa/view/apps/AppsTouchCallBack.kt | 18 +- .../blackboxa/view/apps/AppsViewModel.kt | 19 +- .../blackboxa/view/base/BaseActivity.kt | 7 +- .../blackboxa/view/base/BaseViewModel.kt | 7 +- .../blackboxa/view/base/LoadingActivity.kt | 7 +- .../view/fake/FakeLocationAdapter.kt | 7 +- .../view/fake/FakeLocationFactory.kt | 6 +- .../view/fake/FakeLocationViewModel.kt | 6 +- .../view/fake/FakeManagerActivity.kt | 8 +- .../view/fake/FollowMyLocationOverlay.kt | 48 +- .../blackboxa/view/gms/GmsAdapter.kt | 7 +- .../blackboxa/view/gms/GmsFactory.kt | 7 +- .../blackboxa/view/gms/GmsManagerActivity.kt | 7 +- .../blackboxa/view/gms/GmsViewModel.kt | 7 +- .../blackboxa/view/list/ListAdapter.kt | 7 +- .../blackboxa/view/list/ListFactory.kt | 7 +- .../blackboxa/view/list/ListViewModel.kt | 7 +- .../blackboxa/view/main/BlackBoxLoader.kt | 59 +- .../blackboxa/view/main/MainActivity.kt | 27 +- .../blackboxa/view/main/ShortcutActivity.kt | 7 +- .../blackboxa/view/main/ViewPagerAdapter.kt | 7 +- .../blackboxa/view/setting/SettingFragment.kt | 26 +- .../niunaijun/blackboxa/widget/EnFloatView.kt | 9 +- .../blackboxa/widget/RockerView.java | 88 +-- app/src/main/res/values/strings.xml | 2 + app/src/main/res/values/themes.xml | 10 +- app/src/main/res/xml/setting.xml | 5 + black-reflection/build.gradle.kts | 4 +- .../BlackNullPointerException.java | 9 +- .../blackreflection/BlackReflection.java | 24 +- .../annotation/BConstructor.java | 9 +- .../annotation/BConstructorNotProcess.java | 9 +- .../blackreflection/utils/ClassUtil.java | 9 +- .../blackreflection/utils/Reflector.java | 28 +- build.gradle | 10 +- compiler/build.gradle.kts | 4 +- .../blackreflection/BlackReflectionInfo.java | 4 +- .../BlackReflectionInterfaceInfo.java | 4 +- .../BlackReflectionProcessor.java | 8 +- .../proxy/BlackReflectionInterfaceProxy.java | 27 +- .../proxy/BlackReflectionProxy.java | 11 +- .../blackreflection/utils/ClassUtils.java | 9 +- gradle.properties | 38 +- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 389 files changed, 4621 insertions(+), 7834 deletions(-) diff --git a/Bcore/build.gradle b/Bcore/build.gradle index 6941e03..bcd001f 100644 --- a/Bcore/build.gradle +++ b/Bcore/build.gradle @@ -16,12 +16,10 @@ android { } defaultConfig { minSdkVersion rootProject.ext.minSdk - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName consumerProguardFiles "consumer-rules.pro" ndk { - // 设置支持的SO库架构 + abiFilters 'arm64-v8a' , 'armeabi-v7a' } } @@ -41,11 +39,11 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } - // Enable incremental annotation processing for faster builds + tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint:-deprecation" << "-Xlint:-unchecked" << "-Xlint:-rawtypes" options.fork = true @@ -89,8 +87,8 @@ dependencies { implementation 'com.moandjiezana.toml:toml4j:0.7.2' implementation 'com.github.tiann:FreeReflection:3.2.2' -// implementation "com.github.CodingGay.BlackReflection:core:$rootProject.ext.blackReflection" - // Pine dependency removed + + } diff --git a/Bcore/src/main/AndroidManifest.xml b/Bcore/src/main/AndroidManifest.xml index 950fbba..c8b9cec 100644 --- a/Bcore/src/main/AndroidManifest.xml +++ b/Bcore/src/main/AndroidManifest.xml @@ -3,21 +3,21 @@ - + - + - + - + @@ -26,16 +26,16 @@ - + - + - + @@ -45,7 +45,7 @@ - + @@ -59,21 +59,21 @@ - + - + - + - + - + - + @@ -132,9 +132,9 @@ - + - + @@ -174,131 +174,131 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -326,14 +326,14 @@ - - - + + + - + - + - - + + @@ -359,20 +359,20 @@ - + - + - + - + - + @@ -410,10 +410,10 @@ tools:ignore="ProtectedPermissions" /> - + - + @@ -453,7 +453,7 @@ - + @@ -493,7 +493,7 @@ android:exported="false" android:process="@string/black_box_service_name" /> - + #include "Utils/HexDump.h" #include "hidden_api.h" -/** - * updated by alex5402 on 4/9/21. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + struct { JavaVM *vm; jclass NativeCoreClass; @@ -82,7 +75,7 @@ void nativeHook(JNIEnv *env) { UnixFileSystemHook::init(env); FileSystemHook::init(); VMClassLoaderHook::init(env); -// RuntimeHook::init(env); + BinderHook::init(env); DexFileHook::init(env); } diff --git a/Bcore/src/main/cpp/BoxCore.h b/Bcore/src/main/cpp/BoxCore.h index a1aba9d..fd92cdd 100644 --- a/Bcore/src/main/cpp/BoxCore.h +++ b/Bcore/src/main/cpp/BoxCore.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 4/9/21. -// + + + #ifndef VIRTUALM_VMCORE_H #define VIRTUALM_VMCORE_H @@ -20,4 +20,4 @@ public: }; -#endif //VIRTUALM_VMCORE_H +#endif diff --git a/Bcore/src/main/cpp/Dobby/dobby.h b/Bcore/src/main/cpp/Dobby/dobby.h index bc4c96b..33f2221 100644 --- a/Bcore/src/main/cpp/Dobby/dobby.h +++ b/Bcore/src/main/cpp/Dobby/dobby.h @@ -1,7 +1,7 @@ #ifndef dobby_h #define dobby_h -// obfuscated interface + #if 0 #define DobbyBuildVersion c343f74888dffad84d9ad08d9c433456 #define DobbyHook c8dc3ffa44f22dbd10ccae213dd8b1f8 @@ -38,7 +38,7 @@ typedef uint64_t addr64_t; #define ARM64_TMP_REG_NDX_0 17 -// float register + typedef union _FPReg { __int128_t q; struct { @@ -53,12 +53,12 @@ typedef union _FPReg { } f; } FPReg; -// register context + typedef struct _RegisterContext { - uint64_t dmmpy_0; // dummy placeholder + uint64_t dmmpy_0; uint64_t sp; - uint64_t dmmpy_1; // dummy placeholder + uint64_t dmmpy_1; union { uint64_t x[29]; struct { @@ -74,8 +74,8 @@ typedef struct _RegisterContext { FPReg q[32]; struct { FPReg q0, q1, q2, q3, q4, q5, q6, q7; - // [!!! READ ME !!!] - // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack + + FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, q30, q31; } regs; @@ -142,44 +142,44 @@ typedef struct _HookEntryInfo { }; } HookEntryInfo; -// DobbyWrap <==> DobbyInstrument, so use DobbyInstrument instead of DobbyWrap + #if 0 -// wrap function with pre_call and post_call + typedef void (*PreCallTy)(RegisterContext *ctx, const HookEntryInfo *info); typedef void (*PostCallTy)(RegisterContext *ctx, const HookEntryInfo *info); int DobbyWrap(void *function_address, PreCallTy pre_call, PostCallTy post_call); #endif -// return dobby build date + const char *DobbyBuildVersion(); -// replace function + int DobbyHook(void *address, void *replace_call, void **origin_call); -// dynamic binary instrument for instruction -// [!!! READ ME !!!] -// for Arm64, can't access q8 - q31, unless you enable full floating-point register pack + + + typedef void (*DBICallTy)(RegisterContext *ctx, const HookEntryInfo *info); int DobbyInstrument(void *address, DBICallTy dbi_call); -// destory and restore hook + int DobbyDestroy(void *address); -// iterate symbol table and find symbol + void *DobbySymbolResolver(const char *image_name, const char *symbol_name); -// global offset table + int DobbyGlobalOffsetTableReplace(char *image_name, char *symbol_name, void *fake_func, void **orig_func); -// [!!! READ ME !!!] -// for arm, Arm64, dobby will use b xxx instead of ldr absolute indirect branch -// for x64, dobby always use absolute indirect jump + + + #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) void dobby_enable_near_branch_trampoline(); void dobby_disable_near_branch_trampoline(); #endif -// register linker load image callback + typedef void (*linker_load_callback_t)(const char *image_name, void *handle); void dobby_register_image_load_callback(linker_load_callback_t func); diff --git a/Bcore/src/main/cpp/Hook/BaseHook.cpp b/Bcore/src/main/cpp/Hook/BaseHook.cpp index 948e800..3eb8698 100644 --- a/Bcore/src/main/cpp/Hook/BaseHook.cpp +++ b/Bcore/src/main/cpp/Hook/BaseHook.cpp @@ -1,7 +1,3 @@ -// -// updated by alex5402 on 4/10/21. -// - #include "BaseHook.h" diff --git a/Bcore/src/main/cpp/Hook/BaseHook.h b/Bcore/src/main/cpp/Hook/BaseHook.h index d923f05..9b998fe 100644 --- a/Bcore/src/main/cpp/Hook/BaseHook.h +++ b/Bcore/src/main/cpp/Hook/BaseHook.h @@ -1,7 +1,3 @@ -// -// updated by alex5402 on 4/9/21. -// - #ifndef VIRTUALM_BASEHOOK_H #define VIRTUALM_BASEHOOK_H @@ -14,4 +10,4 @@ public: }; -#endif //VIRTUALM_BASEHOOK_H +#endif diff --git a/Bcore/src/main/cpp/Hook/BinderHook.cpp b/Bcore/src/main/cpp/Hook/BinderHook.cpp index 437681a..fd46317 100644 --- a/Bcore/src/main/cpp/Hook/BinderHook.cpp +++ b/Bcore/src/main/cpp/Hook/BinderHook.cpp @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 4/25/21. -// + + + #include "BinderHook.h" #include diff --git a/Bcore/src/main/cpp/Hook/BinderHook.h b/Bcore/src/main/cpp/Hook/BinderHook.h index 965d3aa..debef47 100644 --- a/Bcore/src/main/cpp/Hook/BinderHook.h +++ b/Bcore/src/main/cpp/Hook/BinderHook.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 4/25/21. -// + + + #ifndef BLACKBOX_BINDERHOOK_H #define BLACKBOX_BINDERHOOK_H @@ -13,4 +13,4 @@ public: static void init(JNIEnv *env); }; -#endif //BLACKBOX_BINDERHOOK_H +#endif diff --git a/Bcore/src/main/cpp/Hook/DexFileHook.cpp b/Bcore/src/main/cpp/Hook/DexFileHook.cpp index 4102d6f..9c86ddd 100644 --- a/Bcore/src/main/cpp/Hook/DexFileHook.cpp +++ b/Bcore/src/main/cpp/Hook/DexFileHook.cpp @@ -9,10 +9,10 @@ HOOK_JNI(jobject, openDexFileNative, JNIEnv *env, jobject obj,jstring sourceName const char *sourceNameC = env->GetStringUTFChars(sourceName, JNI_FALSE); ALOGD("openDexFileNative: %s", sourceNameC); if(strstr(sourceNameC,"/blackbox/") != nullptr){ -// const char *file_ext = strrchr(sourceNameC,'.'); -// if(strcmp(file_ext,".dex") == 0 || strcmp(file_ext,".apk") == 0 || strcmp(file_ext,".jar") == 0){ -// -// } + + + + DexFileHook::setFileReadonly(sourceNameC); } jobject orig = orig_openDexFileNative(env, obj,sourceName,outputName,flags,loader,elements); @@ -32,14 +32,14 @@ void DexFileHook::init(JNIEnv *env) { void DexFileHook::setFileReadonly(const char* filePath) { struct stat fileStat; - // 检查文件是否存在 + if (stat(filePath, &fileStat) != 0) { ALOGD("DexFileHook::setFileReadonly: %s 不存在",filePath); return; } - // 设置文件为只读(权限 0444) - //if (chmod(filePath, S_IRUSR | S_IRGRP | S_IROTH) != 0) { + + if (chmod(filePath, S_IRUSR) != 0) { ALOGD("DexFileHook::setFileReadonly: 设置文件 %s 为只读时出错",filePath); } else { diff --git a/Bcore/src/main/cpp/Hook/DexFileHook.h b/Bcore/src/main/cpp/Hook/DexFileHook.h index 0b56801..11286f6 100644 --- a/Bcore/src/main/cpp/Hook/DexFileHook.h +++ b/Bcore/src/main/cpp/Hook/DexFileHook.h @@ -11,4 +11,4 @@ public: }; -#endif //BLACKBOX2_DEXFILEHOOK_H +#endif diff --git a/Bcore/src/main/cpp/Hook/FileSystemHook.cpp b/Bcore/src/main/cpp/Hook/FileSystemHook.cpp index 7dac2c6..faa68c6 100644 --- a/Bcore/src/main/cpp/Hook/FileSystemHook.cpp +++ b/Bcore/src/main/cpp/Hook/FileSystemHook.cpp @@ -1,6 +1,6 @@ -// -// Created for blocking problematic resource files -// + + + #include "FileSystemHook.h" #include "Log.h" @@ -11,13 +11,13 @@ #include #include -// Original function pointers + static int (*orig_open)(const char *pathname, int flags, ...) = nullptr; static int (*orig_open64)(const char *pathname, int flags, ...) = nullptr; -// Hook for open system call + int new_open(const char *pathname, int flags, ...) { - // Block problematic resource paths + if (pathname != nullptr) { if (strstr(pathname, "resource-cache") || strstr(pathname, "@idmap") || @@ -25,12 +25,12 @@ int new_open(const char *pathname, int flags, ...) { strstr(pathname, "systemui") || strstr(pathname, "data@resource-cache@")) { ALOGD("FileSystemHook: Blocking problematic file access: %s", pathname); - errno = ENOENT; // No such file or directory + errno = ENOENT; return -1; } } - // For non-problematic paths, proceed normally + va_list args; va_start(args, flags); mode_t mode = va_arg(args, mode_t); @@ -39,9 +39,9 @@ int new_open(const char *pathname, int flags, ...) { return orig_open(pathname, flags, mode); } -// Hook for open64 system call + int new_open64(const char *pathname, int flags, ...) { - // Block problematic resource paths + if (pathname != nullptr) { if (strstr(pathname, "resource-cache") || strstr(pathname, "@idmap") || @@ -49,12 +49,12 @@ int new_open64(const char *pathname, int flags, ...) { strstr(pathname, "systemui") || strstr(pathname, "data@resource-cache@")) { ALOGD("FileSystemHook: Blocking problematic file access (64): %s", pathname); - errno = ENOENT; // No such file or directory + errno = ENOENT; return -1; } } - // For non-problematic paths, proceed normally + va_list args; va_start(args, flags); mode_t mode = va_arg(args, mode_t); @@ -66,24 +66,24 @@ int new_open64(const char *pathname, int flags, ...) { void FileSystemHook::init() { ALOGD("FileSystemHook: Initializing file system hooks"); - // Load libc.so + void* handle = xdl_open("libc.so", XDL_DEFAULT); if (!handle) { ALOGE("FileSystemHook: Failed to open libc.so"); return; } - // Hook open function + orig_open = (int (*)(const char*, int, ...))xdl_sym(handle, "open", nullptr); if (orig_open) { - // Note: In a real implementation, you would use a proper hooking library - // like PLT hook or similar to replace the function pointer + + ALOGD("FileSystemHook: Found open function at %p", orig_open); } else { ALOGE("FileSystemHook: Failed to find open function"); } - // Hook open64 function + orig_open64 = (int (*)(const char*, int, ...))xdl_sym(handle, "open64", nullptr); if (orig_open64) { ALOGD("FileSystemHook: Found open64 function at %p", orig_open64); diff --git a/Bcore/src/main/cpp/Hook/FileSystemHook.h b/Bcore/src/main/cpp/Hook/FileSystemHook.h index 5b235a0..884e28d 100644 --- a/Bcore/src/main/cpp/Hook/FileSystemHook.h +++ b/Bcore/src/main/cpp/Hook/FileSystemHook.h @@ -1,6 +1,6 @@ -// -// Created for blocking problematic resource files -// + + + #ifndef VIRTUALM_FILESYSTEMHOOK_H #define VIRTUALM_FILESYSTEMHOOK_H @@ -10,4 +10,4 @@ public: static void init(); }; -#endif //VIRTUALM_FILESYSTEMHOOK_H +#endif diff --git a/Bcore/src/main/cpp/Hook/RuntimeHook.cpp b/Bcore/src/main/cpp/Hook/RuntimeHook.cpp index 453622b..b6e3765 100644 --- a/Bcore/src/main/cpp/Hook/RuntimeHook.cpp +++ b/Bcore/src/main/cpp/Hook/RuntimeHook.cpp @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 5/5/21. -// + + + #include "RuntimeHook.h" #import "JniHook/JniHook.h" diff --git a/Bcore/src/main/cpp/Hook/RuntimeHook.h b/Bcore/src/main/cpp/Hook/RuntimeHook.h index 6c714cc..03ffae9 100644 --- a/Bcore/src/main/cpp/Hook/RuntimeHook.h +++ b/Bcore/src/main/cpp/Hook/RuntimeHook.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 5/5/21. -// + + + #ifndef BLACKBOX_RUNTIMEHOOK_H #define BLACKBOX_RUNTIMEHOOK_H @@ -15,4 +15,4 @@ public: }; -#endif //BLACKBOX_RUNTIMEHOOK_H +#endif diff --git a/Bcore/src/main/cpp/Hook/UnixFileSystemHook.cpp b/Bcore/src/main/cpp/Hook/UnixFileSystemHook.cpp index eca42e3..50962fc 100644 --- a/Bcore/src/main/cpp/Hook/UnixFileSystemHook.cpp +++ b/Bcore/src/main/cpp/Hook/UnixFileSystemHook.cpp @@ -1,108 +1,68 @@ -// -// updated by alex5402 on 4/9/21. -// + + + #include #include "UnixFileSystemHook.h" #import "JniHook/JniHook.h" #include "BaseHook.h" -/* - * Class: java_io_UnixFileSystem - * Method: canonicalize0 - * Signature: (Ljava/lang/String;)Ljava/lang/String; - */ + HOOK_JNI(jstring, canonicalize0, JNIEnv *env, jobject obj, jstring path) { jstring redirect = IO::redirectPath(env, path); return orig_canonicalize0(env, obj, redirect); } -/* - * Class: java_io_UnixFileSystem - * Method: getBooleanAttributes0 - * Signature: (Ljava/lang/String;)I - */ + HOOK_JNI(jint, getBooleanAttributes0, JNIEnv *env, jobject obj, jstring abspath) { jstring redirect = IO::redirectPath(env, abspath); return orig_getBooleanAttributes0(env, obj, redirect); } -/* - * Class: java_io_UnixFileSystem - * Method: getLastModifiedTime0 - * Signature: (Ljava/io/File;)J - */ + HOOK_JNI(jlong, getLastModifiedTime0, JNIEnv *env, jobject obj, jobject path) { jobject redirect = IO::redirectPath(env, path); return orig_getLastModifiedTime0(env, obj, redirect); } -/* - * Class: java_io_UnixFileSystem - * Method: setPermission0 - * Signature: (Ljava/io/File;IZZ)Z - */ + HOOK_JNI(jboolean, setPermission0, JNIEnv *env, jobject obj, jobject file, jint access, jboolean enable, jboolean owneronly) { jobject redirect = IO::redirectPath(env, file); return orig_setPermission0(env, obj, redirect, access, enable, owneronly); } -/* - * Class: java_io_UnixFileSystem - * Method: createFileExclusively0 - * Signature: (Ljava/lang/String;)Z - */ + HOOK_JNI(jboolean, createFileExclusively0, JNIEnv *env, jobject obj, jstring path) { jstring redirect = IO::redirectPath(env, path); return orig_createFileExclusively0(env, obj, redirect); } -/* - * Class: java_io_UnixFileSystem - * Method: list0 - * Signature: (Ljava/io/File;)[Ljava/lang/String; - */ + HOOK_JNI(jobjectArray, list0, JNIEnv *env, jobject obj, jobject file) { jobject redirect = IO::redirectPath(env, file); return orig_list0(env, obj, redirect); } -/* - * Class: java_io_UnixFileSystem - * Method: createDirectory0 - * Signature: (Ljava/io/File;)Z - */ + HOOK_JNI(jboolean, createDirectory0, JNIEnv *env, jobject obj, jobject path) { jobject redirect = IO::redirectPath(env, path); return orig_createDirectory0(env, obj, redirect); } -/* - * Class: java_io_UnixFileSystem - * Method: setLastModifiedTime0 - * Signature: (Ljava/io/File;J)Z - */ + HOOK_JNI(jboolean, setLastModifiedTime0, JNIEnv *env, jobject obj, jobject file, jobject time) { jobject redirect = IO::redirectPath(env, file); return orig_setLastModifiedTime0(env, obj, redirect, time); } -/* - * Class: java_io_UnixFileSystem - * Method: setReadOnly0 - * Signature: (Ljava/io/File;)Z - */ + HOOK_JNI(jboolean, setReadOnly0, JNIEnv *env, jobject obj, jobject file) { jobject redirect = IO::redirectPath(env, file); return orig_setReadOnly0(env, obj, redirect); } -/* - * Class: java_io_UnixFileSystem - * Method: getSpace0 - * Signature: (Ljava/io/File;I)J - */ + HOOK_JNI(jboolean, getSpace0, JNIEnv *env, jobject obj, jobject file, jint t) { jobject redirect = IO::redirectPath(env, file); return orig_getSpace0(env, obj, redirect, t); @@ -111,7 +71,7 @@ HOOK_JNI(jboolean, getSpace0, JNIEnv *env, jobject obj, jobject file, jint t) { void UnixFileSystemHook::init(JNIEnv *env) { const char *className = "java/io/UnixFileSystem"; - // Add error handling for canonicalize0 hook + try { JniHook::HookJniFun(env, className, "canonicalize0", "(Ljava/lang/String;)Ljava/lang/String;", (void *) new_canonicalize0, (void **) (&orig_canonicalize0), false); @@ -119,11 +79,11 @@ void UnixFileSystemHook::init(JNIEnv *env) { ALOGD("UnixFileSystemHook: Failed to hook canonicalize0, continuing without it"); } -// JniHook::HookJniFun(env, className, "getBooleanAttributes0", "(Ljava/lang/String;)I", -// (void *) new_getBooleanAttributes0, -// (void **) (&orig_getBooleanAttributes0), false); + + + + - // Add error handling for other hooks try { JniHook::HookJniFun(env, className, "getLastModifiedTime0", "(Ljava/io/File;)J", (void *) new_getLastModifiedTime0, (void **) (&orig_getLastModifiedTime0), diff --git a/Bcore/src/main/cpp/Hook/UnixFileSystemHook.h b/Bcore/src/main/cpp/Hook/UnixFileSystemHook.h index 2f3fe6a..8e6a2d1 100644 --- a/Bcore/src/main/cpp/Hook/UnixFileSystemHook.h +++ b/Bcore/src/main/cpp/Hook/UnixFileSystemHook.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 4/9/21. -// + + + #ifndef VIRTUALM_UNIXFILESYSTEMHOOK_H #define VIRTUALM_UNIXFILESYSTEMHOOK_H @@ -14,4 +14,4 @@ public: }; -#endif //VIRTUALM_UNIXFILESYSTEMHOOK_H +#endif diff --git a/Bcore/src/main/cpp/Hook/VMClassLoaderHook.cpp b/Bcore/src/main/cpp/Hook/VMClassLoaderHook.cpp index cfa907b..cea19c3 100644 --- a/Bcore/src/main/cpp/Hook/VMClassLoaderHook.cpp +++ b/Bcore/src/main/cpp/Hook/VMClassLoaderHook.cpp @@ -1,10 +1,10 @@ -// -// updated by alex5402 on 2021/5/5. -// -// -// updated by alex5402 on 5/5/21. -// + + + + + + #include #include "VMClassLoaderHook.h" @@ -13,7 +13,7 @@ static bool hideXposedClass = false; HOOK_JNI(jobject, findLoadedClass, JNIEnv *env, jobject obj, jobject class_loader, jstring name) { const char * nameC = env->GetStringUTFChars(name, JNI_FALSE); -// ALOGD("findLoadedClass: %s", nameC); + if (hideXposedClass) { if (strstr(nameC, "de/robv/android/xposed/") || strstr(nameC, "me/weishu/epic") || diff --git a/Bcore/src/main/cpp/Hook/VMClassLoaderHook.h b/Bcore/src/main/cpp/Hook/VMClassLoaderHook.h index 0caab0e..64ee782 100644 --- a/Bcore/src/main/cpp/Hook/VMClassLoaderHook.h +++ b/Bcore/src/main/cpp/Hook/VMClassLoaderHook.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 2021/5/5. -// + + + #ifndef BLACKBOX_VMCLASSLOADERHOOK_H #define BLACKBOX_VMCLASSLOADERHOOK_H @@ -16,4 +16,4 @@ public: }; -#endif //BLACKBOX_VMCLASSLOADERHOOK_H +#endif diff --git a/Bcore/src/main/cpp/IO.cpp b/Bcore/src/main/cpp/IO.cpp index 9c05711..7354414 100644 --- a/Bcore/src/main/cpp/IO.cpp +++ b/Bcore/src/main/cpp/IO.cpp @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 4/10/21. -// + + + #include "IO.h" #include "Log.h" @@ -8,14 +8,7 @@ jmethodID getAbsolutePathMethodId; list relocate_rule; -/** - * updated by alex5402 on 4/9/21. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + char *replace(const char *str, const char *src, const char *dst) { const char *pos = str; int count = 0; @@ -42,37 +35,37 @@ char *replace(const char *str, const char *src, const char *dst) { } const char *IO::redirectPath(const char *__path) { - // Block ALL resource-cache related paths that cause issues + if (strstr(__path, "resource-cache")) { ALOGD("Blocking resource-cache path: %s", __path); return "/dev/null"; } - // Block any path containing @idmap + if (strstr(__path, "@idmap")) { ALOGD("Blocking idmap path: %s", __path); return "/dev/null"; } - // Block any path containing systemui with problematic extensions + if (strstr(__path, "systemui") && (strstr(__path, ".frro") || strstr(__path, "-accent-") || strstr(__path, "-dynamic-") || strstr(__path, "-neutral-"))) { ALOGD("Blocking systemui problematic path: %s", __path); return "/dev/null"; } - // Block any path containing the specific problematic patterns + if (strstr(__path, "data@resource-cache@")) { ALOGD("Blocking data@resource-cache@ pattern: %s", __path); return "/dev/null"; } - // Block any path containing .frro files + if (strstr(__path, ".frro")) { ALOGD("Blocking .frro file: %s", __path); return "/dev/null"; } - // Block any path containing systemui + if (strstr(__path, "systemui")) { ALOGD("Blocking systemui path: %s", __path); return "/dev/null"; @@ -83,7 +76,7 @@ const char *IO::redirectPath(const char *__path) { IO::RelocateInfo info = *iterator; if (strstr(__path, info.targetPath) && !strstr(__path, "/blackbox/")) { char *ret = replace(__path, info.targetPath, info.relocatePath); - // ALOGD("redirectPath %s => %s", __path, ret); + return ret; } } @@ -91,20 +84,20 @@ const char *IO::redirectPath(const char *__path) { } jstring IO::redirectPath(JNIEnv *env, jstring path) { -// const char * pathC = env->GetStringUTFChars(path, JNI_FALSE); -// const char *redirect = redirectPath(pathC); -// env->ReleaseStringUTFChars(path, pathC); -// return env->NewStringUTF(redirect); + + + + return BoxCore::redirectPathString(env, path); } jobject IO::redirectPath(JNIEnv *env, jobject path) { -// auto pathStr = -// reinterpret_cast(env->CallObjectMethod(path, getAbsolutePathMethodId)); -// jstring redirect = redirectPath(env, pathStr); -// jobject file = env->NewObject(fileClazz, fileNew, redirect); -// env->DeleteLocalRef(pathStr); -// env->DeleteLocalRef(redirect); + + + + + + return BoxCore::redirectPathFile(env, path); } diff --git a/Bcore/src/main/cpp/IO.h b/Bcore/src/main/cpp/IO.h index d6ba984..bcf2ef0 100644 --- a/Bcore/src/main/cpp/IO.h +++ b/Bcore/src/main/cpp/IO.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 4/10/21. -// + + + #ifndef VIRTUALM_IO_H #define VIRTUALM_IO_H @@ -32,4 +32,4 @@ public: }; -#endif //VIRTUALM_IO_H +#endif diff --git a/Bcore/src/main/cpp/JniHook/ArtMethod.h b/Bcore/src/main/cpp/JniHook/ArtMethod.h index 11a4844..d21de70 100644 --- a/Bcore/src/main/cpp/JniHook/ArtMethod.h +++ b/Bcore/src/main/cpp/JniHook/ArtMethod.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 3/7/21. -// + + + #include #ifndef ARTHOOK_ART_METHOD_H @@ -10,34 +10,34 @@ #define __ANDROID_API_Q__ 29 #define __ANDROID_API_P__ 28 -static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic -static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic -static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic -static constexpr uint32_t kAccStatic = 0x0008; // field, method, ic -static constexpr uint32_t kAccFinal = 0x0010; // class, field, method, ic -static constexpr uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives) -static constexpr uint32_t kAccSuper = 0x0020; // class (not used in dex) -static constexpr uint32_t kAccVolatile = 0x0040; // field -static constexpr uint32_t kAccBridge = 0x0040; // method (1.5) -static constexpr uint32_t kAccTransient = 0x0080; // field -static constexpr uint32_t kAccVarargs = 0x0080; // method (1.5) -static constexpr uint32_t kAccNative = 0x0100; // method -static constexpr uint32_t kAccInterface = 0x0200; // class, ic -static constexpr uint32_t kAccAbstract = 0x0400; // class, method, ic -static constexpr uint32_t kAccStrict = 0x0800; // method -static constexpr uint32_t kAccSynthetic = 0x1000; // class, field, method, ic -static constexpr uint32_t kAccAnnotation = 0x2000; // class, ic (1.5) -static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5) +static constexpr uint32_t kAccPublic = 0x0001; +static constexpr uint32_t kAccPrivate = 0x0002; +static constexpr uint32_t kAccProtected = 0x0004; +static constexpr uint32_t kAccStatic = 0x0008; +static constexpr uint32_t kAccFinal = 0x0010; +static constexpr uint32_t kAccSynchronized = 0x0020; +static constexpr uint32_t kAccSuper = 0x0020; +static constexpr uint32_t kAccVolatile = 0x0040; +static constexpr uint32_t kAccBridge = 0x0040; +static constexpr uint32_t kAccTransient = 0x0080; +static constexpr uint32_t kAccVarargs = 0x0080; +static constexpr uint32_t kAccNative = 0x0100; +static constexpr uint32_t kAccInterface = 0x0200; +static constexpr uint32_t kAccAbstract = 0x0400; +static constexpr uint32_t kAccStrict = 0x0800; +static constexpr uint32_t kAccSynthetic = 0x1000; +static constexpr uint32_t kAccAnnotation = 0x2000; +static constexpr uint32_t kAccEnum = 0x4000; -static constexpr uint32_t kAccPublicApi = 0x10000000; // field, method -static constexpr uint32_t kAccCorePlatformApi = 0x20000000; // field, method +static constexpr uint32_t kAccPublicApi = 0x10000000; +static constexpr uint32_t kAccCorePlatformApi = 0x20000000; -// Native method flags are set when linking the methods based on the presence of the -// @dalvik.annotation.optimization.{Fast,Critical}Native annotations with build visibility. -// Reuse the values of kAccSkipAccessChecks and kAccMiranda which are not used for native methods. -static constexpr uint32_t kAccFastNative = 0x00080000; // method (runtime; native only) -static constexpr uint32_t kAccCriticalNative = 0x00100000; // method (runtime; native only) -static constexpr uint32_t kAccNterpInvokeFastPathFlag = 0x00200000; // method (runtime) -#endif //ARTHOOK_ART_METHOD_H + +static constexpr uint32_t kAccFastNative = 0x00080000; +static constexpr uint32_t kAccCriticalNative = 0x00100000; + +static constexpr uint32_t kAccNterpInvokeFastPathFlag = 0x00200000; + +#endif diff --git a/Bcore/src/main/cpp/JniHook/JniHook.cpp b/Bcore/src/main/cpp/JniHook/JniHook.cpp index 9322a8d..38a5b60 100644 --- a/Bcore/src/main/cpp/JniHook/JniHook.cpp +++ b/Bcore/src/main/cpp/JniHook/JniHook.cpp @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 3/8/21. -// + + + #include #include "JniHook.h" @@ -73,7 +73,7 @@ inline static bool HasAccessFlag(char *art_method, uint32_t flag) { return (flags & flag) == flag; } -// Add error handling for method flag checking + inline static bool IsNativeMethod(char *art_method) { try { return HasAccessFlag(art_method, kAccNative); @@ -84,7 +84,7 @@ inline static bool IsNativeMethod(char *art_method) { } inline static bool ClearFastNativeFlag(char *art_method) { - // FastNative + return HookEnv.api_level < __ANDROID_API_P__ && ClearAccessFlag(art_method, kAccFastNative); } @@ -112,7 +112,7 @@ static void *GetFieldMethod(JNIEnv *env, jobject field) { bool CheckFlags(void *artMethod) { char *method = static_cast(artMethod); - // Add error handling for flag checking + try { if (!HasAccessFlag(method, kAccNative)) { ALOGD("Method is not native, skipping hook"); @@ -171,7 +171,7 @@ JniHook::HookJniFun(JNIEnv *env, const char *class_name, const char *method_name ALOGE("jni hook error. class:%s, method:%s", class_name, method_name); return; } - // FastNative + if (HookEnv.api_level == __ANDROID_API_O__ || HookEnv.api_level == __ANDROID_API_O_MR1__) { AddAccessFlag((char *) artMethod, kAccFastNative); } @@ -241,7 +241,7 @@ void JniHook::InitJniHook(JNIEnv *env, int api_level) { HookEnv.art_method_size = (size_t) nativeOffset2 - (size_t) nativeOffset; int i = 0; - // calc native offset + auto artMethod = reinterpret_cast(nativeOffset); for (i = 0; i < HookEnv.art_method_size; ++i) { if (reinterpret_cast(artMethod[i]) == native_offset) { @@ -259,17 +259,17 @@ void JniHook::InitJniHook(JNIEnv *env, int api_level) { flags = flags | kAccStatic; flags = flags | kAccNative; flags = flags | kAccFinal; - if (api_level >= __ANDROID_API_Q__) {//android 10 + if (api_level >= __ANDROID_API_Q__) { flags = flags | kAccPublicApi; } - if (api_level >= __ANDROID_API_S__) {//android 12 + if (api_level >= __ANDROID_API_S__) { flags = flags | kAccNterpInvokeFastPathFlag; } char *start = reinterpret_cast(artMethod); for (i = 1; i < HookEnv.art_method_size; ++i) { auto value = *(uint32_t *) (start + i * sizeof(uint32_t)); -// ALOGD("art_method_size search:0x%x",value); + if (value == flags) { HookEnv.art_method_flags_offset = i * sizeof(uint32_t); break; diff --git a/Bcore/src/main/cpp/JniHook/JniHook.h b/Bcore/src/main/cpp/JniHook/JniHook.h index 31afc29..72edc76 100644 --- a/Bcore/src/main/cpp/JniHook/JniHook.h +++ b/Bcore/src/main/cpp/JniHook/JniHook.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 3/8/21. -// + + + #ifndef VIRTUAL_APP_JNIHOOK_H #define VIRTUAL_APP_JNIHOOK_H @@ -19,4 +19,4 @@ public: static void HookJniFun(JNIEnv *env, jobject java_method, void *new_fun, void **orig_fun, bool is_static); }; -#endif //VIRTUAL_APP_JNIHOOK_H +#endif diff --git a/Bcore/src/main/cpp/Utils/AntiDetection.cpp b/Bcore/src/main/cpp/Utils/AntiDetection.cpp index aeb7769..8065b2b 100644 --- a/Bcore/src/main/cpp/Utils/AntiDetection.cpp +++ b/Bcore/src/main/cpp/Utils/AntiDetection.cpp @@ -11,14 +11,7 @@ #define LOG_TAG "AntiDetection" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -/** - * created by alex5402 on 4/9/21. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + struct SpoofedProp { const char* key; const char* value; @@ -27,19 +20,12 @@ struct SpoofedProp { static int (*orig_system_property_get)(const char *name, char *value) = nullptr; -// ============================================================================= -// FILE SYSTEM HIDING -// ============================================================================= -/** - * updated by alex5402 on 4/9/21. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + + + + static const char* blocked_files[] = { - // Root detection files + "/system/xbin/su", "/system/bin/su", "/sbin/su", @@ -58,7 +44,7 @@ static const char* blocked_files[] = { "/sbin/magisk", "/data/adb/magisk", - // Virtual environment detection + "/data/virtual", "/data/data/com.benny.openlauncher", "/data/data/io.va.exposed", @@ -71,7 +57,7 @@ static const char* blocked_files[] = { "/blackbox", "/virtual", - // Emulator detection files + "/dev/vboxguest", "/dev/vboxuser", "/dev/qemu_pipe", @@ -93,7 +79,7 @@ static const char* blocked_files[] = { "/system/lib/libmemu.so", "/system/lib/libbluelog.so", - // Xposed detection + "/system/xposed.prop", "/system/framework/XposedBridge.jar", "/data/data/de.robv.android.xposed.installer", @@ -155,7 +141,7 @@ static bool is_blocked_package(const char* path) { return false; } -// Hook function pointers + static int (*orig_access)(const char *pathname, int mode) = nullptr; static int (*orig_stat)(const char *pathname, struct stat *buf) = nullptr; static int (*orig_lstat)(const char *pathname, struct stat *buf) = nullptr; @@ -164,8 +150,8 @@ static int (*orig_open)(const char *pathname, int flags, ...) = nullptr; static ssize_t (*orig_readlink)(const char *pathname, char *buf, size_t bufsiz) = nullptr; static DIR* (*orig_opendir)(const char *name) = nullptr; -// Hook implementations -// Safe whitelist for network and critical paths + + static bool is_safe_path(const char* path) { if (!path) return false; if (strstr(path, "/proc/net/")) return true; @@ -253,7 +239,7 @@ static void install_file_hooks() { LOGD("File system hooks installed"); } -// Main installer function - call this once at startup + __attribute__((constructor)) void install_antidetection_hooks() { LOGD("Installing anti-detection hooks..."); install_file_hooks(); diff --git a/Bcore/src/main/cpp/Utils/HexDump.cpp b/Bcore/src/main/cpp/Utils/HexDump.cpp index 8a12743..c218344 100644 --- a/Bcore/src/main/cpp/Utils/HexDump.cpp +++ b/Bcore/src/main/cpp/Utils/HexDump.cpp @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 2020/8/18. -// + + + #include #include diff --git a/Bcore/src/main/cpp/Utils/HexDump.h b/Bcore/src/main/cpp/Utils/HexDump.h index d966848..15d7985 100644 --- a/Bcore/src/main/cpp/Utils/HexDump.h +++ b/Bcore/src/main/cpp/Utils/HexDump.h @@ -1,6 +1,6 @@ -// -// updated by alex5402 on 2020/8/18. -// + + + #ifndef SPEED_HEXDUMP_H #define SPEED_HEXDUMP_H @@ -11,4 +11,4 @@ class HexDump { }; void HexDump(char *buf, int len, int addr); -#endif //SPEED_HEXDUMP_H +#endif diff --git a/Bcore/src/main/cpp/Utils/VirtualSpoof.cpp b/Bcore/src/main/cpp/Utils/VirtualSpoof.cpp index 3ca8867..752384d 100644 --- a/Bcore/src/main/cpp/Utils/VirtualSpoof.cpp +++ b/Bcore/src/main/cpp/Utils/VirtualSpoof.cpp @@ -5,14 +5,7 @@ #include #include "Dobby/dobby.h" -/** - * created by alex5402 on 4/9/21. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + #define LOG_TAG "VirtualSpoof" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) @@ -40,7 +33,7 @@ SpoofedProp spoofed_props[] = { {"ro.kernel.android.qemud", ""}, {"ro.hardware.egl", "adreno"}, {"ro.boot.qemu", "0"}, - {nullptr, nullptr} // Sentinel + {nullptr, nullptr} }; @@ -78,7 +71,7 @@ void install_property_get_hook() { } -// Initialization function to ensure our hook is loaded + __attribute__((constructor)) void init_virtual_spoof() { install_property_get_hook(); diff --git a/Bcore/src/main/cpp/Utils/elf_util.cpp b/Bcore/src/main/cpp/Utils/elf_util.cpp index 19f7c19..2169254 100644 --- a/Bcore/src/main/cpp/Utils/elf_util.cpp +++ b/Bcore/src/main/cpp/Utils/elf_util.cpp @@ -1,22 +1,4 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2019 Swift Gan - * Copyright (C) 2021 LSPosed Contributors - */ + #include #include #include @@ -43,7 +25,7 @@ ElfImg::ElfImg(std::string_view base_name) : elf(base_name) { return; } - //load elf + int fd = open(elf.data(), O_RDONLY); if (fd < 0) { LOGE("open(%s) failed: %s", elf.c_str(), strerror(errno)); @@ -210,20 +192,20 @@ ElfW(Addr) ElfImg::LinearLookupShort(std::string_view name) const { } } return 0; -// if (auto i = symtabs_.find(name); i != symtabs_.end()) { -// return i->second->st_value; -// } else { -// return 0; -// } + + + + + } ElfImg::~ElfImg() { - //open elf file local + if (buffer) { free(buffer); buffer = nullptr; } - //use mmap + if (header) { munmap(header, size); } diff --git a/Bcore/src/main/cpp/Utils/elf_util.h b/Bcore/src/main/cpp/Utils/elf_util.h index 57f3202..53af1b3 100644 --- a/Bcore/src/main/cpp/Utils/elf_util.h +++ b/Bcore/src/main/cpp/Utils/elf_util.h @@ -1,22 +1,4 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2019 Swift Gan - * Copyright (C) 2021 LSPosed Contributors - */ + #ifndef SANDHOOK_ELF_UTIL_H #define SANDHOOK_ELF_UTIL_H @@ -48,10 +30,10 @@ namespace SandHook { } } -// template requires(std::is_pointer_v) -// constexpr T getSymbAddress(std::string_view name) const { -// return reinterpret_cast(getSymbAddress(name)); -// } + + + + bool isValid() const { return base != nullptr; @@ -135,4 +117,4 @@ namespace SandHook { } } -#endif //SANDHOOK_ELF_UTIL_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/Bcore/src/main/cpp/hidden_api.cpp b/Bcore/src/main/cpp/hidden_api.cpp index 945d965..4d2bc34 100644 --- a/Bcore/src/main/cpp/hidden_api.cpp +++ b/Bcore/src/main/cpp/hidden_api.cpp @@ -5,14 +5,7 @@ #include "hidden_api.h" #include "Utils/elf_util.h" #include "Log.h" -/** - * updated by alex5402 on 4/9/21. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + bool disable_hidden_api(JNIEnv *env) { char version_str[PROP_VALUE_MAX]; if (!__system_property_get("ro.build.version.sdk", version_str)) { @@ -21,7 +14,7 @@ bool disable_hidden_api(JNIEnv *env) { } long android_version = std::strtol(version_str, nullptr, 10); - // Hidden api introduced in sdk 29 + if (android_version < 29) { ALOGD("HiddenAPI: Android version < 29, no need to disable"); return true; @@ -34,7 +27,7 @@ bool disable_hidden_api(JNIEnv *env) { return false; } - // Try multiple possible symbol names for different Android versions + void *addr = nullptr; const char* symbol_names[] = { "_ZN3artL32VMRuntime_setHiddenApiExemptionsEP7_JNIEnvP7_jclassP13_jobjectArray", @@ -64,7 +57,7 @@ bool disable_hidden_api(JNIEnv *env) { return false; } - // L is basically wildcard for everything + jstring wildcard = env->NewStringUTF("L"); if (!wildcard) { ALOGE("HiddenAPI: Failed to create wildcard string"); @@ -78,23 +71,23 @@ bool disable_hidden_api(JNIEnv *env) { } auto func = reinterpret_cast(addr); - // jclass arg is not used so pass string class for the memes + func(env, stringClass, args); ALOGD("HiddenAPI: Successfully disabled hidden API restrictions"); return true; } bool disable_resource_loading() { - // Try to hook the ApkAssets.nativeLoad method directly (safer than system properties) + try { - // Load the framework library + void* handle = xdl_open("libandroid_runtime.so", XDL_DEFAULT); if (handle) { - // Try to find and hook the nativeLoad method + void* nativeLoadAddr = xdl_sym(handle, "_ZN7android8ApkAssets9nativeLoadEPKc", nullptr); if (nativeLoadAddr) { ALOGD("ResourceLoading: Found ApkAssets.nativeLoad at %p", nativeLoadAddr); - // Here we would implement the actual hook, but for now we'll just log it + } else { ALOGD("ResourceLoading: Could not find ApkAssets.nativeLoad symbol"); } @@ -106,16 +99,16 @@ bool disable_resource_loading() { ALOGD("ResourceLoading: Exception while trying to hook ApkAssets.nativeLoad"); } - // Try to hook the file system calls directly + try { - // Load the libc library + void* handle = xdl_open("libc.so", XDL_DEFAULT); if (handle) { - // Try to find and hook the open function + void* openAddr = xdl_sym(handle, "open", nullptr); if (openAddr) { ALOGD("ResourceLoading: Found open function at %p", openAddr); - // Here we would implement the actual hook, but for now we'll just log it + } else { ALOGD("ResourceLoading: Could not find open function symbol"); } diff --git a/Bcore/src/main/cpp/hidden_api.h b/Bcore/src/main/cpp/hidden_api.h index 4ce4b39..c38cb0b 100644 --- a/Bcore/src/main/cpp/hidden_api.h +++ b/Bcore/src/main/cpp/hidden_api.h @@ -7,4 +7,4 @@ bool disable_hidden_api(JNIEnv*); bool disable_resource_loading(); -#endif //BLACKBOX2_HIDDEN_API_H +#endif diff --git a/Bcore/src/main/cpp/xdl.h b/Bcore/src/main/cpp/xdl.h index ef588d5..eeba477 100644 --- a/Bcore/src/main/cpp/xdl.h +++ b/Bcore/src/main/cpp/xdl.h @@ -1,33 +1,33 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-10-04. -// -// xDL version: 2.1.1 -// -// xDL is an enhanced implementation of the Android DL series functions. -// For more information, documentation, and the latest version please check: -// https://github.com/hexhacking/xDL -// + + + + + + + + + + + + + + + + + + + + + + + + + + + + #ifndef IO_GITHUB_HEXHACKING_XDL #define IO_GITHUB_HEXHACKING_XDL @@ -41,25 +41,25 @@ extern "C" { #endif typedef struct { - // same as Dl_info: - const char *dli_fname; // Pathname of shared object that contains address. - void *dli_fbase; // Address at which shared object is loaded. - const char *dli_sname; // Name of nearest symbol with address lower than addr. - void *dli_saddr; // Exact address of symbol named in dli_sname. - // added by xDL: - size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr. - const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object. - size_t dlpi_phnum; // Number of items in dlpi_phdr. + + const char *dli_fname; + void *dli_fbase; + const char *dli_sname; + void *dli_saddr; + + size_t dli_ssize; + const ElfW(Phdr) *dlpi_phdr; + size_t dlpi_phnum; } xdl_info_t; -// -// Default value for flags in both xdl_open() and xdl_iterate_phdr(). -// + + + #define XDL_DEFAULT 0x00 -// -// Enhanced dlopen() / dlclose() / dlsym(). -// + + + #define XDL_TRY_FORCE_LOAD 0x01 #define XDL_ALWAYS_FORCE_LOAD 0x02 void *xdl_open(const char *filename, int flags); @@ -67,22 +67,22 @@ void *xdl_close(void *handle); void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size); void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size); -// -// Enhanced dladdr(). -// + + + int xdl_addr(void *addr, xdl_info_t *info, void **cache); void xdl_addr_clean(void **cache); -// -// Enhanced dl_iterate_phdr(). -// + + + #define XDL_FULL_PATHNAME 0x01 int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags); -// -// Custom dlinfo(). -// -#define XDL_DI_DLINFO 1 // type of info: xdl_info_t + + + +#define XDL_DI_DLINFO 1 int xdl_info(void *handle, int request, void *info); #ifdef __cplusplus diff --git a/Bcore/src/main/cpp/xdl/xdl.c b/Bcore/src/main/cpp/xdl/xdl.c index 6dc743e..fc21709 100644 --- a/Bcore/src/main/cpp/xdl/xdl.c +++ b/Bcore/src/main/cpp/xdl/xdl.c @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-10-04. + + + + + + + + + + + + + + + + + + + + + #include "xdl.h" @@ -67,18 +67,18 @@ typedef struct xdl { const ElfW(Phdr) *dlpi_phdr; ElfW(Half) dlpi_phnum; - struct xdl *next; // to next xdl obj for cache in xdl_addr() - void *linker_handle; // hold handle returned by xdl_linker_force_dlopen() + struct xdl *next; + void *linker_handle; - // - // (1) for searching symbols from .dynsym - // + + + bool dynsym_try_load; - ElfW(Sym) *dynsym; // .dynsym - const char *dynstr; // .dynstr + ElfW(Sym) *dynsym; + const char *dynstr; - // .hash (SYSV hash for .dynstr) + struct { const uint32_t *buckets; uint32_t buckets_cnt; @@ -86,7 +86,7 @@ typedef struct xdl { uint32_t chains_cnt; } sysv_hash; - // .gnu.hash (GNU hash for .dynstr) + struct { const uint32_t *buckets; uint32_t buckets_cnt; @@ -97,24 +97,24 @@ typedef struct xdl { uint32_t bloom_shift; } gnu_hash; - // - // (2) for searching symbols from .symtab - // + + + bool symtab_try_load; uintptr_t base; - ElfW(Sym) *symtab; // .symtab + ElfW(Sym) *symtab; size_t symtab_cnt; - char *strtab; // .strtab + char *strtab; size_t strtab_sz; } xdl_t; #pragma clang diagnostic pop -// load from memory + static int xdl_dynsym_load(xdl_t *self) { - // find the dynamic segment + ElfW(Dyn) *dynamic = NULL; for (size_t i = 0; i < self->dlpi_phnum; i++) { const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]); @@ -125,22 +125,22 @@ static int xdl_dynsym_load(xdl_t *self) { } if (NULL == dynamic) return -1; - // iterate the dynamic segment + for (ElfW(Dyn) *entry = dynamic; entry && entry->d_tag != DT_NULL; entry++) { switch (entry->d_tag) { - case DT_SYMTAB: //.dynsym + case DT_SYMTAB: self->dynsym = (ElfW(Sym) *)(self->load_bias + entry->d_un.d_ptr); break; - case DT_STRTAB: //.dynstr + case DT_STRTAB: self->dynstr = (const char *)(self->load_bias + entry->d_un.d_ptr); break; - case DT_HASH: //.hash + case DT_HASH: self->sysv_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0]; self->sysv_hash.chains_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1]; self->sysv_hash.buckets = &(((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2]); self->sysv_hash.chains = &(self->sysv_hash.buckets[self->sysv_hash.buckets_cnt]); break; - case DT_GNU_HASH: //.gnu.hash + case DT_GNU_HASH: self->gnu_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0]; self->gnu_hash.symoffset = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1]; self->gnu_hash.bloom_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2]; @@ -220,47 +220,47 @@ static void *xdl_get_memory_by_section(void *mem, size_t mem_sz, ElfW(Shdr) *shd return xdl_get_memory(mem, mem_sz, (size_t)shdr->sh_offset, shdr->sh_size); } -// load from disk and memory + static int xdl_symtab_load_from_debugdata(xdl_t *self, int file_fd, size_t file_sz, ElfW(Shdr) *shdr_debugdata) { void *debugdata = NULL; ElfW(Shdr) *shdrs = NULL; int r = -1; - // get zipped .gnu_debugdata + uint8_t *debugdata_zip = (uint8_t *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_debugdata); if (NULL == debugdata_zip) return -1; - // get unzipped .gnu_debugdata + size_t debugdata_sz; if (0 != xdl_lzma_decompress(debugdata_zip, shdr_debugdata->sh_size, (uint8_t **)&debugdata, &debugdata_sz)) goto end; - // get ELF header + ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)debugdata; if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end; - // get section headers + shdrs = (ElfW(Shdr) *)xdl_read_memory_to_heap(debugdata, debugdata_sz, (size_t)ehdr->e_shoff, ehdr->e_shentsize * ehdr->e_shnum); if (NULL == shdrs) goto end; - // get .shstrtab + if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end; char *shstrtab = (char *)xdl_get_memory_by_section(debugdata, debugdata_sz, shdrs + ehdr->e_shstrndx); if (NULL == shstrtab) goto end; - // find .symtab & .strtab + for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) { char *shdr_name = shstrtab + shdr->sh_name; if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) { - // get & check associated .strtab section + if (shdr->sh_link >= ehdr->e_shnum) continue; ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link; if (SHT_STRTAB != shdr_strtab->sh_type) continue; - // get .symtab & .strtab + ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr); if (NULL == symtab) continue; char *strtab = (char *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr_strtab); @@ -269,7 +269,7 @@ static int xdl_symtab_load_from_debugdata(xdl_t *self, int file_fd, size_t file_ continue; } - // OK + self->symtab = symtab; self->symtab_cnt = shdr->sh_size / shdr->sh_entsize; self->strtab = strtab; @@ -286,7 +286,7 @@ end: return r; } -// load from disk and memory + static int xdl_symtab_load(xdl_t *self) { if ('[' == self->pathname[0]) return -1; @@ -294,7 +294,7 @@ static int xdl_symtab_load(xdl_t *self) { ElfW(Shdr) *shdrs = NULL; char *shstrtab = NULL; - // get base address + uintptr_t vaddr_min = UINTPTR_MAX; for (size_t i = 0; i < self->dlpi_phnum; i++) { const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]); @@ -305,18 +305,18 @@ static int xdl_symtab_load(xdl_t *self) { if (UINTPTR_MAX == vaddr_min) return -1; self->base = self->load_bias + vaddr_min; - // open file + int flags = O_RDONLY | O_CLOEXEC; int file_fd; if ('/' == self->pathname[0]) { file_fd = open(self->pathname, flags); } else { char full_pathname[1024]; - // try the fast method + snprintf(full_pathname, sizeof(full_pathname), "%s/%s", XDL_LIB_PATH, self->pathname); file_fd = open(full_pathname, flags); if (file_fd < 0) { - // try the slow method + if (0 != xdl_iterate_get_full_pathname(self->base, full_pathname, sizeof(full_pathname))) return -1; file_fd = open(full_pathname, flags); } @@ -326,31 +326,31 @@ static int xdl_symtab_load(xdl_t *self) { if (0 != fstat(file_fd, &st)) goto end; size_t file_sz = (size_t)st.st_size; - // get ELF header + ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)self->base; if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end; - // get section headers + shdrs = (ElfW(Shdr) *)xdl_read_file_to_heap(file_fd, file_sz, (size_t)ehdr->e_shoff, ehdr->e_shentsize * ehdr->e_shnum); if (NULL == shdrs) goto end; - // get .shstrtab + if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end; shstrtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdrs + ehdr->e_shstrndx); if (NULL == shstrtab) goto end; - // find .symtab & .strtab + for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) { char *shdr_name = shstrtab + shdr->sh_name; if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) { - // get & check associated .strtab section + if (shdr->sh_link >= ehdr->e_shnum) continue; ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link; if (SHT_STRTAB != shdr_strtab->sh_type) continue; - // get .symtab & .strtab + ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr); if (NULL == symtab) continue; char *strtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_strtab); @@ -359,7 +359,7 @@ static int xdl_symtab_load(xdl_t *self) { continue; } - // OK + self->symtab = symtab; self->symtab_cnt = shdr->sh_size / shdr->sh_entsize; self->strtab = strtab; @@ -368,7 +368,7 @@ static int xdl_symtab_load(xdl_t *self) { break; } else if (SHT_PROGBITS == shdr->sh_type && 0 == strcmp(".gnu_debugdata", shdr_name)) { if (0 == xdl_symtab_load_from_debugdata(self, file_fd, file_sz, shdr)) { - // OK + r = 0; break; } @@ -383,21 +383,21 @@ end: } static xdl_t *xdl_find_from_auxv(unsigned long type, const char *pathname) { - if (NULL == getauxval) return NULL; // API level < 18 + if (NULL == getauxval) return NULL; uintptr_t val = (uintptr_t)getauxval(type); if (0 == val) return NULL; - // get base + uintptr_t base = (AT_PHDR == type ? (val & (~0xffful)) : val); if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) return NULL; - // ELF info + ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base; const ElfW(Phdr) *dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); ElfW(Half) dlpi_phnum = ehdr->e_phnum; - // get bias + uintptr_t min_vaddr = UINTPTR_MAX; for (size_t i = 0; i < dlpi_phnum; i++) { const ElfW(Phdr) *phdr = &(dlpi_phdr[i]); @@ -408,7 +408,7 @@ static xdl_t *xdl_find_from_auxv(unsigned long type, const char *pathname) { if (UINTPTR_MAX == min_vaddr || base < min_vaddr) return NULL; uintptr_t load_bias = base - min_vaddr; - // create xDL object + xdl_t *self; if (NULL == (self = calloc(1, sizeof(xdl_t)))) return NULL; if (NULL == (self->pathname = strdup(pathname))) { @@ -430,10 +430,10 @@ static int xdl_find_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg xdl_t **self = (xdl_t **)*pkg++; const char *filename = (const char *)*pkg; - // check load_bias + if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; - // check pathname + if ('[' == filename[0]) { if (0 != strcmp(info->dlpi_name, filename)) return 0; } else if ('/' == filename[0]) { @@ -450,30 +450,30 @@ static int xdl_find_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg } } - // found the target ELF - if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // return failed + + if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; if (NULL == ((*self)->pathname = strdup((const char *)info->dlpi_name))) { free(*self); *self = NULL; - return 1; // return failed + return 1; } (*self)->load_bias = info->dlpi_addr; (*self)->dlpi_phdr = info->dlpi_phdr; (*self)->dlpi_phnum = info->dlpi_phnum; (*self)->dynsym_try_load = false; (*self)->symtab_try_load = false; - return 1; // return OK + return 1; } static xdl_t *xdl_find(const char *filename) { - // from auxv (linker, vDSO) + xdl_t *self = NULL; if (xdl_util_ends_with(filename, XDL_UTIL_LINKER_BASENAME)) self = xdl_find_from_auxv(AT_BASE, XDL_UTIL_LINKER_PATHNAME); else if (xdl_util_ends_with(filename, XDL_UTIL_VDSO_BASENAME)) self = xdl_find_from_auxv(AT_SYSINFO_EHDR, XDL_UTIL_VDSO_BASENAME); - // from auxv (app_process) + const char *basename, *pathname; #if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__ if (xdl_util_get_api_level() < __ANDROID_API_L__) { @@ -489,18 +489,18 @@ static xdl_t *xdl_find(const char *filename) { if (NULL != self) return self; - // from dl_iterate_phdr + uintptr_t pkg[2] = {(uintptr_t)&self, (uintptr_t)filename}; xdl_iterate_phdr(xdl_find_iterate_cb, pkg, XDL_DEFAULT); return self; } static void *xdl_open_always_force(const char *filename) { - // always force dlopen() + void *linker_handle = xdl_linker_force_dlopen(filename); if (NULL == linker_handle) return NULL; - // find + xdl_t *self = xdl_find(filename); if (NULL == self) dlclose(linker_handle); @@ -511,15 +511,15 @@ static void *xdl_open_always_force(const char *filename) { } static void *xdl_open_try_force(const char *filename) { - // find + xdl_t *self = xdl_find(filename); if (NULL != self) return (void *)self; - // try force dlopen() + void *linker_handle = xdl_linker_force_dlopen(filename); if (NULL == linker_handle) return NULL; - // find again + self = xdl_find(filename); if (NULL == self) dlclose(linker_handle); @@ -595,14 +595,14 @@ static ElfW(Sym) *xdl_dynsym_find_symbol_use_gnu_hash(xdl_t *self, const char *s size_t mask = 0 | (size_t)1 << (hash % elfclass_bits) | (size_t)1 << ((hash >> self->gnu_hash.bloom_shift) % elfclass_bits); - // if at least one bit is not set, this symbol is surely missing + if ((word & mask) != mask) return NULL; - // ignore STN_UNDEF + uint32_t i = self->gnu_hash.buckets[hash % self->gnu_hash.buckets_cnt]; if (i < self->gnu_hash.symoffset) return NULL; - // loop through the chain + while (1) { ElfW(Sym) *sym = self->dynsym + i; uint32_t sym_hash = self->gnu_hash.chains[i - self->gnu_hash.symoffset]; @@ -613,7 +613,7 @@ static ElfW(Sym) *xdl_dynsym_find_symbol_use_gnu_hash(xdl_t *self, const char *s } } - // chain ends with an element with the lowest bit set to 1 + if (sym_hash & (uint32_t)1) break; i++; @@ -628,21 +628,21 @@ void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size) { xdl_t *self = (xdl_t *)handle; - // load .dynsym only once + if (!self->dynsym_try_load) { self->dynsym_try_load = true; if (0 != xdl_dynsym_load(self)) return NULL; } - // find symbol + if (NULL == self->dynsym) return NULL; ElfW(Sym) *sym = NULL; if (self->gnu_hash.buckets_cnt > 0) { - // use GNU hash (.gnu.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1) + sym = xdl_dynsym_find_symbol_use_gnu_hash(self, symbol); } if (NULL == sym && self->sysv_hash.buckets_cnt > 0) { - // use SYSV hash (.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1) + sym = xdl_dynsym_find_symbol_use_sysv_hash(self, symbol); } if (NULL == sym || !XDL_DYNSYM_IS_EXPORT_SYM(sym->st_shndx)) return NULL; @@ -651,34 +651,9 @@ void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size) { return (void *)(self->load_bias + sym->st_value); } -// clang-format off -/* - * For internal symbols in .symtab, LLVM may add some suffixes (for example for thinLTO). - * The format of the suffix is: ".xxxx.[hash]". LLVM may add multiple suffixes at once. - * The symbol name after removing these all suffixes is called canonical name. - * - * Because the hash part in the suffix may change when recompiled, so here we only match - * the canonical name. - * - * IN ADDITION: According to C/C++ syntax, it is illegal for a function name to contain - * dot character('.'), either in the middle or at the end. - * - * samples: - * - * symbol name in .symtab lookup is match - * ---------------------- ---------------- -------- - * abcd abc N - * abcd abcde N - * abcd abcd Y - * abcd.llvm.10190306339727611508 abc N - * abcd.llvm.10190306339727611508 abcd Y - * abcd.llvm.10190306339727611508 abcd. N - * abcd.llvm.10190306339727611508 abcd.llvm Y - * abcd.llvm.10190306339727611508 abcd.llvm. N - * abcd.__uniq.513291356003753 abcd.__uniq.51329 N - * abcd.__uniq.513291356003753 abcd.__uniq.513291356003753 Y - */ -// clang-format on + + + static inline bool xdl_dsym_is_match(const char *str, const char *sym, size_t sym_len) { size_t str_len = strlen(str); if (0 == str_len) return false; @@ -689,7 +664,7 @@ static inline bool xdl_dsym_is_match(const char *str, const char *sym, size_t sy bool sym_len_match = (0 == memcmp(str, sym, sym_len)); if (str_len == sym_len) return sym_len_match; - else // str_len > sym_len + else return sym_len_match && (str[sym_len] == '.'); } } @@ -700,20 +675,20 @@ void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size) { xdl_t *self = (xdl_t *)handle; - // load .symtab only once + if (!self->symtab_try_load) { self->symtab_try_load = true; if (0 != xdl_symtab_load(self)) return NULL; } - // find symbol + if (NULL == self->symtab) return NULL; size_t symbol_len = strlen(symbol); for (size_t i = 0; i < self->symtab_cnt; i++) { ElfW(Sym) *sym = self->symtab + i; if (!XDL_SYMTAB_IS_EXPORT_SYM(sym->st_shndx)) continue; - // if (0 != strncmp(self->strtab + sym->st_name, symbol, self->strtab_sz - sym->st_name)) continue; + if (!xdl_dsym_is_match(self->strtab + sym->st_name, symbol, symbol_len)) continue; if (NULL != symbol_size) *symbol_size = sym->st_size; @@ -745,25 +720,25 @@ static int xdl_open_by_addr_iterate_cb(struct dl_phdr_info *info, size_t size, v xdl_t **self = (xdl_t **)*pkg++; uintptr_t addr = *pkg; - if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue + if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; if (xdl_elf_is_match(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum, addr)) { - // found the target ELF - if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // failed + + if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; if (NULL == ((*self)->pathname = strdup((const char *)info->dlpi_name))) { free(*self); *self = NULL; - return 1; // failed + return 1; } (*self)->load_bias = info->dlpi_addr; (*self)->dlpi_phdr = info->dlpi_phdr; (*self)->dlpi_phnum = info->dlpi_phnum; (*self)->dynsym_try_load = false; (*self)->symtab_try_load = false; - return 1; // OK + return 1; } - return 0; // continue + return 0; } static void *xdl_open_by_addr(void *addr) { @@ -790,13 +765,13 @@ static bool xdl_sym_is_match(ElfW(Sym) *sym, uintptr_t offset, bool is_symtab) { static ElfW(Sym) *xdl_sym_by_addr(void *handle, void *addr) { xdl_t *self = (xdl_t *)handle; - // load .dynsym only once + if (!self->dynsym_try_load) { self->dynsym_try_load = true; if (0 != xdl_dynsym_load(self)) return NULL; } - // find symbol + if (NULL == self->dynsym) return NULL; uintptr_t offset = (uintptr_t)addr - self->load_bias; if (self->gnu_hash.buckets_cnt > 0) { @@ -822,13 +797,13 @@ static ElfW(Sym) *xdl_sym_by_addr(void *handle, void *addr) { static ElfW(Sym) *xdl_dsym_by_addr(void *handle, void *addr) { xdl_t *self = (xdl_t *)handle; - // load .symtab only once + if (!self->symtab_try_load) { self->symtab_try_load = true; if (0 != xdl_symtab_load(self)) return NULL; } - // find symbol + if (NULL == self->symtab) return NULL; uintptr_t offset = (uintptr_t)addr - self->load_bias; for (size_t i = 0; i < self->symtab_cnt; i++) { @@ -844,12 +819,12 @@ int xdl_addr(void *addr, xdl_info_t *info, void **cache) { memset(info, 0, sizeof(Dl_info)); - // find handle from cache + xdl_t *handle = NULL; for (handle = *((xdl_t **)cache); NULL != handle; handle = handle->next) if (xdl_elf_is_match(handle->load_bias, handle->dlpi_phdr, handle->dlpi_phnum, (uintptr_t)addr)) break; - // create new handle, save handle to cache + if (NULL == handle) { handle = (xdl_t *)xdl_open_by_addr(addr); if (NULL == handle) return 0; @@ -857,7 +832,7 @@ int xdl_addr(void *addr, xdl_info_t *info, void **cache) { *(xdl_t **)cache = handle; } - // we have at least: load_bias, pathname, dlpi_phdr, dlpi_phnum + info->dli_fbase = (void *)handle->load_bias; info->dli_fname = handle->pathname; info->dli_sname = NULL; @@ -866,7 +841,7 @@ int xdl_addr(void *addr, xdl_info_t *info, void **cache) { info->dlpi_phdr = handle->dlpi_phdr; info->dlpi_phnum = (size_t)handle->dlpi_phnum; - // keep looking for: symbol name, symbol offset, symbol size + ElfW(Sym) *sym; if (NULL != (sym = xdl_sym_by_addr((void *)handle, addr))) { info->dli_sname = handle->dynstr + sym->st_name; diff --git a/Bcore/src/main/cpp/xdl/xdl_iterate.c b/Bcore/src/main/cpp/xdl/xdl_iterate.c index b89b642..b61b717 100644 --- a/Bcore/src/main/cpp/xdl/xdl_iterate.c +++ b/Bcore/src/main/cpp/xdl/xdl_iterate.c @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-10-04. + + + + + + + + + + + + + + + + + + + + + #include "xdl_iterate.h" @@ -40,22 +40,7 @@ #include "xdl_linker.h" #include "xdl_util.h" -/* - * ========================================================================================================= - * API-LEVEL ANDROID-VERSION SOLUTION - * ========================================================================================================= - * 16 4.1 /proc/self/maps - * 17 4.2 /proc/self/maps - * 18 4.3 /proc/self/maps - * 19 4.4 /proc/self/maps - * 20 4.4W /proc/self/maps - * --------------------------------------------------------------------------------------------------------- - * 21 5.0 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3) - * 22 5.1 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3) - * --------------------------------------------------------------------------------------------------------- - * 23 >= 6.0 dl_iterate_phdr() + linker/linker64 from getauxval(3) - * ========================================================================================================= - */ + extern __attribute((weak)) int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *); extern __attribute((weak)) unsigned long int getauxval(unsigned long int); @@ -82,28 +67,28 @@ static int xdl_iterate_open_or_rewind_maps(FILE **maps) { } static int xdl_iterate_get_pathname_from_maps(uintptr_t base, char *buf, size_t buf_len, FILE **maps) { - // open or rewind maps-file - if (0 != xdl_iterate_open_or_rewind_maps(maps)) return -1; // failed + + if (0 != xdl_iterate_open_or_rewind_maps(maps)) return -1; char line[1024]; while (fgets(line, sizeof(line), *maps)) { - // check base address + uintptr_t start, end; if (2 != sscanf(line, "%" SCNxPTR "-%" SCNxPTR " r", &start, &end)) continue; - if (base < start) break; // failed + if (base < start) break; if (base >= end) continue; - // get pathname + char *pathname = strchr(line, '/'); - if (NULL == pathname) break; // failed + if (NULL == pathname) break; xdl_util_trim_ending(pathname); - // found it + strlcpy(buf, pathname, buf_len); - return 0; // OK + return 0; } - return -1; // failed + return -1; } static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void *arg) { @@ -114,10 +99,10 @@ static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void uintptr_t linker_load_bias = *pkg++; int flags = (int)*pkg; - // ignore invalid ELF + if (0 == info->dlpi_addr || NULL == info->dlpi_name || '\0' == info->dlpi_name[0]) return 0; - // ignore linker if we have returned it already + if (linker_load_bias == info->dlpi_addr) return 0; struct dl_phdr_info info_fixed; @@ -127,27 +112,27 @@ static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void info_fixed.dlpi_phnum = info->dlpi_phnum; info = &info_fixed; - // fix dlpi_phdr & dlpi_phnum (from memory) + if (NULL == info->dlpi_phdr || 0 == info->dlpi_phnum) { ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)info->dlpi_addr; info->dlpi_phdr = (ElfW(Phdr) *)(info->dlpi_addr + ehdr->e_phoff); info->dlpi_phnum = ehdr->e_phnum; } - // fix dlpi_name (from /proc/self/maps) + if ('/' != info->dlpi_name[0] && '[' != info->dlpi_name[0] && (0 != (flags & XDL_FULL_PATHNAME))) { - // get base address + uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(info); - if (UINTPTR_MAX == min_vaddr) return 0; // ignore this ELF + if (UINTPTR_MAX == min_vaddr) return 0; uintptr_t base = (uintptr_t)(info->dlpi_addr + min_vaddr); char buf[1024]; - if (0 != xdl_iterate_get_pathname_from_maps(base, buf, sizeof(buf), maps)) return 0; // ignore this ELF + if (0 != xdl_iterate_get_pathname_from_maps(base, buf, sizeof(buf), maps)) return 0; info->dlpi_name = (const char *)buf; } - // callback + return cb(info, size, cb_arg); } @@ -170,9 +155,9 @@ static int xdl_iterate_do_callback(xdl_iterate_phdr_cb_t cb, void *cb_arg, uintp info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); info.dlpi_phnum = ehdr->e_phnum; - // get load bias + uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(&info); - if (UINTPTR_MAX == min_vaddr) return 0; // ignore invalid ELF + if (UINTPTR_MAX == min_vaddr) return 0; info.dlpi_addr = (ElfW(Addr))(base - min_vaddr); if (NULL != load_bias) *load_bias = info.dlpi_addr; @@ -186,8 +171,8 @@ static int xdl_iterate_by_linker(xdl_iterate_phdr_cb_t cb, void *cb_arg, int fla FILE *maps = NULL; int r; - // dl_iterate_phdr(3) does NOT contain linker/linker64 when Android version < 8.1 (API level 27). - // Here we always try to get linker base address from auxv. + + uintptr_t linker_load_bias = 0; uintptr_t linker_base = xdl_iterate_get_linker_base(); if (0 != linker_base) { @@ -196,7 +181,7 @@ static int xdl_iterate_by_linker(xdl_iterate_phdr_cb_t cb, void *cb_arg, int fla return r; } - // for other ELF + uintptr_t pkg[5] = {(uintptr_t)cb, (uintptr_t)cb_arg, (uintptr_t)&maps, linker_load_bias, (uintptr_t)flags}; if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_lock(); r = dl_iterate_phdr(xdl_iterate_by_linker_cb, pkg); @@ -218,20 +203,20 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) { bool try_next_line = false; while (fgets(line, sizeof(buf1), maps)) { - // Try to find an ELF which loaded by linker. + uintptr_t base, offset; char exec; if (3 != sscanf(line, "%" SCNxPTR "-%*" SCNxPTR " r%*c%cp %" SCNxPTR " ", &base, &exec, &offset)) goto clean; if ('-' == exec && 0 == offset) { - // r--p + prev_base = base; line = (line == buf1 ? buf2 : buf1); try_next_line = true; continue; } else if (exec == 'x') { - // r-xp + char *pathname = NULL; if (try_next_line && 0 != offset) { char *prev = (line == buf1 ? buf2 : buf1); @@ -245,14 +230,14 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) { xdl_util_trim_ending(pathname); if (0 != strcmp(prev_pathname, pathname)) goto clean; - // we found the line with r-xp in the next line + base = prev_base; offset = 0; } if (0 != offset) goto clean; - // get pathname + if (NULL == pathname) { pathname = strchr(line, '/'); if (NULL == pathname) goto clean; @@ -266,7 +251,7 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) { info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); info.dlpi_phnum = ehdr->e_phnum; - // callback + if (0 != (r = xdl_iterate_do_callback(cb, cb_arg, base, pathname, NULL))) break; } @@ -280,12 +265,12 @@ static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) { #endif int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) { - // iterate by /proc/self/maps in Android 4.x (Android 4.x only supports arm32 and x86) + #if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__ if (xdl_util_get_api_level() < __ANDROID_API_L__) return xdl_iterate_by_maps(cb, cb_arg); #endif - // iterate by dl_iterate_phdr() + return xdl_iterate_by_linker(cb, cb_arg, flags); } diff --git a/Bcore/src/main/cpp/xdl/xdl_iterate.h b/Bcore/src/main/cpp/xdl/xdl_iterate.h index ab22866..fdd7dc6 100644 --- a/Bcore/src/main/cpp/xdl/xdl_iterate.h +++ b/Bcore/src/main/cpp/xdl/xdl_iterate.h @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-10-04. + + + + + + + + + + + + + + + + + + + + + #ifndef IO_GITHUB_HEXHACKING_XDL_ITERATE #define IO_GITHUB_HEXHACKING_XDL_ITERATE diff --git a/Bcore/src/main/cpp/xdl/xdl_linker.c b/Bcore/src/main/cpp/xdl/xdl_linker.c index 9021867..e1523a2 100644 --- a/Bcore/src/main/cpp/xdl/xdl_linker.c +++ b/Bcore/src/main/cpp/xdl/xdl_linker.c @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2021-02-21. + + + + + + + + + + + + + + + + + + + + + #include "xdl_linker.h" @@ -66,8 +66,8 @@ typedef struct { size_t matches_cursor; } xdl_linker_caller_t; -// https://source.android.com/docs/core/architecture/vndk/linker-namespace -// The following rules are loose and incomplete, you can add more according to your needs. + + static xdl_linker_match_t xdl_linker_match_default[] = {{MATCH_SUFFIX, "/libc.so"}}; static xdl_linker_match_t xdl_linker_match_art[] = {{MATCH_SUFFIX, "/libart.so"}}; static xdl_linker_match_t xdl_linker_match_sphal[] = {{MATCH_PREFIX, "/vendor/" LIB "/egl/"}, @@ -84,26 +84,26 @@ static xdl_linker_caller_t xdl_linker_callers[] = { {NULL, xdl_linker_match_vndk, sizeof(xdl_linker_match_vndk) / sizeof(xdl_linker_match_t)}}; static void xdl_linker_init_symbols_impl(void) { - // find linker from: /proc/self/maps (API level < 18) or getauxval (API level >= 18) + void *handle = xdl_open(XDL_UTIL_LINKER_BASENAME, XDL_DEFAULT); if (NULL == handle) return; int api_level = xdl_util_get_api_level(); if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) { - // == Android 5.x + xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL); } else if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) { - // == Android 7.x + xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_EXT_N, NULL); if (NULL == xdl_linker_dlopen) { xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DO_DLOPEN_N, NULL); xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL); } } else if (__ANDROID_API_O__ == api_level || __ANDROID_API_O_MR1__ == api_level) { - // == Android 8.x + xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_O, NULL); } else if (api_level >= __ANDROID_API_P__) { - // >= Android 9.0 + xdl_linker_dlopen = xdl_sym(handle, XDL_LINKER_SYM_LOADER_DLOPEN_P, NULL); } @@ -154,9 +154,9 @@ static void xdl_linker_save_caller_addr(struct dl_phdr_info *info, xdl_linker_ca static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) { (void)size, (void)arg; - if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue + if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; - int ret = 1; // OK + int ret = 1; for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { xdl_linker_caller_t *caller = &xdl_linker_callers[i]; for (size_t j = 0; j < caller->matches_cursor; j++) { @@ -174,7 +174,7 @@ static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, break; } } - if (NULL == caller->addr || 0 != caller->matches_cursor) ret = 0; // continue + if (NULL == caller->addr || 0 != caller->matches_cursor) ret = 0; } return ret; } @@ -200,7 +200,7 @@ void *xdl_linker_force_dlopen(const char *filename) { int api_level = xdl_util_get_api_level(); if (api_level <= __ANDROID_API_M__) { - // <= Android 6.0 + return dlopen(filename, RTLD_NOW); } else { xdl_linker_init_symbols(); @@ -209,7 +209,7 @@ void *xdl_linker_force_dlopen(const char *filename) { void *handle = NULL; if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) { - // == Android 7.x + xdl_linker_lock(); for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { xdl_linker_caller_t *caller = &xdl_linker_callers[i]; @@ -220,7 +220,7 @@ void *xdl_linker_force_dlopen(const char *filename) { } xdl_linker_unlock(); } else { - // >= Android 8.0 + for (size_t i = 0; i < sizeof(xdl_linker_callers) / sizeof(xdl_linker_callers[0]); i++) { xdl_linker_caller_t *caller = &xdl_linker_callers[i]; if (NULL != caller->addr) { diff --git a/Bcore/src/main/cpp/xdl/xdl_linker.h b/Bcore/src/main/cpp/xdl/xdl_linker.h index 00cbf44..36d329e 100644 --- a/Bcore/src/main/cpp/xdl/xdl_linker.h +++ b/Bcore/src/main/cpp/xdl/xdl_linker.h @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2021-02-21. + + + + + + + + + + + + + + + + + + + + + #ifndef IO_GITHUB_HEXHACKING_XDL_LINKER #define IO_GITHUB_HEXHACKING_XDL_LINKER diff --git a/Bcore/src/main/cpp/xdl/xdl_lzma.c b/Bcore/src/main/cpp/xdl/xdl_lzma.c index c673933..e6f5e67 100644 --- a/Bcore/src/main/cpp/xdl/xdl_lzma.c +++ b/Bcore/src/main/cpp/xdl/xdl_lzma.c @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-11-08. + + + + + + + + + + + + + + + + + + + + + #include "xdl_lzma.h" @@ -36,7 +36,7 @@ #include "xdl.h" #include "xdl_util.h" -// LZMA library pathname & symbol names + #ifndef __LP64__ #define XDL_LZMA_PATHNAME "/system/lib/liblzma.so" #else @@ -49,26 +49,26 @@ #define XDL_LZMA_SYM_FREE "XzUnpacker_Free" #define XDL_LZMA_SYM_CODE "XzUnpacker_Code" -// LZMA data type definition + #define SZ_OK 0 typedef struct ISzAlloc ISzAlloc; typedef const ISzAlloc *ISzAllocPtr; struct ISzAlloc { void *(*Alloc)(ISzAllocPtr p, size_t size); - void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ + void (*Free)(ISzAllocPtr p, void *address); }; typedef enum { - CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ - CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ - CODER_STATUS_NOT_FINISHED, /* stream was not finished */ - CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ + CODER_STATUS_NOT_SPECIFIED, + CODER_STATUS_FINISHED_WITH_MARK, + CODER_STATUS_NOT_FINISHED, + CODER_STATUS_NEEDS_MORE_INPUT } ECoderStatus; typedef enum { - CODER_FINISH_ANY, /* finish at any point */ - CODER_FINISH_END /* block must be finished at the end */ + CODER_FINISH_ANY, + CODER_FINISH_END } ECoderFinishMode; -// LZMA function type definition + typedef void (*xdl_lzma_crcgen_t)(void); typedef void (*xdl_lzma_crc64gen_t)(void); typedef void (*xdl_lzma_construct_t)(void *, ISzAllocPtr); @@ -79,13 +79,13 @@ typedef int (*xdl_lzma_code_t)(void *, uint8_t *, size_t *, const uint8_t *, siz typedef int (*xdl_lzma_code_q_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, int, ECoderFinishMode, ECoderStatus *); -// LZMA function pointor + static xdl_lzma_construct_t xdl_lzma_construct = NULL; static xdl_lzma_isfinished_t xdl_lzma_isfinished = NULL; static xdl_lzma_free_t xdl_lzma_free = NULL; static void *xdl_lzma_code = NULL; -// LZMA init + static void xdl_lzma_init(void) { void *lzma = xdl_open(XDL_LZMA_PATHNAME, XDL_TRY_FORCE_LOAD); if (NULL == lzma) return; @@ -107,7 +107,7 @@ end: xdl_close(lzma); } -// LZMA internal alloc / free + static void *xdl_lzma_internal_alloc(ISzAllocPtr p, size_t size) { (void)p; return malloc(size); @@ -123,11 +123,11 @@ int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *ds size_t src_remaining; size_t dst_remaining; ISzAlloc alloc = {.Alloc = xdl_lzma_internal_alloc, .Free = xdl_lzma_internal_free}; - long long state[4096 / sizeof(long long)]; // must be enough, 8-bit aligned + long long state[4096 / sizeof(long long)]; ECoderStatus status; int api_level = xdl_util_get_api_level(); - // init and check + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static bool inited = false; if (!inited) { diff --git a/Bcore/src/main/cpp/xdl/xdl_lzma.h b/Bcore/src/main/cpp/xdl/xdl_lzma.h index 63c848a..2c95dc5 100644 --- a/Bcore/src/main/cpp/xdl/xdl_lzma.h +++ b/Bcore/src/main/cpp/xdl/xdl_lzma.h @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-11-08. + + + + + + + + + + + + + + + + + + + + + #ifndef IO_GITHUB_HEXHACKING_XDL_LZMA #define IO_GITHUB_HEXHACKING_XDL_LZMA diff --git a/Bcore/src/main/cpp/xdl/xdl_util.c b/Bcore/src/main/cpp/xdl/xdl_util.c index 7624ca4..c5bd512 100644 --- a/Bcore/src/main/cpp/xdl/xdl_util.c +++ b/Bcore/src/main/cpp/xdl/xdl_util.c @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-10-04. + + + + + + + + + + + + + + + + + + + + + #include "xdl_util.h" @@ -92,7 +92,7 @@ int xdl_util_get_api_level(void) { if (xdl_util_api_level < 0) { int api_level = GetAndroidApiLevel(); if (api_level < 0) - api_level = xdl_util_get_api_level_from_build_prop(); // compatible with unusual models + api_level = xdl_util_get_api_level_from_build_prop(); if (api_level < __ANDROID_API_J__) api_level = __ANDROID_API_J__; __atomic_store_n(&xdl_util_api_level, api_level, __ATOMIC_SEQ_CST); diff --git a/Bcore/src/main/cpp/xdl/xdl_util.h b/Bcore/src/main/cpp/xdl/xdl_util.h index 582e99f..4d039e0 100644 --- a/Bcore/src/main/cpp/xdl/xdl_util.h +++ b/Bcore/src/main/cpp/xdl/xdl_util.h @@ -1,25 +1,25 @@ -// Copyright (c) 2020-2023 HexHacking Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Created by caikelun on 2020-10-04. + + + + + + + + + + + + + + + + + + + + + #ifndef IO_GITHUB_HEXHACKING_XDL_UTIL #define IO_GITHUB_HEXHACKING_XDL_UTIL diff --git a/Bcore/src/main/java/android/app/ActivityThread.java b/Bcore/src/main/java/android/app/ActivityThread.java index f8ef4b5..e22a185 100644 --- a/Bcore/src/main/java/android/app/ActivityThread.java +++ b/Bcore/src/main/java/android/app/ActivityThread.java @@ -12,14 +12,7 @@ import java.lang.ref.WeakReference; import java.util.Map; import java.util.Objects; -/** - * updated by alex5402 on 2021/5/7. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + public class ActivityThread { public H mH = null; public AppBindData mBoundApplication; diff --git a/Bcore/src/main/java/android/app/ContentProviderHolder.java b/Bcore/src/main/java/android/app/ContentProviderHolder.java index 75d8171..eac6ecb 100644 --- a/Bcore/src/main/java/android/app/ContentProviderHolder.java +++ b/Bcore/src/main/java/android/app/ContentProviderHolder.java @@ -4,14 +4,7 @@ import android.content.IContentProvider; import android.content.pm.ProviderInfo; import android.os.IBinder; -/** - * updated by alex5402 on 2021/5/7. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + public class ContentProviderHolder { public final ProviderInfo info = null; public IContentProvider provider; diff --git a/Bcore/src/main/java/android/content/IContentProvider.java b/Bcore/src/main/java/android/content/IContentProvider.java index 1687d8b..d5631f6 100644 --- a/Bcore/src/main/java/android/content/IContentProvider.java +++ b/Bcore/src/main/java/android/content/IContentProvider.java @@ -2,13 +2,6 @@ package android.content; import android.os.IInterface; -/** - * updated by alex5402 on 2021/5/7. - * * ∧_∧ - * (`・ω・∥ - * 丶 つ0 - * しーJ - * - */ + public interface IContentProvider extends IInterface { } diff --git a/Bcore/src/main/java/android/content/SyncInfo.java b/Bcore/src/main/java/android/content/SyncInfo.java index c1ba2c8..575f473 100644 --- a/Bcore/src/main/java/android/content/SyncInfo.java +++ b/Bcore/src/main/java/android/content/SyncInfo.java @@ -1,18 +1,4 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ + package android.content; @@ -20,64 +6,45 @@ import android.accounts.Account; import android.os.Parcel; import android.os.Parcelable; -/** - * Information about the sync operation that is currently underway. - */ + public class SyncInfo implements Parcelable { - /** - * Used when the caller receiving this object doesn't have permission to access the accounts - * on device. - * @See Manifest.permission.GET_ACCOUNTS - */ + private static final Account REDACTED_ACCOUNT = new Account("*****", "*****"); - /** @hide */ + public final int authorityId; - /** - * The {@link Account} that is currently being synced. - */ + public final Account account; - /** - * The authority of the provider that is currently being synced. - */ + public final String authority; - /** - * The start time of the current sync operation in milliseconds since boot. - * This is represented in elapsed real time. - * See {@link android.os.SystemClock#elapsedRealtime()}. - */ + public final long startTime; - /** - * Creates a SyncInfo object with an unusable Account. Used when the caller receiving this - * object doesn't have access to the accounts on the device. - * @See Manifest.permission.GET_ACCOUNTS - * @hide - */ + public static SyncInfo createAccountRedacted( int authorityId, String authority, long startTime) { throw new RuntimeException("Stub!"); } - /** @hide */ + public SyncInfo(int authorityId, Account account, String authority, long startTime) { throw new RuntimeException("Stub!"); } - /** @hide */ + public SyncInfo(SyncInfo other) { throw new RuntimeException("Stub!"); } - /** @hide */ + public int describeContents() { return 0; } - /** @hide */ + public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(authorityId); parcel.writeParcelable(account, flags); diff --git a/Bcore/src/main/java/android/content/SyncStatusInfo.java b/Bcore/src/main/java/android/content/SyncStatusInfo.java index 20c00af..4f34222 100644 --- a/Bcore/src/main/java/android/content/SyncStatusInfo.java +++ b/Bcore/src/main/java/android/content/SyncStatusInfo.java @@ -26,8 +26,8 @@ public class SyncStatusInfo implements Parcelable { public boolean pending; public boolean initialize; - // Warning: It is up to the external caller to ensure there are - // no race conditions when accessing this list + + private ArrayList 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 create(modelClass: Class): T { diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsManagerActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsManagerActivity.kt index e33ac5c..b7d1255 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsManagerActivity.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsManagerActivity.kt @@ -16,12 +16,7 @@ import top.niunaijun.blackboxa.util.inflate import top.niunaijun.blackboxa.util.toast import top.niunaijun.blackboxa.view.base.LoadingActivity -/** - * - * @Description: gms manager activity - * @Author: BlackBox - * @CreateDate: 2022/3/2 21:06 - */ + class GmsManagerActivity : LoadingActivity() { private lateinit var viewModel: GmsViewModel diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsViewModel.kt index 77981fc..28289e7 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsViewModel.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/gms/GmsViewModel.kt @@ -6,12 +6,7 @@ import top.niunaijun.blackboxa.bean.GmsInstallBean import top.niunaijun.blackboxa.data.GmsRepository import top.niunaijun.blackboxa.view.base.BaseViewModel -/** - * - * @Description: gms viewModel - * @Author: BlackBox - * @CreateDate: 2022/3/2 21:11 - */ + class GmsViewModel(private val mRepo: GmsRepository) : BaseViewModel() { val mInstalledLiveData = MutableLiveData>() diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListAdapter.kt index 8f0f8c7..df3aabb 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListAdapter.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListAdapter.kt @@ -8,12 +8,7 @@ import top.niunaijun.blackboxa.R import top.niunaijun.blackboxa.bean.InstalledAppBean import top.niunaijun.blackboxa.databinding.ItemPackageBinding -/** - * - * @Description: 软件显示界面适配器 - * @Author: wukaicheng - * @CreateDate: 2021/4/29 21:52 - */ + class ListAdapter : RVHolderFactory() { diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListFactory.kt b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListFactory.kt index 0da1a6c..6138b9f 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListFactory.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListFactory.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 ListFactory(private val appsRepository: AppsRepository) : ViewModelProvider.NewInstanceFactory() { diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListViewModel.kt b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListViewModel.kt index b170436..7e049d6 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/list/ListViewModel.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/list/ListViewModel.kt @@ -5,12 +5,7 @@ import top.niunaijun.blackboxa.bean.InstalledAppBean import top.niunaijun.blackboxa.data.AppsRepository import top.niunaijun.blackboxa.view.base.BaseViewModel -/** - * - * @Description: - * @Author: wukaicheng - * @CreateDate: 2021/4/29 22:36 - */ + class ListViewModel(private val repo: AppsRepository) : BaseViewModel() { val appsLiveData = MutableLiveData>() diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt index 6d6d089..0a2030a 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/main/BlackBoxLoader.kt @@ -12,12 +12,7 @@ import top.niunaijun.blackboxa.app.App import top.niunaijun.blackboxa.app.rocker.RockerManager import top.niunaijun.blackboxa.biz.cache.AppSharedPreferenceDelegate -/** - * - * @Description: - * @Author: wukaicheng - * @CreateDate: 2021/5/6 23:38 - */ + class BlackBoxLoader { private var mHideRoot by AppSharedPreferenceDelegate(App.getContext(), false) @@ -25,9 +20,11 @@ class BlackBoxLoader { private var mDaemonEnable by AppSharedPreferenceDelegate(App.getContext(), false) private var mShowShortcutPermissionDialog by AppSharedPreferenceDelegate(App.getContext(), true) - // VPN network mode: true = use VPN, false = normal network + private var mUseVpnNetwork by AppSharedPreferenceDelegate(App.getContext(), false) + private var mDisableFlagSecure by AppSharedPreferenceDelegate(App.getContext(), false) + fun hideRoot(): Boolean { return try { mHideRoot @@ -45,6 +42,23 @@ class BlackBoxLoader { } } + fun disableFlagSecure(): Boolean { + return try { + mDisableFlagSecure + } catch (e: Exception) { + Log.e(TAG, "Error getting disableFlagSecure: ${e.message}") + false + } + } + + fun invalidDisableFlagSecure(disable: Boolean) { + try { + this.mDisableFlagSecure = disable + } catch (e: Exception) { + Log.e(TAG, "Error setting disableFlagSecure: ${e.message}") + } + } + fun daemonEnable(): Boolean { return try { mDaemonEnable @@ -174,9 +188,9 @@ class BlackBoxLoader { TAG, "Storage permission needed for launching: $packageName" ) - // Broadcast to request storage permission - // The main activity should listen for this and show - // permission dialog + + + val intent = android.content.Intent( "top.niunaijun.blackboxa.REQUEST_STORAGE_PERMISSION" @@ -185,11 +199,11 @@ class BlackBoxLoader { intent.putExtra("user_id", userId) intent.setPackage(App.getContext().packageName) App.getContext().sendBroadcast(intent) - // Return false to NOT block the launch - the app will - // launch anyway - // but the user will be notified to grant permission - // Change to 'true' if you want to block launch until - // permission is granted + + + + + return false } catch (e: Exception) { Log.e( @@ -248,6 +262,15 @@ class BlackBoxLoader { } } + override fun isDisableFlagSecure(): Boolean { + return try { + mDisableFlagSecure + } catch (e: Exception) { + Log.e(TAG, "Error checking disableFlagSecure: ${e.message}") + false + } + } + override fun requestInstallPackage( file: File?, userId: Int @@ -279,12 +302,12 @@ class BlackBoxLoader { try { BlackBoxCore.get().doCreate() - // Register callback to refresh app list when services become available + try { BlackBoxCore.get().addServiceAvailableCallback { Log.d(TAG, "Services became available, triggering app list refresh") - // This will be called when services are ready - // The UI components can listen for this and refresh their data + + } } catch (e: Exception) { Log.e(TAG, "Error registering service available callback: ${e.message}") diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt index 2aa0fbc..3844faa 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/main/MainActivity.kt @@ -63,10 +63,10 @@ class MainActivity : LoadingActivity() { initFab() initToolbarSubTitle() - // Check and request storage permission on Android 11+ + checkStoragePermission() - // Check and request VPN permission + checkVpnPermission() try { @@ -76,7 +76,7 @@ class MainActivity : LoadingActivity() { } } catch (e: Exception) { Log.e(TAG, "Critical error in onCreate: ${e.message}") - // Show error dialog to user + showErrorDialog("Failed to initialize app: ${e.message}") } } @@ -84,13 +84,13 @@ class MainActivity : LoadingActivity() { private fun checkStoragePermission() { try { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { - // Android 11+: Need MANAGE_EXTERNAL_STORAGE + if (!android.os.Environment.isExternalStorageManager()) { Log.w(TAG, "MANAGE_EXTERNAL_STORAGE permission not granted") showStoragePermissionDialog() } } else { - // Android 10 and below: Need READ/WRITE_EXTERNAL_STORAGE + if (androidx.core.content.ContextCompat.checkSelfPermission( this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE @@ -176,7 +176,7 @@ class MainActivity : LoadingActivity() { } } catch (e: Exception) { Log.e(TAG, "Error opening storage settings: ${e.message}") - // Fallback: open general manage all files settings + try { val intent = Intent(android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) @@ -202,19 +202,16 @@ class MainActivity : LoadingActivity() { } } - /** - * Check and request VPN permission if needed. VpnService.prepare() must be called from an - * Activity before VPN can be established. - */ + private fun checkVpnPermission() { try { val vpnIntent = VpnService.prepare(this) if (vpnIntent != null) { - // User needs to grant VPN permission + Log.d(TAG, "VPN permission not granted, requesting...") vpnPermissionResult.launch(vpnIntent) } else { - // VPN permission already granted + Log.d(TAG, "VPN permission already granted") } } catch (e: Exception) { @@ -227,7 +224,7 @@ class MainActivity : LoadingActivity() { try { if (result.resultCode == RESULT_OK) { Log.d(TAG, "VPN permission granted!") - // VPN service will now be able to establish connection + } else { Log.w(TAG, "VPN permission denied by user") } @@ -252,7 +249,7 @@ class MainActivity : LoadingActivity() { private fun initToolbarSubTitle() { try { updateUserRemark(0) - // hack code + viewBinding.toolbarLayout.toolbar.getChildAt(1)?.setOnClickListener { try { MaterialDialog(this).show { @@ -421,7 +418,7 @@ class MainActivity : LoadingActivity() { startActivity(intent) } R.id.fake_location -> { - // toast("Still Developing") + val intent = Intent(this, FakeManagerActivity::class.java) intent.putExtra("userID", 0) startActivity(intent) diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/ShortcutActivity.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/ShortcutActivity.kt index 30c17d2..f72655a 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/ShortcutActivity.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/main/ShortcutActivity.kt @@ -6,12 +6,7 @@ import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.launch import top.niunaijun.blackbox.BlackBoxCore -/** - * - * @Description: 快捷方式跳转activity - * @Author: wukaicheng - * @CreateDate: 2022/2/11 23:13 - */ + class ShortcutActivity:AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/main/ViewPagerAdapter.kt b/app/src/main/java/top/niunaijun/blackboxa/view/main/ViewPagerAdapter.kt index 8d0d35a..1c27627 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/main/ViewPagerAdapter.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/main/ViewPagerAdapter.kt @@ -5,12 +5,7 @@ import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter import top.niunaijun.blackboxa.view.apps.AppsFragment -/** - * - * @Description: - * @Author: wukaicheng - * @CreateDate: 2021/4/29 22:00 - */ + class ViewPagerAdapter(appCompatActivity: AppCompatActivity) : FragmentStateAdapter(appCompatActivity) { diff --git a/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt b/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt index a12ab08..c0a2dc0 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/view/setting/SettingFragment.kt @@ -37,6 +37,13 @@ class SettingFragment : PreferenceFragmentCompat() { vpnPreference } + invalidHideState { + val disableFlagSecurePreference: Preference = (findPreference("disable_flag_secure")!!) + val mDisableFlagSecure = AppManager.mBlackBoxLoader.disableFlagSecure() + disableFlagSecurePreference.setDefaultValue(mDisableFlagSecure) + disableFlagSecurePreference + } + initSendLogs() } @@ -70,6 +77,9 @@ class SettingFragment : PreferenceFragmentCompat() { "use_vpn_network" -> { AppManager.mBlackBoxLoader.invalidUseVpnNetwork(tmpHide) } + "disable_flag_secure" -> { + AppManager.mBlackBoxLoader.invalidDisableFlagSecure(tmpHide) + } } toast(R.string.restart_module) @@ -79,7 +89,21 @@ class SettingFragment : PreferenceFragmentCompat() { private fun initSendLogs() { val sendLogsPreference: Preference? = findPreference("send_logs") sendLogsPreference?.setOnPreferenceClickListener { - BlackBoxCore.get().sendLogs("Manual Log Upload from Settings", true) + it.isEnabled = false + BlackBoxCore.get() + .sendLogs( + "Manual Log Upload from Settings", + true, + object : BlackBoxCore.LogSendListener { + override fun onSuccess() { + activity?.runOnUiThread { sendLogsPreference.isEnabled = true } + } + + override fun onFailure(error: String?) { + activity?.runOnUiThread { sendLogsPreference.isEnabled = true } + } + } + ) toast("Sending logs... (Check notifications for status)") true } diff --git a/app/src/main/java/top/niunaijun/blackboxa/widget/EnFloatView.kt b/app/src/main/java/top/niunaijun/blackboxa/widget/EnFloatView.kt index 4dafde9..60849d3 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/widget/EnFloatView.kt +++ b/app/src/main/java/top/niunaijun/blackboxa/widget/EnFloatView.kt @@ -5,12 +5,7 @@ import android.view.MotionEvent import com.imuxuan.floatingview.FloatingMagnetView import top.niunaijun.blackboxa.R -/** - * - * @Description: rocker parent - * @Author: kotlinMiku - * @CreateDate: 2022/3/20 16:58 - */ + class EnFloatView(mContext: Context) : FloatingMagnetView(mContext) { private val TAG = "RockerManager" @@ -31,7 +26,7 @@ class EnFloatView(mContext: Context) : FloatingMagnetView(mContext) { if (type == RockerView.EVENT_CLOCK && currentAngle != -1F) { val realAngle = currentAngle val realDistance = currentDistance * 0.001F - //拉满的话,大概就是一秒五米 + mListener?.invoke(realAngle, realDistance) diff --git a/app/src/main/java/top/niunaijun/blackboxa/widget/RockerView.java b/app/src/main/java/top/niunaijun/blackboxa/widget/RockerView.java index 0cc317b..1c37131 100644 --- a/app/src/main/java/top/niunaijun/blackboxa/widget/RockerView.java +++ b/app/src/main/java/top/niunaijun/blackboxa/widget/RockerView.java @@ -21,14 +21,7 @@ import androidx.annotation.NonNull; import top.niunaijun.blackboxa.util.MathUtil; -/** - * A custom view for game or others. - *

- * Author: GcsSloop - * Created Date: 16/5/24 - * Copyright (C) 2016 GcsSloop. - * GitHub: https://github.com/GcsSloop - */ + public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.Callback { private static final int DEFAULT_AREA_RADIUS = 100; @@ -48,19 +41,10 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C private Paint mPaint; - /** - * The rocker active area center position. - * usually, it is the center of this view. - */ + private Point mAreaPosition; - /** - * The Rocker position. - * usually, it as same asmAreaPosition . - * if this view touched, it will follow the touch position. - *

- * we get position information from this. - */ + private Point mRockerPosition; @@ -83,7 +67,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C private int mCallbackCycle = DEFAULT_CALLBACK_CYCLE; - /*Life Cycle***********************************************************************************/ + public RockerView(Context context) { this(context, null); @@ -96,20 +80,20 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C public RockerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - // init attrs + initAttrs(context, attrs); - // set paint + setPaint(); if (isInEditMode()) { return; } - // config surfaceView + configSurfaceView(); - // config surfaceHolder + configSurfaceHolder(); } @@ -127,16 +111,16 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C } private void configSurfaceView() { - setKeepScreenOn(true); // do not lock screen when surfaceView is running. - setFocusable(true); // make sure this surfaceView can get focus from keyboard. - setFocusableInTouchMode(true); // make sure this surfaceView can get focus from touch. - setZOrderOnTop(true); // make sure this surface is placed on top of the window + setKeepScreenOn(true); + setFocusable(true); + setFocusableInTouchMode(true); + setZOrderOnTop(true); } private void configSurfaceHolder() { mHolder = getHolder(); mHolder.addCallback(this); - mHolder.setFormat(PixelFormat.TRANSPARENT); //设置背景透明 + mHolder.setFormat(PixelFormat.TRANSPARENT); } @Override @@ -145,11 +129,11 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C int defaultWidth = (mAreaRadius + mRockerRadius) * 2; int defalutHeight = defaultWidth; - int widthsize = MeasureSpec.getSize(widthMeasureSpec); //取出宽度的确切数值 - int widthmode = MeasureSpec.getMode(widthMeasureSpec); //取出宽度的测量模式 + int widthsize = MeasureSpec.getSize(widthMeasureSpec); + int widthmode = MeasureSpec.getMode(widthMeasureSpec); - int heightsize = MeasureSpec.getSize(heightMeasureSpec); //取出高度的确切数值 - int heightmode = MeasureSpec.getMode(heightMeasureSpec); //取出高度的测量模式 + int heightsize = MeasureSpec.getSize(heightMeasureSpec); + int heightmode = MeasureSpec.getMode(heightMeasureSpec); if (widthmode == MeasureSpec.AT_MOST || widthmode == MeasureSpec.UNSPECIFIED || widthsize < 0) { measureWidth = defaultWidth; @@ -174,7 +158,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C mAreaPosition = new Point(w / 2, h / 2); mRockerPosition = new Point(mAreaPosition); - // this need subtract the view padding + int tempRadius = Math.min(w - getPaddingLeft() - getPaddingRight(), h - getPaddingTop() - getPaddingBottom()); tempRadius /= 2; if (mAreaRadius == -1) @@ -192,7 +176,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C mCallbackThread = new Thread(() -> { while (mCallbackOk) { - // listener callback + listenerCallback(); try { @@ -231,7 +215,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C } } - /*Event Response*******************************************************************************/ + @Override public boolean onTouchEvent(MotionEvent event) { @@ -239,7 +223,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C int len = MathUtil.getDistance(mAreaPosition.x, mAreaPosition.y, event.getX(), event.getY()); if (event.getAction() == MotionEvent.ACTION_DOWN) { - //如果屏幕接触点不在摇杆挥动范围内,则不处理 + if (len > mAreaRadius) { return true; } @@ -247,11 +231,11 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C if (event.getAction() == MotionEvent.ACTION_MOVE) { if (len <= mAreaRadius) { - //如果手指在摇杆活动范围内,则摇杆处于手指触摸位置 + mRockerPosition.set((int) event.getX(), (int) event.getY()); } else { - //设置摇杆位置,使其处于手指触摸方向的 摇杆活动范围边缘 + mRockerPosition = MathUtil.getPointByCutLength(mAreaPosition, new Point((int) event.getX(), (int) event.getY()), mAreaRadius); } @@ -262,7 +246,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C mListener.callback(EVENT_ACTION, angle, distance); } } - //如果手指离开屏幕,则摇杆返回初始位置 + if (event.getAction() == MotionEvent.ACTION_UP) { mRockerPosition = new Point(mAreaPosition); if (mListener != null) { @@ -276,7 +260,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C } - /*Thread - draw view***************************************************************************/ + @Override public void run() { @@ -296,7 +280,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C drawArea(canvas); drawRocker(canvas); } - Thread.sleep(mRefreshCycle); // 休眠 + Thread.sleep(mRefreshCycle); } catch (Exception e) { e.printStackTrace(); @@ -354,12 +338,12 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C } } - //获取摇杆偏移角度 上方中间为0,左为负,右为正 + private float getAngleConvert(float radian) { return 90 + Math.round(radian / Math.PI * 180); } - // for preview + @Override protected void onDraw(Canvas canvas) { if (isInEditMode()) { @@ -369,7 +353,7 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C } } - /*Getter Setter********************************************************************************/ + public void setCanMove(boolean isMove) { this.canMove = isMove; @@ -445,20 +429,12 @@ public class RockerView extends SurfaceView implements Runnable, SurfaceHolder.C mListener = listener; } - /*Rocker Listener******************************************************************************/ + - /** - * rocker listener - */ + public interface RockerListener { - /** - * you can get some event from this method - * - * @param eventType The event type, EVENT_ACTION or EVENT_CLOCK - * @param currentAngle The current angle - * @param currentDistance The current distance (px) - */ + void callback(int eventType, float currentAngle, float currentDistance); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3abb270..7dc6d8a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,6 +58,8 @@ Daemon Use VPN Network Route traffic through VPN for sandboxed apps (may improve network access) + Disable Flag Secure + Allow screenshots and screen recording in apps GMS Manager Go to Gms Manager Enable Service diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 35a4e4c..4a7335f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,17 +1,17 @@ - +