Showing preview only (3,772K chars total). Download the full file or copy to clipboard to get everything.
Repository: topjohnwu/Magisk
Branch: master
Commit: 9035a9480440
Files: 740
Total size: 3.4 MB
Directory structure:
gitextract_zn19wufn/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── config.yml
│ ├── actions/
│ │ └── setup/
│ │ ├── action.yml
│ │ └── sccache.sh
│ ├── ci.prop
│ ├── kvm.sh
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.MD
├── app/
│ ├── .gitignore
│ ├── apk/
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── arch/
│ │ │ │ ├── AsyncLoadViewModel.kt
│ │ │ │ ├── BaseFragment.kt
│ │ │ │ ├── BaseViewModel.kt
│ │ │ │ ├── NavigationActivity.kt
│ │ │ │ ├── UIActivity.kt
│ │ │ │ ├── ViewEvent.kt
│ │ │ │ └── ViewModelHolder.kt
│ │ │ ├── databinding/
│ │ │ │ ├── DataBindingAdapters.kt
│ │ │ │ ├── DiffObservableList.kt
│ │ │ │ ├── MergeObservableList.kt
│ │ │ │ ├── ObservableHost.kt
│ │ │ │ ├── RecyclerViewItems.kt
│ │ │ │ └── RvItemAdapter.kt
│ │ │ ├── dialog/
│ │ │ │ ├── DarkThemeDialog.kt
│ │ │ │ ├── EnvFixDialog.kt
│ │ │ │ ├── LocalModuleInstallDialog.kt
│ │ │ │ ├── ManagerInstallDialog.kt
│ │ │ │ ├── MarkDownDialog.kt
│ │ │ │ ├── OnlineModuleInstallDialog.kt
│ │ │ │ ├── SecondSlotWarningDialog.kt
│ │ │ │ ├── SuperuserRevokeDialog.kt
│ │ │ │ └── UninstallDialog.kt
│ │ │ ├── events/
│ │ │ │ └── ViewEvents.kt
│ │ │ ├── ui/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── deny/
│ │ │ │ │ ├── AppProcessInfo.kt
│ │ │ │ │ ├── DenyListFragment.kt
│ │ │ │ │ ├── DenyListRvItem.kt
│ │ │ │ │ └── DenyListViewModel.kt
│ │ │ │ ├── flash/
│ │ │ │ │ ├── ConsoleItem.kt
│ │ │ │ │ ├── FlashFragment.kt
│ │ │ │ │ └── FlashViewModel.kt
│ │ │ │ ├── home/
│ │ │ │ │ ├── DeveloperItem.kt
│ │ │ │ │ ├── HomeFragment.kt
│ │ │ │ │ ├── HomeViewModel.kt
│ │ │ │ │ └── RebootMenu.kt
│ │ │ │ ├── install/
│ │ │ │ │ ├── InstallFragment.kt
│ │ │ │ │ └── InstallViewModel.kt
│ │ │ │ ├── log/
│ │ │ │ │ ├── LogFragment.kt
│ │ │ │ │ ├── LogRvItem.kt
│ │ │ │ │ ├── LogViewModel.kt
│ │ │ │ │ └── SuLogRvItem.kt
│ │ │ │ ├── module/
│ │ │ │ │ ├── ActionFragment.kt
│ │ │ │ │ ├── ActionViewModel.kt
│ │ │ │ │ ├── ModuleFragment.kt
│ │ │ │ │ ├── ModuleRvItem.kt
│ │ │ │ │ └── ModuleViewModel.kt
│ │ │ │ ├── settings/
│ │ │ │ │ ├── BaseSettingsItem.kt
│ │ │ │ │ ├── SettingsFragment.kt
│ │ │ │ │ ├── SettingsItems.kt
│ │ │ │ │ └── SettingsViewModel.kt
│ │ │ │ ├── superuser/
│ │ │ │ │ ├── PolicyRvItem.kt
│ │ │ │ │ ├── SuperuserFragment.kt
│ │ │ │ │ └── SuperuserViewModel.kt
│ │ │ │ ├── surequest/
│ │ │ │ │ ├── SuRequestActivity.kt
│ │ │ │ │ └── SuRequestViewModel.kt
│ │ │ │ └── theme/
│ │ │ │ ├── Theme.kt
│ │ │ │ ├── ThemeFragment.kt
│ │ │ │ └── ThemeViewModel.kt
│ │ │ ├── utils/
│ │ │ │ ├── AccessibilityUtils.kt
│ │ │ │ ├── MotionRevealHelper.kt
│ │ │ │ └── TextHolder.kt
│ │ │ ├── view/
│ │ │ │ ├── MagiskDialog.kt
│ │ │ │ ├── TappableHeadlineItem.kt
│ │ │ │ └── TextItem.kt
│ │ │ └── widget/
│ │ │ └── ConcealableBottomNavigationView.java
│ │ └── res/
│ │ ├── anim/
│ │ │ ├── fragment_enter.xml
│ │ │ ├── fragment_enter_pop.xml
│ │ │ ├── fragment_exit.xml
│ │ │ └── fragment_exit_pop.xml
│ │ ├── color/
│ │ │ ├── color_card_background_color_selector.xml
│ │ │ ├── color_error_transient.xml
│ │ │ ├── color_menu_tint.xml
│ │ │ ├── color_on_primary_transient.xml
│ │ │ ├── color_primary_error_transient.xml
│ │ │ ├── color_primary_transient.xml
│ │ │ ├── color_state_primary_transient.xml
│ │ │ └── color_text_transient.xml
│ │ ├── drawable/
│ │ │ ├── avd_bug_from_filled.xml
│ │ │ ├── avd_bug_to_filled.xml
│ │ │ ├── avd_circle_check_from_filled.xml
│ │ │ ├── avd_circle_check_to_filled.xml
│ │ │ ├── avd_home_from_filled.xml
│ │ │ ├── avd_home_to_filled.xml
│ │ │ ├── avd_module_from_filled.xml
│ │ │ ├── avd_module_to_filled.xml
│ │ │ ├── avd_settings_from_filled.xml
│ │ │ ├── avd_settings_to_filled.xml
│ │ │ ├── avd_superuser_from_filled.xml
│ │ │ ├── avd_superuser_to_filled.xml
│ │ │ ├── bg_line_bottom_rounded.xml
│ │ │ ├── bg_line_top_rounded.xml
│ │ │ ├── bg_selection_circle_green.xml
│ │ │ ├── ic_action_md2.xml
│ │ │ ├── ic_back_md2.xml
│ │ │ ├── ic_bug_filled_md2.xml
│ │ │ ├── ic_bug_md2.xml
│ │ │ ├── ic_bug_outlined_md2.xml
│ │ │ ├── ic_check_circle_checked_md2.xml
│ │ │ ├── ic_check_circle_md2.xml
│ │ │ ├── ic_check_circle_unchecked_md2.xml
│ │ │ ├── ic_check_md2.xml
│ │ │ ├── ic_close_md2.xml
│ │ │ ├── ic_day.xml
│ │ │ ├── ic_day_night.xml
│ │ │ ├── ic_delete_md2.xml
│ │ │ ├── ic_download_md2.xml
│ │ │ ├── ic_folder_list.xml
│ │ │ ├── ic_forth_md2.xml
│ │ │ ├── ic_home_filled_md2.xml
│ │ │ ├── ic_home_md2.xml
│ │ │ ├── ic_home_outlined_md2.xml
│ │ │ ├── ic_install.xml
│ │ │ ├── ic_manager.xml
│ │ │ ├── ic_module_filled_md2.xml
│ │ │ ├── ic_module_md2.xml
│ │ │ ├── ic_module_outlined_md2.xml
│ │ │ ├── ic_module_storage_md2.xml
│ │ │ ├── ic_night.xml
│ │ │ ├── ic_notifications_md2.xml
│ │ │ ├── ic_paint.xml
│ │ │ ├── ic_restart.xml
│ │ │ ├── ic_save_md2.xml
│ │ │ ├── ic_search_md2.xml
│ │ │ ├── ic_settings_filled_md2.xml
│ │ │ ├── ic_settings_md2.xml
│ │ │ ├── ic_settings_outlined_md2.xml
│ │ │ ├── ic_superuser_filled_md2.xml
│ │ │ ├── ic_superuser_md2.xml
│ │ │ ├── ic_superuser_outlined_md2.xml
│ │ │ └── ic_update_md2.xml
│ │ ├── layout/
│ │ │ ├── activity_main_md2.xml
│ │ │ ├── activity_request.xml
│ │ │ ├── dialog_magisk_base.xml
│ │ │ ├── dialog_settings_app_name.xml
│ │ │ ├── dialog_settings_download_path.xml
│ │ │ ├── dialog_settings_update_channel.xml
│ │ │ ├── fragment_action_md2.xml
│ │ │ ├── fragment_deny_md2.xml
│ │ │ ├── fragment_flash_md2.xml
│ │ │ ├── fragment_home_md2.xml
│ │ │ ├── fragment_install_md2.xml
│ │ │ ├── fragment_log_md2.xml
│ │ │ ├── fragment_module_md2.xml
│ │ │ ├── fragment_settings_md2.xml
│ │ │ ├── fragment_superuser_md2.xml
│ │ │ ├── fragment_theme_md2.xml
│ │ │ ├── include_home_magisk.xml
│ │ │ ├── include_home_manager.xml
│ │ │ ├── include_log_magisk.xml
│ │ │ ├── include_log_superuser.xml
│ │ │ ├── item_console_md2.xml
│ │ │ ├── item_developer.xml
│ │ │ ├── item_hide_md2.xml
│ │ │ ├── item_hide_process_md2.xml
│ │ │ ├── item_icon_link.xml
│ │ │ ├── item_list_single_line.xml
│ │ │ ├── item_log_access_md2.xml
│ │ │ ├── item_log_textview.xml
│ │ │ ├── item_log_track_md2.xml
│ │ │ ├── item_module_download.xml
│ │ │ ├── item_module_md2.xml
│ │ │ ├── item_policy_md2.xml
│ │ │ ├── item_settings.xml
│ │ │ ├── item_settings_section.xml
│ │ │ ├── item_spinner.xml
│ │ │ ├── item_tappable_headline.xml
│ │ │ ├── item_text.xml
│ │ │ ├── item_theme.xml
│ │ │ ├── item_theme_container.xml
│ │ │ └── markdown_window_md2.xml
│ │ ├── menu/
│ │ │ ├── menu_bottom_nav.xml
│ │ │ ├── menu_deny_md2.xml
│ │ │ ├── menu_flash.xml
│ │ │ ├── menu_home_md2.xml
│ │ │ ├── menu_log_md2.xml
│ │ │ └── menu_reboot.xml
│ │ ├── navigation/
│ │ │ └── main.xml
│ │ ├── values/
│ │ │ ├── attrs.xml
│ │ │ ├── dimens.xml
│ │ │ ├── ids.xml
│ │ │ ├── styles_md2.xml
│ │ │ ├── styles_md2_appearance.xml
│ │ │ ├── styles_md2_impl.xml
│ │ │ ├── styles_view_md2.xml
│ │ │ ├── theme_overlay.xml
│ │ │ ├── themes.xml
│ │ │ ├── themes_md2.xml
│ │ │ └── themes_override.xml
│ │ ├── values-night/
│ │ │ ├── styles_md2.xml
│ │ │ └── themes_md2.xml
│ │ └── values-v27/
│ │ └── themes.xml
│ ├── apk-ng/
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── arch/
│ │ │ │ ├── AsyncLoadViewModel.kt
│ │ │ │ ├── BaseViewModel.kt
│ │ │ │ └── ViewModelFactory.kt
│ │ │ ├── terminal/
│ │ │ │ ├── TerminalBuffer.kt
│ │ │ │ ├── TerminalEmulator.kt
│ │ │ │ ├── TerminalProcess.kt
│ │ │ │ ├── TerminalRow.kt
│ │ │ │ ├── TerminalStyle.kt
│ │ │ │ └── WcWidth.kt
│ │ │ ├── ui/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── MainScreen.kt
│ │ │ │ ├── component/
│ │ │ │ │ ├── Dialog.kt
│ │ │ │ │ └── MenuPositionProvider.kt
│ │ │ │ ├── deny/
│ │ │ │ │ ├── AppProcessInfo.kt
│ │ │ │ │ ├── DenyListScreen.kt
│ │ │ │ │ └── DenyListViewModel.kt
│ │ │ │ ├── flash/
│ │ │ │ │ ├── FlashScreen.kt
│ │ │ │ │ ├── FlashUtils.kt
│ │ │ │ │ └── FlashViewModel.kt
│ │ │ │ ├── home/
│ │ │ │ │ ├── HomeScreen.kt
│ │ │ │ │ └── HomeViewModel.kt
│ │ │ │ ├── install/
│ │ │ │ │ └── InstallViewModel.kt
│ │ │ │ ├── log/
│ │ │ │ │ ├── LogScreen.kt
│ │ │ │ │ ├── LogViewModel.kt
│ │ │ │ │ └── MagiskLogParser.kt
│ │ │ │ ├── module/
│ │ │ │ │ ├── ActionScreen.kt
│ │ │ │ │ ├── ActionViewModel.kt
│ │ │ │ │ ├── ModuleScreen.kt
│ │ │ │ │ └── ModuleViewModel.kt
│ │ │ │ ├── navigation/
│ │ │ │ │ ├── CollectNavEvents.kt
│ │ │ │ │ ├── Navigator.kt
│ │ │ │ │ └── Routes.kt
│ │ │ │ ├── settings/
│ │ │ │ │ ├── SettingsScreen.kt
│ │ │ │ │ └── SettingsViewModel.kt
│ │ │ │ ├── superuser/
│ │ │ │ │ ├── SuperuserDetailScreen.kt
│ │ │ │ │ ├── SuperuserScreen.kt
│ │ │ │ │ └── SuperuserViewModel.kt
│ │ │ │ ├── surequest/
│ │ │ │ │ ├── SuRequestActivity.kt
│ │ │ │ │ ├── SuRequestScreen.kt
│ │ │ │ │ └── SuRequestViewModel.kt
│ │ │ │ ├── terminal/
│ │ │ │ │ ├── TerminalRenderer.kt
│ │ │ │ │ └── TerminalScreen.kt
│ │ │ │ ├── theme/
│ │ │ │ │ ├── MagiskTheme.kt
│ │ │ │ │ └── Theme.kt
│ │ │ │ └── util/
│ │ │ │ └── DrawablePainter.kt
│ │ │ └── utils/
│ │ │ └── AccessibilityUtils.kt
│ │ └── res/
│ │ ├── color/
│ │ │ ├── color_card_background_color_selector.xml
│ │ │ ├── color_error_transient.xml
│ │ │ ├── color_menu_tint.xml
│ │ │ ├── color_on_primary_transient.xml
│ │ │ ├── color_primary_error_transient.xml
│ │ │ ├── color_primary_transient.xml
│ │ │ ├── color_state_primary_transient.xml
│ │ │ └── color_text_transient.xml
│ │ ├── drawable/
│ │ │ ├── avd_bug_from_filled.xml
│ │ │ ├── avd_bug_to_filled.xml
│ │ │ ├── avd_circle_check_from_filled.xml
│ │ │ ├── avd_circle_check_to_filled.xml
│ │ │ ├── avd_home_from_filled.xml
│ │ │ ├── avd_home_to_filled.xml
│ │ │ ├── avd_module_from_filled.xml
│ │ │ ├── avd_module_to_filled.xml
│ │ │ ├── avd_settings_from_filled.xml
│ │ │ ├── avd_settings_to_filled.xml
│ │ │ ├── avd_superuser_from_filled.xml
│ │ │ ├── avd_superuser_to_filled.xml
│ │ │ ├── ic_bug_filled_md2.xml
│ │ │ ├── ic_bug_md2.xml
│ │ │ ├── ic_bug_outlined_md2.xml
│ │ │ ├── ic_check_circle_checked_md2.xml
│ │ │ ├── ic_check_circle_md2.xml
│ │ │ ├── ic_check_circle_unchecked_md2.xml
│ │ │ ├── ic_check_md2.xml
│ │ │ ├── ic_delete_md2.xml
│ │ │ ├── ic_download_md2.xml
│ │ │ ├── ic_home_filled_md2.xml
│ │ │ ├── ic_home_md2.xml
│ │ │ ├── ic_home_outlined_md2.xml
│ │ │ ├── ic_install.xml
│ │ │ ├── ic_manager.xml
│ │ │ ├── ic_module_filled_md2.xml
│ │ │ ├── ic_module_md2.xml
│ │ │ ├── ic_module_outlined_md2.xml
│ │ │ ├── ic_module_storage_md2.xml
│ │ │ ├── ic_notifications_md2.xml
│ │ │ ├── ic_restart.xml
│ │ │ ├── ic_save_md2.xml
│ │ │ ├── ic_search_md2.xml
│ │ │ ├── ic_settings_filled_md2.xml
│ │ │ ├── ic_settings_md2.xml
│ │ │ ├── ic_settings_outlined_md2.xml
│ │ │ ├── ic_superuser_filled_md2.xml
│ │ │ ├── ic_superuser_md2.xml
│ │ │ ├── ic_superuser_outlined_md2.xml
│ │ │ └── ic_update_md2.xml
│ │ ├── values/
│ │ │ ├── attrs.xml
│ │ │ ├── dimens.xml
│ │ │ ├── styles_md2.xml
│ │ │ ├── styles_md2_appearance.xml
│ │ │ ├── styles_md2_impl.xml
│ │ │ ├── themes.xml
│ │ │ ├── themes_md2.xml
│ │ │ └── themes_override.xml
│ │ ├── values-night/
│ │ │ ├── styles_md2.xml
│ │ │ └── themes_md2.xml
│ │ └── values-v27/
│ │ └── themes.xml
│ ├── build.gradle.kts
│ ├── buildSrc/
│ │ ├── build.gradle.kts
│ │ ├── settings.gradle.kts
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ ├── AddCommentTask.kt
│ │ ├── DesugarClassVisitorFactory.kt
│ │ ├── Plugin.kt
│ │ ├── Setup.kt
│ │ └── Stub.kt
│ ├── core/
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── aidl/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ └── core/
│ │ │ └── utils/
│ │ │ └── IRootUtils.aidl
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── core/
│ │ │ │ ├── App.kt
│ │ │ │ ├── AppContext.kt
│ │ │ │ ├── Config.kt
│ │ │ │ ├── Const.kt
│ │ │ │ ├── Hacks.kt
│ │ │ │ ├── Info.kt
│ │ │ │ ├── JobService.kt
│ │ │ │ ├── Provider.kt
│ │ │ │ ├── Receiver.kt
│ │ │ │ ├── Service.kt
│ │ │ │ ├── base/
│ │ │ │ │ ├── BaseActivity.kt
│ │ │ │ │ ├── BaseJobService.kt
│ │ │ │ │ ├── BaseProvider.kt
│ │ │ │ │ ├── BaseReceiver.kt
│ │ │ │ │ ├── BaseService.kt
│ │ │ │ │ └── SplashScreen.kt
│ │ │ │ ├── data/
│ │ │ │ │ ├── RetrofitInterfaces.kt
│ │ │ │ │ ├── SuLogDao.kt
│ │ │ │ │ └── magiskdb/
│ │ │ │ │ ├── MagiskDB.kt
│ │ │ │ │ ├── PolicyDao.kt
│ │ │ │ │ ├── SettingsDao.kt
│ │ │ │ │ └── StringDao.kt
│ │ │ │ ├── di/
│ │ │ │ │ ├── Networking.kt
│ │ │ │ │ └── ServiceLocator.kt
│ │ │ │ ├── download/
│ │ │ │ │ ├── DownloadEngine.kt
│ │ │ │ │ ├── DownloadProcessor.kt
│ │ │ │ │ ├── Interfaces.kt
│ │ │ │ │ └── Subject.kt
│ │ │ │ ├── ktx/
│ │ │ │ │ ├── XAndroid.kt
│ │ │ │ │ ├── XJVM.kt
│ │ │ │ │ └── XSU.kt
│ │ │ │ ├── model/
│ │ │ │ │ ├── UpdateInfo.kt
│ │ │ │ │ ├── module/
│ │ │ │ │ │ ├── LocalModule.kt
│ │ │ │ │ │ ├── Module.kt
│ │ │ │ │ │ └── OnlineModule.kt
│ │ │ │ │ └── su/
│ │ │ │ │ ├── SuLog.kt
│ │ │ │ │ └── SuPolicy.kt
│ │ │ │ ├── repository/
│ │ │ │ │ ├── DBConfig.kt
│ │ │ │ │ ├── LogRepository.kt
│ │ │ │ │ ├── NetworkService.kt
│ │ │ │ │ └── PreferenceConfig.kt
│ │ │ │ ├── signing/
│ │ │ │ │ ├── ApkSignerV2.java
│ │ │ │ │ ├── ByteArrayStream.java
│ │ │ │ │ ├── JarMap.java
│ │ │ │ │ ├── SignApk.java
│ │ │ │ │ └── ZipUtils.java
│ │ │ │ ├── su/
│ │ │ │ │ ├── SuCallbackHandler.kt
│ │ │ │ │ ├── SuEvents.kt
│ │ │ │ │ └── SuRequestHandler.kt
│ │ │ │ ├── tasks/
│ │ │ │ │ ├── AppMigration.kt
│ │ │ │ │ ├── FlashZip.kt
│ │ │ │ │ └── MagiskInstaller.kt
│ │ │ │ ├── utils/
│ │ │ │ │ ├── AXML.kt
│ │ │ │ │ ├── Desugar.java
│ │ │ │ │ ├── DummyList.kt
│ │ │ │ │ ├── Keygen.kt
│ │ │ │ │ ├── LocaleSetting.kt
│ │ │ │ │ ├── MediaStoreUtils.kt
│ │ │ │ │ ├── NetworkObserver.kt
│ │ │ │ │ ├── ProgressInputStream.kt
│ │ │ │ │ ├── RequestAuthentication.kt
│ │ │ │ │ ├── RequestInstall.kt
│ │ │ │ │ ├── RootUtils.kt
│ │ │ │ │ └── ShellInit.kt
│ │ │ │ └── view/
│ │ │ │ ├── Notifications.kt
│ │ │ │ └── Shortcuts.kt
│ │ │ └── test/
│ │ │ ├── AdditionalTest.kt
│ │ │ ├── BaseTest.kt
│ │ │ ├── Environment.kt
│ │ │ └── MagiskAppTest.kt
│ │ └── res/
│ │ ├── drawable/
│ │ │ ├── ic_extension.xml
│ │ │ ├── ic_favorite.xml
│ │ │ ├── ic_fingerprint.xml
│ │ │ ├── ic_github.xml
│ │ │ ├── ic_logo.xml
│ │ │ ├── ic_magisk.xml
│ │ │ ├── ic_magisk_outline.xml
│ │ │ ├── ic_magisk_padded.xml
│ │ │ ├── ic_more.xml
│ │ │ ├── ic_patreon.xml
│ │ │ ├── ic_paypal.xml
│ │ │ ├── ic_superuser.xml
│ │ │ ├── ic_twitter.xml
│ │ │ ├── sc_extension.xml
│ │ │ └── sc_superuser.xml
│ │ ├── drawable-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ ├── sc_extension.xml
│ │ │ └── sc_superuser.xml
│ │ ├── values/
│ │ │ ├── arrays.xml
│ │ │ ├── colors.xml
│ │ │ ├── resources.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ ├── values-ar/
│ │ │ └── strings.xml
│ │ ├── values-ast/
│ │ │ └── strings.xml
│ │ ├── values-az/
│ │ │ └── strings.xml
│ │ ├── values-b+sr+Latn/
│ │ │ └── strings.xml
│ │ ├── values-be/
│ │ │ └── strings.xml
│ │ ├── values-bg/
│ │ │ └── strings.xml
│ │ ├── values-bn/
│ │ │ └── strings.xml
│ │ ├── values-ca/
│ │ │ └── strings.xml
│ │ ├── values-cs/
│ │ │ └── strings.xml
│ │ ├── values-de/
│ │ │ └── strings.xml
│ │ ├── values-el/
│ │ │ └── strings.xml
│ │ ├── values-es/
│ │ │ └── strings.xml
│ │ ├── values-et/
│ │ │ └── strings.xml
│ │ ├── values-fa/
│ │ │ └── strings.xml
│ │ ├── values-fr/
│ │ │ └── strings.xml
│ │ ├── values-hi/
│ │ │ └── strings.xml
│ │ ├── values-hn/
│ │ │ └── strings.xml
│ │ ├── values-hr/
│ │ │ └── strings.xml
│ │ ├── values-hu/
│ │ │ └── strings.xml
│ │ ├── values-in/
│ │ │ └── strings.xml
│ │ ├── values-it/
│ │ │ └── strings.xml
│ │ ├── values-iw/
│ │ │ └── strings.xml
│ │ ├── values-ja/
│ │ │ └── strings.xml
│ │ ├── values-ka/
│ │ │ └── strings.xml
│ │ ├── values-kk/
│ │ │ └── strings.xml
│ │ ├── values-ko/
│ │ │ └── strings.xml
│ │ ├── values-ku/
│ │ │ └── strings.xml
│ │ ├── values-lt/
│ │ │ └── strings.xml
│ │ ├── values-mk/
│ │ │ └── strings.xml
│ │ ├── values-ml/
│ │ │ └── strings.xml
│ │ ├── values-nb/
│ │ │ └── strings.xml
│ │ ├── values-night/
│ │ │ └── colors.xml
│ │ ├── values-nl/
│ │ │ └── strings.xml
│ │ ├── values-pa/
│ │ │ └── strings.xml
│ │ ├── values-pl/
│ │ │ └── strings.xml
│ │ ├── values-pt-rBR/
│ │ │ └── strings.xml
│ │ ├── values-pt-rPT/
│ │ │ └── strings.xml
│ │ ├── values-ro/
│ │ │ └── strings.xml
│ │ ├── values-ru/
│ │ │ └── strings.xml
│ │ ├── values-sk/
│ │ │ └── strings.xml
│ │ ├── values-sq/
│ │ │ └── strings.xml
│ │ ├── values-sr/
│ │ │ └── strings.xml
│ │ ├── values-sv/
│ │ │ └── strings.xml
│ │ ├── values-sw/
│ │ │ └── strings.xml
│ │ ├── values-ta/
│ │ │ └── strings.xml
│ │ ├── values-th/
│ │ │ └── strings.xml
│ │ ├── values-tr/
│ │ │ └── strings.xml
│ │ ├── values-uk/
│ │ │ └── strings.xml
│ │ ├── values-ur/
│ │ │ └── strings.xml
│ │ ├── values-v31/
│ │ │ └── themes.xml
│ │ ├── values-v34/
│ │ │ └── resources.xml
│ │ ├── values-vi/
│ │ │ └── strings.xml
│ │ ├── values-zh-rCN/
│ │ │ └── strings.xml
│ │ ├── values-zh-rTW/
│ │ │ └── strings.xml
│ │ └── xml/
│ │ └── locale_config.xml
│ ├── gradle/
│ │ ├── libs.versions.toml
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── settings.gradle.kts
│ ├── shared/
│ │ ├── build.gradle.kts
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ └── java/
│ │ └── com/
│ │ └── topjohnwu/
│ │ └── magisk/
│ │ ├── ProviderInstaller.java
│ │ ├── StubApk.java
│ │ └── utils/
│ │ ├── APKInstall.java
│ │ ├── CompoundEnumeration.java
│ │ └── DynamicClassLoader.java
│ ├── stub/
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── ClassLoaders.java
│ │ │ ├── DelegateComponentFactory.java
│ │ │ ├── DownloadActivity.java
│ │ │ ├── DynLoad.java
│ │ │ ├── StubApplication.java
│ │ │ ├── StubRootService.java
│ │ │ ├── dummy/
│ │ │ │ ├── DummyProvider.java
│ │ │ │ ├── DummyReceiver.java
│ │ │ │ └── DummyService.java
│ │ │ └── net/
│ │ │ ├── BadRequest.java
│ │ │ ├── ErrorHandler.java
│ │ │ ├── Networking.java
│ │ │ ├── Request.java
│ │ │ └── ResponseListener.java
│ │ └── res/
│ │ ├── values/
│ │ │ └── strings.xml
│ │ ├── values-ar/
│ │ │ └── strings.xml
│ │ ├── values-ast/
│ │ │ └── strings.xml
│ │ ├── values-az/
│ │ │ └── strings.xml
│ │ ├── values-b+sr+Latn/
│ │ │ └── strings.xml
│ │ ├── values-be/
│ │ │ └── strings.xml
│ │ ├── values-bg/
│ │ │ └── strings.xml
│ │ ├── values-ca/
│ │ │ └── strings.xml
│ │ ├── values-cs/
│ │ │ └── strings.xml
│ │ ├── values-de/
│ │ │ └── strings.xml
│ │ ├── values-el/
│ │ │ └── strings.xml
│ │ ├── values-es/
│ │ │ └── strings.xml
│ │ ├── values-et/
│ │ │ └── strings.xml
│ │ ├── values-fa/
│ │ │ └── strings.xml
│ │ ├── values-fr/
│ │ │ └── strings.xml
│ │ ├── values-hi/
│ │ │ └── strings.xml
│ │ ├── values-hn/
│ │ │ └── strings.xml
│ │ ├── values-hr/
│ │ │ └── strings.xml
│ │ ├── values-hu/
│ │ │ └── strings.xml
│ │ ├── values-in/
│ │ │ └── strings.xml
│ │ ├── values-it/
│ │ │ └── strings.xml
│ │ ├── values-iw/
│ │ │ └── strings.xml
│ │ ├── values-ja/
│ │ │ └── strings.xml
│ │ ├── values-ka/
│ │ │ └── strings.xml
│ │ ├── values-kk/
│ │ │ └── strings.xml
│ │ ├── values-ko/
│ │ │ └── strings.xml
│ │ ├── values-ku/
│ │ │ └── strings.xml
│ │ ├── values-lt/
│ │ │ └── strings.xml
│ │ ├── values-mk/
│ │ │ └── strings.xml
│ │ ├── values-ml/
│ │ │ └── strings.xml
│ │ ├── values-nb/
│ │ │ └── strings.xml
│ │ ├── values-nl/
│ │ │ └── strings.xml
│ │ ├── values-pa/
│ │ │ └── strings.xml
│ │ ├── values-pl/
│ │ │ └── strings.xml
│ │ ├── values-pt-rBR/
│ │ │ └── strings.xml
│ │ ├── values-pt-rPT/
│ │ │ └── strings.xml
│ │ ├── values-ro/
│ │ │ └── strings.xml
│ │ ├── values-ru/
│ │ │ └── strings.xml
│ │ ├── values-sk/
│ │ │ └── strings.xml
│ │ ├── values-sq/
│ │ │ └── strings.xml
│ │ ├── values-sr/
│ │ │ └── strings.xml
│ │ ├── values-sv/
│ │ │ └── strings.xml
│ │ ├── values-sw/
│ │ │ └── strings.xml
│ │ ├── values-ta/
│ │ │ └── strings.xml
│ │ ├── values-th/
│ │ │ └── strings.xml
│ │ ├── values-tr/
│ │ │ └── strings.xml
│ │ ├── values-uk/
│ │ │ └── strings.xml
│ │ ├── values-vi/
│ │ │ └── strings.xml
│ │ ├── values-zh-rCN/
│ │ │ └── strings.xml
│ │ └── values-zh-rTW/
│ │ └── strings.xml
│ └── test/
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ └── java/
│ └── com/
│ └── topjohnwu/
│ └── magisk/
│ └── test/
│ ├── AppMigrationTest.kt
│ └── Runners.kt
├── build.py
├── config.prop.sample
├── docs/
│ ├── README.md
│ ├── app_changes.md
│ ├── boot.md
│ ├── build.md
│ ├── changes.md
│ ├── details.md
│ ├── faq.md
│ ├── guides.md
│ ├── install.md
│ ├── ota.md
│ └── tools.md
├── native/
│ ├── .gitignore
│ └── src/
│ ├── .cargo/
│ │ └── config.toml
│ ├── Android-rs.mk
│ ├── Android.mk
│ ├── Application.mk
│ ├── Cargo.toml
│ ├── base/
│ │ ├── Android.mk
│ │ ├── Cargo.toml
│ │ ├── argh.rs
│ │ ├── base.cpp
│ │ ├── build.rs
│ │ ├── cstr.rs
│ │ ├── cxx_extern.rs
│ │ ├── derive/
│ │ │ ├── Cargo.toml
│ │ │ ├── argh/
│ │ │ │ ├── errors.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── parse_attrs.rs
│ │ │ ├── decodable.rs
│ │ │ └── lib.rs
│ │ ├── dir.rs
│ │ ├── files.rs
│ │ ├── include/
│ │ │ └── base.hpp
│ │ ├── lib.rs
│ │ ├── logging.rs
│ │ ├── misc.rs
│ │ ├── mount.rs
│ │ ├── result.rs
│ │ └── xwrap.rs
│ ├── boot/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── bootimg.cpp
│ │ ├── bootimg.hpp
│ │ ├── build.rs
│ │ ├── cli.rs
│ │ ├── compress.rs
│ │ ├── cpio.rs
│ │ ├── dtb.rs
│ │ ├── format.rs
│ │ ├── lib.rs
│ │ ├── magiskboot.hpp
│ │ ├── patch.rs
│ │ ├── payload.rs
│ │ ├── proto/
│ │ │ └── update_metadata.proto
│ │ └── sign.rs
│ ├── core/
│ │ ├── Cargo.toml
│ │ ├── applet_stub.cpp
│ │ ├── applets.cpp
│ │ ├── bootstages.rs
│ │ ├── build.rs
│ │ ├── daemon.rs
│ │ ├── db.rs
│ │ ├── deny/
│ │ │ ├── cli.cpp
│ │ │ ├── deny.hpp
│ │ │ ├── logcat.cpp
│ │ │ └── utils.cpp
│ │ ├── include/
│ │ │ ├── core.hpp
│ │ │ └── sqlite.hpp
│ │ ├── lib.rs
│ │ ├── logging.rs
│ │ ├── magisk.rs
│ │ ├── module.rs
│ │ ├── mount.rs
│ │ ├── package.rs
│ │ ├── resetprop/
│ │ │ ├── .gitignore
│ │ │ ├── cli.rs
│ │ │ ├── mod.rs
│ │ │ ├── persist.rs
│ │ │ ├── proto/
│ │ │ │ └── persistent_properties.proto
│ │ │ └── sys.cpp
│ │ ├── scripting.cpp
│ │ ├── selinux.rs
│ │ ├── socket.rs
│ │ ├── sqlite.cpp
│ │ ├── su/
│ │ │ ├── connect.rs
│ │ │ ├── daemon.rs
│ │ │ ├── db.rs
│ │ │ ├── mod.rs
│ │ │ ├── pts.rs
│ │ │ └── su.cpp
│ │ ├── thread.rs
│ │ ├── utils.cpp
│ │ └── zygisk/
│ │ ├── api.hpp
│ │ ├── daemon.rs
│ │ ├── entry.cpp
│ │ ├── gen_jni_hooks.py
│ │ ├── hook.cpp
│ │ ├── jni_hooks.hpp
│ │ ├── mod.rs
│ │ ├── module.cpp
│ │ ├── module.hpp
│ │ └── zygisk.hpp
│ ├── exported_sym.txt
│ ├── external/
│ │ ├── Android.mk
│ │ ├── lz4-sys/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ ├── lib.rs
│ │ │ └── wasm_shim.rs
│ │ ├── xz-embedded/
│ │ │ ├── xz.h
│ │ │ ├── xz_config.h
│ │ │ ├── xz_crc32.c
│ │ │ ├── xz_dec_lzma2.c
│ │ │ ├── xz_dec_stream.c
│ │ │ ├── xz_lzma2.h
│ │ │ ├── xz_private.h
│ │ │ └── xz_stream.h
│ │ └── xz_config/
│ │ └── config.h
│ ├── include/
│ │ ├── codegen.rs
│ │ ├── consts.hpp
│ │ └── consts.rs
│ ├── init/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ ├── getinfo.cpp
│ │ ├── getinfo.rs
│ │ ├── init.hpp
│ │ ├── init.rs
│ │ ├── lib.rs
│ │ ├── logging.rs
│ │ ├── mount.cpp
│ │ ├── mount.rs
│ │ ├── preload.c
│ │ ├── rootdir.cpp
│ │ ├── rootdir.rs
│ │ ├── selinux.rs
│ │ └── twostage.rs
│ ├── rustfmt.toml
│ └── sepolicy/
│ ├── Cargo.toml
│ ├── api.cpp
│ ├── build.rs
│ ├── cli.rs
│ ├── include/
│ │ └── sepolicy.hpp
│ ├── lib.rs
│ ├── policy.hpp
│ ├── policydb.cpp
│ ├── rules.rs
│ ├── sepolicy.cpp
│ └── statement.rs
├── scripts/
│ ├── addon.d.sh
│ ├── app_functions.sh
│ ├── avd.sh
│ ├── boot_patch.sh
│ ├── cuttlefish.sh
│ ├── flash_script.sh
│ ├── host_patch.sh
│ ├── live_setup.sh
│ ├── module_installer.sh
│ ├── release.sh
│ ├── test_common.sh
│ ├── uninstaller.sh
│ ├── update_binary.sh
│ └── util_functions.sh
└── tools/
├── bootctl
├── bootctl.patch
├── elf-cleaner/
│ ├── .gitignore
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
├── futility
├── keys/
│ ├── kernel.keyblock
│ ├── kernel_data_key.vbprivk
│ ├── verity.pk8
│ └── verity.x509.pem
└── rustup-wrapper/
├── .gitignore
├── Cargo.toml
└── src/
└── main.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Set the default behavior, in case people don't have core.autocrlf set.
* text eol=lf
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
# *.c text
# *.h text
# Declare files that will always have CRLF line endings on checkout.
*.cmd text eol=crlf
*.bat text eol=crlf
# Denote all files that are truly binary and should not be modified.
tools/** binary
tools/rustup-wrapper/** -binary
tools/elf-cleaner/** -binary
*.jar binary
*.exe binary
*.apk binary
*.png binary
*.jpg binary
*.ttf binary
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ""
labels: ""
assignees: ""
---
<!--
## READ BEFORE OPENING ISSUES
All bug reports require you to **USE DEBUG BUILDS**. Please include the version name and version code in the bug report.
If you experience a bootloop, attach a `dmesg` (kernel logs) when the device refuse to boot. This may very likely require a custom kernel on some devices as `last_kmsg` or `pstore ramoops` are usually not enabled by default. In addition, please also upload the result of `cat /proc/mounts` when your device is working correctly **WITHOUT MAGISK**.
If you experience issues during installation, in recovery, upload the recovery logs, or in Magisk, upload the install logs. Please also upload the `boot.img` or `recovery.img` that you are using for patching.
If you experience a crash of Magisk app, dump the full `logcat` **when the crash happens**.
If you experience other issues related to Magisk, upload `magisk.log`, and preferably also include a boot `logcat` (start dumping `logcat` when the device boots up)
**DO NOT** open issues regarding root detection.
**DO NOT** ask for instructions.
**DO NOT** report issues if you have any modules installed.
Without following the rules above, your issue will be closed without explanation.
-->
Device:
Android version:
Magisk version name:
Magisk version code:
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: XDA Community Support
url: https://forum.xda-developers.com/f/magisk.5903/
about: Please ask and answer questions here.
================================================
FILE: .github/actions/setup/action.yml
================================================
name: Magisk Setup
description: Set up the build environment for Magisk
inputs:
is-asset-build:
required: false
default: false
runs:
using: "composite"
steps:
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: "temurin"
java-version: "21"
- name: Set up Python 3
uses: actions/setup-python@v6
with:
python-version: "3.x"
- name: Install GNU make
if: runner.os == 'macOS'
shell: bash
run: |
brew install make
echo 'GNUMAKE=gmake' >> "$GITHUB_ENV"
- name: Cache sccache
uses: actions/cache@v5
if: ${{ github.event_name != 'pull_request' }}
with:
path: .sccache
key: sccache-${{ runner.os }}-${{ github.sha }}
restore-keys: sccache-${{ runner.os }}-
- name: Restore sccache
uses: actions/cache/restore@v5
if: ${{ github.event_name == 'pull_request' }}
with:
path: .sccache
key: sccache-${{ runner.os }}-${{ github.sha }}
restore-keys: sccache-${{ runner.os }}-
- name: Set up sccache
shell: bash
env:
SCCACHE_DIRECT: false
SCCACHE_DIR: ${{ github.workspace }}/.sccache
SCCACHE_CACHE_SIZE: ${{ inputs.is-asset-build == 'true' && '2G' || '300M' }}
SCCACHE_IDLE_TIMEOUT: 0
run: |
bash $GITHUB_ACTION_PATH/sccache.sh
sccache --start-server
sccache -z
- name: Show sccache stats
uses: gacts/run-and-post-run@v1
with:
run: sccache -s
post: sccache -s
- name: Set GRADLE_USER_HOME
shell: bash
run: echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/.gradle" >> "$GITHUB_ENV"
- name: Cache Gradle dependencies
uses: actions/cache@v5
if: ${{ inputs.is-asset-build == 'true' && github.event_name != 'pull_request' }}
with:
path: |
.gradle/caches
.gradle/wrapper
!.gradle/caches/build-cache-*
key: gradle-cache-${{ hashFiles('app/gradle/**') }}
restore-keys: gradle-cache-
- name: Restore Gradle dependencies
uses: actions/cache/restore@v5
if: ${{ inputs.is-asset-build == 'false' || github.event_name == 'pull_request' }}
with:
path: |
.gradle/caches
.gradle/wrapper
!.gradle/caches/build-cache-*
key: gradle-cache-${{ hashFiles('gradle/**') }}
restore-keys: gradle-cache-
enableCrossOsArchive: true
- name: Cache Gradle build cache
uses: actions/cache@v5
if: ${{ inputs.is-asset-build == 'true' && github.event_name != 'pull_request' }}
with:
path: .gradle/caches/build-cache-*
key: gradle-build-cache-${{ github.sha }}
restore-keys: gradle-build-cache-
- name: Restore Gradle build cache
uses: actions/cache/restore@v5
if: ${{ inputs.is-asset-build == 'false' || github.event_name == 'pull_request' }}
with:
path: .gradle/caches/build-cache-*
key: gradle-build-cache-${{ github.sha }}
restore-keys: gradle-build-cache-
enableCrossOsArchive: true
- name: Set up NDK
shell: bash
run: python build.py -v ndk
================================================
FILE: .github/actions/setup/sccache.sh
================================================
#!/usr/bin/env bash
# Get latest sccache version
get_sccache_ver() {
curl -sL 'https://api.github.com/repos/mozilla/sccache/releases/latest' | jq -r .name
}
# $1=variant
# $2=install_dir
# $3=exe
install_from_gh() {
local ver=$(curl -sL 'https://api.github.com/repos/mozilla/sccache/releases/latest' | jq -r .name)
local url="https://github.com/mozilla/sccache/releases/download/${ver}/sccache-${ver}-$1.tar.gz"
local dest="$2/$3"
curl -L "$url" | tar xz -O --wildcards "*/$3" > $dest
chmod +x $dest
}
if [ $RUNNER_OS = "macOS" ]; then
brew install sccache
elif [ $RUNNER_OS = "Linux" ]; then
install_from_gh x86_64-unknown-linux-musl /usr/local/bin sccache
elif [ $RUNNER_OS = "Windows" ]; then
install_from_gh x86_64-pc-windows-msvc $USERPROFILE/.cargo/bin sccache.exe
fi
================================================
FILE: .github/ci.prop
================================================
abiList=arm64-v8a
================================================
FILE: .github/kvm.sh
================================================
#!/usr/bin/env bash
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
================================================
FILE: .github/workflows/build.yml
================================================
name: Magisk Build
on:
push:
branches: [master]
paths:
- "app/**"
- "native/**"
- "build.py"
- ".github/workflows/build.yml"
pull_request:
branches: [master]
workflow_dispatch:
jobs:
build:
name: Build Magisk artifacts
runs-on: macos-26
strategy:
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
submodules: "recursive"
- name: Setup environment
uses: ./.github/actions/setup
with:
is-asset-build: true
- name: Build release
run: ./build.py -vr all
- name: Build debug
run: ./build.py -v all
- name: Stop gradle daemon
run: ./app/gradlew --stop
- name: Upload build artifact
uses: actions/upload-artifact@v7
with:
name: ${{ github.sha }}
path: out
compression-level: 9
- name: Upload mapping and native debug symbols
uses: actions/upload-artifact@v7
with:
name: ${{ github.sha }}-symbols
path: app/apk/build/outputs
compression-level: 9
test-build:
name: Test building on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-2025, ubuntu-24.04]
steps:
- name: Check out
uses: actions/checkout@v6
with:
submodules: "recursive"
- name: Setup environment
uses: ./.github/actions/setup
- name: Test build
run: python build.py -v -c .github/ci.prop all
- name: Stop gradle daemon
run: ./app/gradlew --stop
avd-test:
name: Test API ${{ matrix.version }} (x86_64)
runs-on: ubuntu-24.04
needs: build
if: ${{ github.event_name != 'push' }}
strategy:
fail-fast: false
matrix:
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36.1, "CANARY"]
type: [""]
include:
- version: "CinnamonBun"
type: "google_apis_ps16k"
steps:
- name: Check out
uses: actions/checkout@v6
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: ${{ github.sha }}
path: out
- name: Enable KVM group perms
run: .github/kvm.sh
- name: Run AVD test
timeout-minutes: 18
run: scripts/avd.sh test -l -v ${{ matrix.version }} -t ${{ matrix.type }}
- name: Upload logs on error
if: ${{ failure() }}
uses: actions/upload-artifact@v7
with:
name: "avd-logs-${{ matrix.version }}"
path: |
kernel.log
logcat.log
avd-test-32:
name: Test API ${{ matrix.version }} (x86)
runs-on: ubuntu-24.04
needs: build
if: ${{ github.event_name != 'push' }}
strategy:
fail-fast: false
matrix:
version: [23, 24, 25, 26, 27, 28, 29, 30]
steps:
- name: Check out
uses: actions/checkout@v6
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: ${{ github.sha }}
path: out
- name: Enable KVM group perms
run: .github/kvm.sh
- name: Run AVD test
timeout-minutes: 18
env:
FORCE_32_BIT: 1
run: scripts/avd.sh test -l -v ${{ matrix.version }}
- name: Upload logs on error
if: ${{ failure() }}
uses: actions/upload-artifact@v7
with:
name: "avd32-logs-${{ matrix.version }}"
path: |
kernel.log
logcat.log
cf-test:
name: Test ${{ matrix.device }}
runs-on: ubuntu-24.04
needs: build
if: ${{ github.event_name != 'push' }}
env:
CF_HOME: /home/runner/aosp_cf_phone
strategy:
fail-fast: false
matrix:
include:
- branch: "aosp-android-latest-release"
device: "aosp_cf_x86_64_only_phone"
steps:
- name: Check out
uses: actions/checkout@v6
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: ${{ github.sha }}
path: out
- name: Enable KVM group perms
run: .github/kvm.sh
- name: Setup Cuttlefish environment
run: |
scripts/cuttlefish.sh setup
scripts/cuttlefish.sh download ${{ matrix.branch }} ${{ matrix.device }}
- name: Run Cuttlefish test
timeout-minutes: 18
run: sudo -E -u $USER scripts/cuttlefish.sh test
- name: Upload logs on error
if: ${{ failure() }}
uses: actions/upload-artifact@v7
with:
name: "cvd-logs-${{ matrix.device }}"
path: |
/home/runner/aosp_cf_phone/cuttlefish/instances/cvd-1/logs
/home/runner/aosp_cf_phone/cuttlefish/instances/cvd-1/cuttlefish_config.json
================================================
FILE: .gitignore
================================================
out
*.zip
*.jks
*.apk
*.log
/config.prop
/notes.md
# Built binaries
native/out
# Android Studio
*.iml
.idea
.cursor
ramdisk.img
app/core/src/debug
app/core/src/release
================================================
FILE: .gitmodules
================================================
[submodule "selinux"]
path = native/src/external/selinux
url = https://github.com/topjohnwu/selinux.git
[submodule "lz4"]
path = native/src/external/lz4
url = https://github.com/lz4/lz4.git
[submodule "libcxx"]
path = native/src/external/libcxx
url = https://github.com/topjohnwu/libcxx.git
[submodule "cxx-rs"]
path = native/src/external/cxx-rs
url = https://github.com/topjohnwu/cxx.git
[submodule "lsplt"]
path = native/src/external/lsplt
url = https://github.com/LSPosed/LSPlt.git
[submodule "system_properties"]
path = native/src/external/system_properties
url = https://github.com/topjohnwu/system_properties.git
[submodule "crt0"]
path = native/src/external/crt0
url = https://github.com/topjohnwu/crt0.git
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
================================================
FILE: README.MD
================================================

[](https://raw.githubusercontent.com/topjohnwu/magisk-files/count/count.json)
#### This is not an officially supported Google product
## Introduction
Magisk is a suite of open source software for customizing Android, supporting devices higher than Android 6.0.<br>
Some highlight features:
- **MagiskSU**: Provide root access for applications
- **Magisk Modules**: Modify read-only partitions by installing modules
- **MagiskBoot**: The most complete tool for unpacking and repacking Android boot images
- **Zygisk**: Run code in every Android applications' processes
## Downloads
[Github](https://github.com/topjohnwu/Magisk/releases) is the only source where you can get official Magisk information and downloads.
## Useful Links
- [Installation Instruction](https://topjohnwu.github.io/Magisk/install.html)
- [Building and Development](https://topjohnwu.github.io/Magisk/build.html)
- [Magisk Documentation](https://topjohnwu.github.io/Magisk/)
- [Zygisk module sample](https://github.com/topjohnwu/zygisk-module-sample)
## Bug Reports
**Only bug reports from Debug builds will be accepted.**
For installation issues, upload both boot image and install logs.<br>
For Magisk issues, upload boot logcat or dmesg.<br>
For Magisk app crashes, record and upload the logcat when the crash occurs.
## Translation Contributions
Default string resources for the Magisk app and its stub APK are located here:
- `app/core/src/main/res/values/strings.xml`
- `app/stub/src/main/res/values/strings.xml`
Translate each and place them in the respective locations (`[module]/src/main/res/values-[lang]/strings.xml`).
## License
Magisk, including all git submodules are 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
================================================
FILE: app/.gitignore
================================================
/dict.txt
# Gradle
.gradle
.kotlin
build
/local.properties
================================================
FILE: app/apk/build.gradle.kts
================================================
plugins {
id("com.android.application")
kotlin("plugin.parcelize")
alias(libs.plugins.legacy.kapt)
alias(libs.plugins.navigation.safeargs)
}
setupMainApk()
kapt {
correctErrorTypes = true
useBuildCache = true
mapDiagnosticLocations = true
javacOptions {
option("-Xmaxerrs", "1000")
}
}
android {
buildFeatures {
dataBinding = true
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
defaultConfig {
proguardFile("proguard-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
}
}
}
dependencies {
implementation(project(":core"))
coreLibraryDesugaring(libs.jdk.libs)
implementation(libs.indeterminate.checkbox)
implementation(libs.rikka.layoutinflater)
implementation(libs.rikka.insets)
implementation(libs.rikka.recyclerview)
implementation(libs.navigation.fragment.ktx)
implementation(libs.navigation.ui.ktx)
implementation(libs.constraintlayout)
implementation(libs.swiperefreshlayout)
implementation(libs.recyclerview)
implementation(libs.transition)
implementation(libs.fragment.ktx)
implementation(libs.appcompat)
implementation(libs.material)
// Make sure kapt runs with a proper kotlin-stdlib
kapt(kotlin("stdlib"))
}
================================================
FILE: app/apk/proguard-rules.pro
================================================
# Excessive obfuscation
-flattenpackagehierarchy
-allowaccessmodification
================================================
FILE: app/apk/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application android:localeConfig="@xml/locale_config">
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".ui.surequest.SuRequestActivity"
android:directBootAware="true"
android:exported="false"
android:taskAffinity=""
tools:ignore="AppLinkUrlError">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/arch/AsyncLoadViewModel.kt
================================================
package com.topjohnwu.magisk.arch
import androidx.annotation.MainThread
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
abstract class AsyncLoadViewModel : BaseViewModel() {
private var loadingJob: Job? = null
@MainThread
fun startLoading() {
if (loadingJob?.isActive == true) {
// Prevent multiple jobs from running at the same time
return
}
loadingJob = viewModelScope.launch { doLoadWork() }
}
protected abstract suspend fun doLoadWork()
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/arch/BaseFragment.kt
================================================
package com.topjohnwu.magisk.arch
import android.os.Bundle
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.MenuProvider
import androidx.databinding.DataBindingUtil
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.BR
abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHolder {
val activity get() = getActivity() as? NavigationActivity<*>
protected lateinit var binding: Binding
protected abstract val layoutRes: Int
private val navigation get() = activity?.navigation
open val snackbarView: View? get() = null
open val snackbarAnchorView: View? get() = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startObserveLiveData()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate<Binding>(inflater, layoutRes, container, false).also {
it.setVariable(BR.viewModel, viewModel)
it.lifecycleOwner = viewLifecycleOwner
}
if (this is MenuProvider) {
activity?.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.STARTED)
}
savedInstanceState?.let { viewModel.onRestoreState(it) }
return binding.root
}
override fun onSaveInstanceState(outState: Bundle) {
viewModel.onSaveState(outState)
}
override fun onStart() {
super.onStart()
activity?.supportActionBar?.subtitle = null
}
override fun onEventDispatched(event: ViewEvent) = when(event) {
is ContextExecutor -> event(requireContext())
is ActivityExecutor -> activity?.let { event(it) } ?: Unit
is FragmentExecutor -> event(this)
else -> Unit
}
open fun onKeyEvent(event: KeyEvent): Boolean {
return false
}
open fun onBackPressed(): Boolean = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.addOnRebindCallback(object : OnRebindCallback<Binding>() {
override fun onPreBind(binding: Binding): Boolean {
this@BaseFragment.onPreBind(binding)
return true
}
})
}
override fun onResume() {
super.onResume()
viewModel.let {
if (it is AsyncLoadViewModel)
it.startLoading()
}
}
protected open fun onPreBind(binding: Binding) {
(binding.root as? ViewGroup)?.startAnimations()
}
fun NavDirections.navigate() {
navigation?.currentDestination?.getAction(actionId)?.let { navigation!!.navigate(this) }
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/arch/BaseViewModel.kt
================================================
package com.topjohnwu.magisk.arch
import android.Manifest.permission.POST_NOTIFICATIONS
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.annotation.SuppressLint
import android.os.Bundle
import androidx.databinding.PropertyChangeRegistry
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.databinding.ObservableHost
import com.topjohnwu.magisk.events.BackPressEvent
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.events.DialogEvent
import com.topjohnwu.magisk.events.NavigationEvent
import com.topjohnwu.magisk.events.PermissionEvent
import com.topjohnwu.magisk.events.SnackbarEvent
abstract class BaseViewModel : ViewModel(), ObservableHost {
override var callbacks: PropertyChangeRegistry? = null
private val _viewEvents = MutableLiveData<ViewEvent>()
val viewEvents: LiveData<ViewEvent> get() = _viewEvents
open fun onSaveState(state: Bundle) {}
open fun onRestoreState(state: Bundle) {}
open fun onNetworkChanged(network: Boolean) {}
fun withPermission(permission: String, callback: (Boolean) -> Unit) {
PermissionEvent(permission, callback).publish()
}
inline fun withExternalRW(crossinline callback: () -> Unit) {
withPermission(WRITE_EXTERNAL_STORAGE) {
if (!it) {
SnackbarEvent(R.string.external_rw_permission_denied).publish()
} else {
callback()
}
}
}
@SuppressLint("InlinedApi")
inline fun withInstallPermission(crossinline callback: () -> Unit) {
withPermission(REQUEST_INSTALL_PACKAGES) {
if (!it) {
SnackbarEvent(R.string.install_unknown_denied).publish()
} else {
callback()
}
}
}
@SuppressLint("InlinedApi")
inline fun withPostNotificationPermission(crossinline callback: () -> Unit) {
withPermission(POST_NOTIFICATIONS) {
if (!it) {
SnackbarEvent(R.string.post_notifications_denied).publish()
} else {
callback()
}
}
}
fun back() = BackPressEvent().publish()
fun ViewEvent.publish() {
_viewEvents.postValue(this)
}
fun DialogBuilder.show() {
DialogEvent(this).publish()
}
fun NavDirections.navigate(pop: Boolean = false) {
_viewEvents.postValue(NavigationEvent(this, pop))
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/arch/NavigationActivity.kt
================================================
package com.topjohnwu.magisk.arch
import android.content.ContentResolver
import android.view.KeyEvent
import androidx.databinding.ViewDataBinding
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.navOptions
import com.topjohnwu.magisk.utils.AccessibilityUtils
abstract class NavigationActivity<Binding : ViewDataBinding> : UIActivity<Binding>() {
abstract val navHostId: Int
private val navHostFragment by lazy {
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
}
protected val currentFragment get() =
navHostFragment.childFragmentManager.fragments.getOrNull(0) as? BaseFragment<*>
val navigation: NavController get() = navHostFragment.navController
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
return if (binded && currentFragment?.onKeyEvent(event) == true) true else super.dispatchKeyEvent(event)
}
override fun onBackPressed() {
if (binded) {
if (currentFragment?.onBackPressed() == false) {
super.onBackPressed()
}
}
}
companion object {
fun navigate(directions: NavDirections, navigation: NavController, cr: ContentResolver) {
if (AccessibilityUtils.isAnimationEnabled(cr)) {
navigation.navigate(directions)
} else {
navigation.navigate(directions, navOptions {})
}
}
}
fun NavDirections.navigate() {
navigate(this, navigation, contentResolver)
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/arch/UIActivity.kt
================================================
package com.topjohnwu.magisk.arch
import android.content.Context
import android.content.res.Resources
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.res.use
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.transition.AutoTransition
import androidx.transition.TransitionManager
import com.google.android.material.snackbar.Snackbar
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.base.ActivityExtension
import com.topjohnwu.magisk.core.base.IActivityExtension
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.ktx.reflectField
import com.topjohnwu.magisk.core.wrap
import rikka.insets.WindowInsetsHelper
import rikka.layoutinflater.view.LayoutInflaterFactory
abstract class UIActivity<Binding : ViewDataBinding>
: AppCompatActivity(), ViewModelHolder, IActivityExtension {
protected lateinit var binding: Binding
protected abstract val layoutRes: Int
override val extension = ActivityExtension(this)
protected val binded get() = ::binding.isInitialized
open val snackbarView get() = binding.root
open val snackbarAnchorView: View? get() = null
init {
AppCompatDelegate.setDefaultNightMode(Config.darkTheme)
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap())
}
override fun onCreate(savedInstanceState: Bundle?) {
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
.addOnViewCreatedListener(WindowInsetsHelper.LISTENER)
extension.onCreate(savedInstanceState)
if (isRunningAsStub) {
// Overwrite private members to avoid nasty "false" stack traces being logged
val delegate = delegate
val clz = delegate.javaClass
clz.reflectField("mActivityHandlesConfigFlagsChecked").set(delegate, true)
clz.reflectField("mActivityHandlesConfigFlags").set(delegate, 0)
}
super.onCreate(savedInstanceState)
startObserveLiveData()
// We need to set the window background explicitly since for whatever reason it's not
// propagated upstream
obtainStyledAttributes(intArrayOf(android.R.attr.windowBackground))
.use { it.getDrawable(0) }
.also { window.setBackgroundDrawable(it) }
WindowCompat.setDecorFitsSystemWindows(window, false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window?.decorView?.post {
// If navigation bar is short enough (gesture navigation enabled), make it transparent
if ((window.decorView.rootWindowInsets?.systemWindowInsetBottom
?: 0) < Resources.getSystem().displayMetrics.density * 40) {
window.navigationBarColor = Color.TRANSPARENT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.navigationBarDividerColor = Color.TRANSPARENT
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.isNavigationBarContrastEnforced = false
window.isStatusBarContrastEnforced = false
}
}
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
extension.onSaveInstanceState(outState)
}
fun setContentView() {
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).also {
it.setVariable(BR.viewModel, viewModel)
it.lifecycleOwner = this
}
}
fun setAccessibilityDelegate(delegate: View.AccessibilityDelegate?) {
binding.root.rootView.accessibilityDelegate = delegate
}
fun showSnackbar(
message: CharSequence,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) = Snackbar.make(snackbarView, message, length)
.setAnchorView(snackbarAnchorView).apply(builder).show()
override fun onResume() {
super.onResume()
viewModel.let {
if (it is AsyncLoadViewModel)
it.startLoading()
}
}
override fun onEventDispatched(event: ViewEvent) = when (event) {
is ContextExecutor -> event(this)
is ActivityExecutor -> event(this)
else -> Unit
}
}
fun ViewGroup.startAnimations() {
val transition = AutoTransition()
.setInterpolator(FastOutSlowInInterpolator())
.setDuration(400)
.excludeTarget(R.id.main_toolbar, true)
TransitionManager.beginDelayedTransition(
this,
transition
)
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/arch/ViewEvent.kt
================================================
package com.topjohnwu.magisk.arch
import android.content.Context
/**
* Class for passing events from ViewModels to Activities/Fragments
* (see https://medium.com/google-developers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150)
*/
abstract class ViewEvent
interface ContextExecutor {
operator fun invoke(context: Context)
}
interface ActivityExecutor {
operator fun invoke(activity: UIActivity<*>)
}
interface FragmentExecutor {
operator fun invoke(fragment: BaseFragment<*>)
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/arch/ViewModelHolder.kt
================================================
package com.topjohnwu.magisk.arch
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.ui.home.HomeViewModel
import com.topjohnwu.magisk.ui.install.InstallViewModel
import com.topjohnwu.magisk.ui.log.LogViewModel
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
import com.topjohnwu.magisk.ui.surequest.SuRequestViewModel
interface ViewModelHolder : LifecycleOwner, ViewModelStoreOwner {
val viewModel: BaseViewModel
fun startObserveLiveData() {
viewModel.viewEvents.observe(this, this::onEventDispatched)
Info.isConnected.observe(this, viewModel::onNetworkChanged)
}
/**
* Called for all [ViewEvent]s published by associated viewModel.
*/
fun onEventDispatched(event: ViewEvent) {}
}
object VMFactory : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when (modelClass) {
HomeViewModel::class.java -> HomeViewModel(ServiceLocator.networkService)
LogViewModel::class.java -> LogViewModel(ServiceLocator.logRepo)
SuperuserViewModel::class.java -> SuperuserViewModel(ServiceLocator.policyDB)
InstallViewModel::class.java ->
InstallViewModel(ServiceLocator.networkService, ServiceLocator.markwon)
SuRequestViewModel::class.java ->
SuRequestViewModel(ServiceLocator.policyDB, ServiceLocator.timeoutPrefs)
else -> modelClass.newInstance()
} as T
}
}
inline fun <reified VM : ViewModel> ViewModelHolder.viewModel() =
lazy(LazyThreadSafetyMode.NONE) {
ViewModelProvider(this, VMFactory)[VM::class.java]
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt
================================================
package com.topjohnwu.magisk.databinding
import android.animation.ValueAnimator
import android.content.res.ColorStateList
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.text.Spanned
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.Spinner
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.widget.Toolbar
import androidx.cardview.widget.CardView
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.updateLayoutParams
import androidx.core.widget.ImageViewCompat
import androidx.databinding.BindingAdapter
import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener
import androidx.databinding.InverseMethod
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.slider.Slider
import com.google.android.material.textfield.TextInputLayout
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.widget.IndeterminateCheckBox
import kotlin.math.roundToInt
@BindingAdapter("gone")
fun setGone(view: View, gone: Boolean) {
view.isGone = gone
}
@BindingAdapter("invisible")
fun setInvisible(view: View, invisible: Boolean) {
view.isInvisible = invisible
}
@BindingAdapter("goneUnless")
fun setGoneUnless(view: View, goneUnless: Boolean) {
setGone(view, goneUnless.not())
}
@BindingAdapter("invisibleUnless")
fun setInvisibleUnless(view: View, invisibleUnless: Boolean) {
setInvisible(view, invisibleUnless.not())
}
@BindingAdapter("markdownText")
fun setMarkdownText(tv: TextView, markdown: Spanned) {
ServiceLocator.markwon.setParsedMarkdown(tv, markdown)
}
@BindingAdapter("onNavigationClick")
fun setOnNavigationClickedListener(view: Toolbar, listener: View.OnClickListener) {
view.setNavigationOnClickListener(listener)
}
@BindingAdapter("srcCompat")
fun setImageResource(view: ImageView, @DrawableRes resId: Int) {
view.setImageResource(resId)
}
@BindingAdapter("srcCompat")
fun setImageResource(view: ImageView, drawable: Drawable) {
view.setImageDrawable(drawable)
}
@BindingAdapter("onTouch")
fun setOnTouchListener(view: View, listener: View.OnTouchListener) {
view.setOnTouchListener(listener)
}
@BindingAdapter("scrollToLast")
fun setScrollToLast(view: RecyclerView, shouldScrollToLast: Boolean) {
fun scrollToLast() = UiThreadHandler.handler.postDelayed({
view.scrollToPosition(view.adapter?.itemCount?.minus(1) ?: 0)
}, 30)
fun wait(callback: () -> Unit) {
UiThreadHandler.handler.postDelayed(callback, 1000)
}
fun RecyclerView.Adapter<*>.setListener() {
val observer = object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
scrollToLast()
}
}
registerAdapterDataObserver(observer)
view.setTag(R.id.recyclerScrollListener, observer)
}
fun RecyclerView.Adapter<*>.removeListener() {
val observer =
view.getTag(R.id.recyclerScrollListener) as? RecyclerView.AdapterDataObserver ?: return
unregisterAdapterDataObserver(observer)
}
fun trySetListener(): Unit = view.adapter?.setListener() ?: wait { trySetListener() }
if (shouldScrollToLast) {
trySetListener()
} else {
view.adapter?.removeListener()
}
}
@BindingAdapter("isEnabled")
fun setEnabled(view: View, isEnabled: Boolean) {
view.isEnabled = isEnabled
}
@BindingAdapter("error")
fun TextInputLayout.setErrorString(error: String) {
val newError = error.let { if (it.isEmpty()) null else it }
if (this.error == null && newError == null) return
this.error = newError
}
// md2
@BindingAdapter(
"android:layout_marginLeft",
"android:layout_marginTop",
"android:layout_marginRight",
"android:layout_marginBottom",
"android:layout_marginStart",
"android:layout_marginEnd",
requireAll = false
)
fun View.setMargins(
marginLeft: Int?,
marginTop: Int?,
marginRight: Int?,
marginBottom: Int?,
marginStart: Int?,
marginEnd: Int?
) = updateLayoutParams<ViewGroup.MarginLayoutParams> {
marginLeft?.let { leftMargin = it }
marginTop?.let { topMargin = it }
marginRight?.let { rightMargin = it }
marginBottom?.let { bottomMargin = it }
marginStart?.let { this.marginStart = it }
marginEnd?.let { this.marginEnd = it }
}
@BindingAdapter("nestedScrollingEnabled")
fun RecyclerView.setNestedScrolling(enabled: Boolean) {
isNestedScrollingEnabled = enabled
}
@BindingAdapter("isSelected")
fun View.isSelected(isSelected: Boolean) {
this.isSelected = isSelected
}
@BindingAdapter("dividerVertical", "dividerHorizontal", requireAll = false)
fun RecyclerView.setDividers(dividerVertical: Drawable?, dividerHorizontal: Drawable?) {
if (dividerHorizontal != null) {
DividerItemDecoration(context, LinearLayoutManager.HORIZONTAL).apply {
setDrawable(dividerHorizontal)
}.let { addItemDecoration(it) }
}
if (dividerVertical != null) {
DividerItemDecoration(context, LinearLayoutManager.VERTICAL).apply {
setDrawable(dividerVertical)
}.let { addItemDecoration(it) }
}
}
@BindingAdapter("icon")
fun Button.setIconRes(res: Int) {
(this as MaterialButton).setIconResource(res)
}
@BindingAdapter("icon")
fun Button.setIcon(drawable: Drawable) {
(this as MaterialButton).icon = drawable
}
@BindingAdapter("strokeWidth")
fun MaterialCardView.setCardStrokeWidthBound(stroke: Float) {
strokeWidth = stroke.roundToInt()
}
@BindingAdapter("onMenuClick")
fun Toolbar.setOnMenuClickListener(listener: Toolbar.OnMenuItemClickListener) {
setOnMenuItemClickListener(listener)
}
@BindingAdapter("onCloseClicked")
fun Chip.setOnCloseClickedListenerBinding(listener: View.OnClickListener) {
setOnCloseIconClickListener(listener)
}
@BindingAdapter("progressAnimated")
fun ProgressBar.setProgressAnimated(newProgress: Int) {
val animator = tag as? ValueAnimator
animator?.cancel()
ValueAnimator.ofInt(progress, newProgress).apply {
interpolator = FastOutSlowInInterpolator()
addUpdateListener { progress = it.animatedValue as Int }
tag = this
}.start()
}
@BindingAdapter("android:text")
fun TextView.setTextSafe(text: Int) {
if (text == 0) this.text = null else setText(text)
}
@BindingAdapter("android:onLongClick")
fun View.setOnLongClickListenerBinding(listener: () -> Unit) {
setOnLongClickListener {
listener()
true
}
}
@BindingAdapter("strikeThrough")
fun TextView.setStrikeThroughEnabled(useStrikeThrough: Boolean) {
paintFlags = if (useStrikeThrough) {
paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
} else {
paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}
}
@BindingAdapter("spanCount")
fun RecyclerView.setSpanCount(count: Int) {
when (val lama = layoutManager) {
is GridLayoutManager -> lama.spanCount = count
is StaggeredGridLayoutManager -> lama.spanCount = count
}
}
@BindingAdapter("state")
fun setState(view: IndeterminateCheckBox, state: Boolean?) {
if (view.state != state)
view.state = state
}
@InverseBindingAdapter(attribute = "state")
fun getState(view: IndeterminateCheckBox) = view.state
@BindingAdapter("stateAttrChanged")
fun setListeners(
view: IndeterminateCheckBox,
attrChange: InverseBindingListener
) {
view.setOnStateChangedListener { _, _ ->
attrChange.onChange()
}
}
@BindingAdapter("cardBackgroundColorAttr")
fun CardView.setCardBackgroundColorAttr(attr: Int) {
val tv = TypedValue()
context.theme.resolveAttribute(attr, tv, true)
setCardBackgroundColor(tv.data)
}
@BindingAdapter("tint")
fun ImageView.setTint(color: Int) {
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(color))
}
@BindingAdapter("tintAttr")
fun ImageView.setTintAttr(attr: Int) {
val tv = TypedValue()
context.theme.resolveAttribute(attr, tv, true)
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(tv.data))
}
@BindingAdapter("textColorAttr")
fun TextView.setTextColorAttr(attr: Int) {
val tv = TypedValue()
context.theme.resolveAttribute(attr, tv, true)
setTextColor(tv.data)
}
@BindingAdapter("android:text")
fun TextView.setText(text: TextHolder) {
this.text = text.getText(context.resources)
}
@BindingAdapter("items", "layout")
fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) {
adapter = ArrayAdapter(context, layoutRes, items)
}
@BindingAdapter("labelFormatter")
fun Slider.setLabelFormatter(formatter: (Float) -> Int) {
setLabelFormatter { value -> resources.getString(formatter(value)) }
}
@InverseBindingAdapter(attribute = "android:value")
fun Slider.getValueBinding() = value
@BindingAdapter("android:valueAttrChanged")
fun Slider.setListener(attrChange: InverseBindingListener) {
addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
override fun onStartTrackingTouch(slider: Slider) = Unit
override fun onStopTrackingTouch(slider: Slider) = attrChange.onChange()
})
}
@InverseMethod("sliderValueToPolicy")
fun policyToSliderValue(policy: Int): Float {
return when (policy) {
SuPolicy.DENY -> 1f
SuPolicy.RESTRICT -> 2f
SuPolicy.ALLOW -> 3f
else -> 1f
}
}
fun sliderValueToPolicy(value: Float): Int {
return when (value) {
1f -> SuPolicy.DENY
2f -> SuPolicy.RESTRICT
3f -> SuPolicy.ALLOW
else -> SuPolicy.DENY
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/databinding/DiffObservableList.kt
================================================
package com.topjohnwu.magisk.databinding
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import androidx.databinding.ListChangeRegistry
import androidx.databinding.ObservableList
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListUpdateCallback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.AbstractList
// Only expose the immutable List types
interface DiffList<T : DiffItem<*>> : List<T> {
fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult
@MainThread
fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult)
@WorkerThread
suspend fun update(newItems: List<T>)
}
interface FilterList<T : DiffItem<*>> : List<T> {
fun filter(filter: (T) -> Boolean)
@MainThread
fun set(newItems: List<T>)
}
fun <T : DiffItem<*>> diffList(): DiffList<T> = DiffObservableList()
fun <T : DiffItem<*>> filterList(scope: CoroutineScope): FilterList<T> =
FilterableDiffObservableList(scope)
private open class DiffObservableList<T : DiffItem<*>>
: AbstractList<T>(), ObservableList<T>, DiffList<T>, ListUpdateCallback {
protected var list: List<T> = emptyList()
private val listeners = ListChangeRegistry()
override val size: Int get() = list.size
override fun get(index: Int) = list[index]
override fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult {
return doCalculateDiff(list, newItems)
}
protected fun doCalculateDiff(oldItems: List<T>, newItems: List<T>): DiffUtil.DiffResult {
return DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize() = oldItems.size
override fun getNewListSize() = newItems.size
@Suppress("UNCHECKED_CAST")
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldItems[oldItemPosition]
val newItem = newItems[newItemPosition]
return (oldItem as DiffItem<Any>).itemSameAs(newItem)
}
@Suppress("UNCHECKED_CAST")
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldItems[oldItemPosition]
val newItem = newItems[newItemPosition]
return (oldItem as DiffItem<Any>).contentSameAs(newItem)
}
}, true)
}
@MainThread
override fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult) {
list = ArrayList(newItems)
diffResult.dispatchUpdatesTo(this)
}
@WorkerThread
override suspend fun update(newItems: List<T>) {
val diffResult = calculateDiff(newItems)
withContext(Dispatchers.Main) {
update(newItems, diffResult)
}
}
override fun addOnListChangedCallback(listener: ObservableList.OnListChangedCallback<out ObservableList<T>>) {
listeners.add(listener)
}
override fun removeOnListChangedCallback(listener: ObservableList.OnListChangedCallback<out ObservableList<T>>) {
listeners.remove(listener)
}
override fun onChanged(position: Int, count: Int, payload: Any?) {
listeners.notifyChanged(this, position, count)
}
override fun onMoved(fromPosition: Int, toPosition: Int) {
listeners.notifyMoved(this, fromPosition, toPosition, 1)
}
override fun onInserted(position: Int, count: Int) {
modCount += 1
listeners.notifyInserted(this, position, count)
}
override fun onRemoved(position: Int, count: Int) {
modCount += 1
listeners.notifyRemoved(this, position, count)
}
}
private class FilterableDiffObservableList<T : DiffItem<*>>(
private val scope: CoroutineScope
) : DiffObservableList<T>(), FilterList<T> {
private var sublist: List<T> = emptyList()
private var job: Job? = null
private var lastFilter: ((T) -> Boolean)? = null
// ---
override fun filter(filter: (T) -> Boolean) {
lastFilter = filter
job?.cancel()
job = scope.launch(Dispatchers.Default) {
val oldList = sublist
val newList = list.filter(filter)
val diff = doCalculateDiff(oldList, newList)
withContext(Dispatchers.Main) {
sublist = newList
diff.dispatchUpdatesTo(this@FilterableDiffObservableList)
}
}
}
// ---
override fun get(index: Int): T {
return sublist[index]
}
override val size: Int
get() = sublist.size
@MainThread
override fun set(newItems: List<T>) {
onRemoved(0, sublist.size)
list = newItems
sublist = emptyList()
lastFilter?.let { filter(it) }
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/databinding/MergeObservableList.kt
================================================
package com.topjohnwu.magisk.databinding
import androidx.databinding.ListChangeRegistry
import androidx.databinding.ObservableList
import androidx.databinding.ObservableList.OnListChangedCallback
import java.util.AbstractList
@Suppress("UNCHECKED_CAST")
class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
private val lists: MutableList<List<T>> = mutableListOf()
private val listeners = ListChangeRegistry()
private val callback = Callback<T>()
override fun addOnListChangedCallback(callback: OnListChangedCallback<out ObservableList<T>>) {
listeners.add(callback)
}
override fun removeOnListChangedCallback(callback: OnListChangedCallback<out ObservableList<T>>) {
listeners.remove(callback)
}
override fun get(index: Int): T {
if (index < 0)
throw IndexOutOfBoundsException()
var idx = index
for (list in lists) {
val size = list.size
if (idx < size) {
return list[idx]
}
idx -= size
}
throw IndexOutOfBoundsException()
}
override val size: Int
get() = lists.fold(0) { i, it -> i + it.size }
fun insertItem(obj: T): MergeObservableList<T> {
val idx = size
lists.add(listOf(obj))
++modCount
listeners.notifyInserted(this, idx, 1)
return this
}
fun insertList(list: List<T>): MergeObservableList<T> {
val idx = size
lists.add(list)
++modCount
(list as? ObservableList<T>)?.addOnListChangedCallback(callback)
if (list.isNotEmpty())
listeners.notifyInserted(this, idx, list.size)
return this
}
fun removeItem(obj: T): Boolean {
var idx = 0
for ((i, list) in lists.withIndex()) {
if (list !is ObservableList<*>) {
if (obj == list[0]) {
lists.removeAt(i)
++modCount
listeners.notifyRemoved(this, idx, 1)
return true
}
}
idx += list.size
}
return false
}
fun removeList(listToRemove: List<T>): Boolean {
var idx = 0
for ((i, list) in lists.withIndex()) {
if (listToRemove === list) {
(list as? ObservableList<T>)?.removeOnListChangedCallback(callback)
lists.removeAt(i)
++modCount
listeners.notifyRemoved(this, idx, list.size)
return true
}
idx += list.size
}
return false
}
override fun clear() {
val sz = size
for (list in lists) {
if (list is ObservableList) {
list.removeOnListChangedCallback(callback)
}
}
++modCount
lists.clear()
if (sz > 0)
listeners.notifyRemoved(this, 0, sz)
}
private fun subIndexToIndex(subList: List<*>, index: Int): Int {
if (index < 0)
throw IndexOutOfBoundsException()
var idx = 0
for (list in lists) {
if (subList === list) {
return idx + index
}
idx += list.size
}
throw IllegalArgumentException()
}
inner class Callback<T> : OnListChangedCallback<ObservableList<T>>() {
override fun onChanged(sender: ObservableList<T>) {
++modCount
listeners.notifyChanged(this@MergeObservableList)
}
override fun onItemRangeChanged(
sender: ObservableList<T>,
positionStart: Int,
itemCount: Int
) {
listeners.notifyChanged(this@MergeObservableList,
subIndexToIndex(sender, positionStart), itemCount)
}
override fun onItemRangeInserted(
sender: ObservableList<T>,
positionStart: Int,
itemCount: Int
) {
++modCount
listeners.notifyInserted(this@MergeObservableList,
subIndexToIndex(sender, positionStart), itemCount)
}
override fun onItemRangeMoved(
sender: ObservableList<T>,
fromPosition: Int,
toPosition: Int,
itemCount: Int
) {
val idx = subIndexToIndex(sender, 0)
listeners.notifyMoved(this@MergeObservableList,
idx + fromPosition, idx + toPosition, itemCount)
}
override fun onItemRangeRemoved(
sender: ObservableList<T>,
positionStart: Int,
itemCount: Int
) {
++modCount
listeners.notifyRemoved(this@MergeObservableList,
subIndexToIndex(sender, positionStart), itemCount)
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/databinding/ObservableHost.kt
================================================
package com.topjohnwu.magisk.databinding
import androidx.databinding.Observable
import androidx.databinding.PropertyChangeRegistry
/**
* Modified from https://github.com/skoumalcz/teanity/blob/1.2/core/src/main/java/com/skoumal/teanity/observable/Notifyable.kt
*
* Interface that allows user to be observed via DataBinding or manually by assigning listeners.
*
* @see [androidx.databinding.Observable]
* */
interface ObservableHost : Observable {
var callbacks: PropertyChangeRegistry?
/**
* Notifies all observers that something has changed. By default implementation this method is
* synchronous, hence observers will never be notified in undefined order. Observers might
* choose to refresh the view completely, which is beyond the scope of this function.
* */
fun notifyChange() {
synchronized(this) {
callbacks ?: return
}.notifyCallbacks(this, 0, null)
}
/**
* Notifies all observers about field with [fieldId] has been changed. This will happen
* synchronously before or after [notifyChange] has been called. It will never be called during
* the execution of aforementioned method.
* */
fun notifyPropertyChanged(fieldId: Int) {
synchronized(this) {
callbacks ?: return
}.notifyCallbacks(this, fieldId, null)
}
override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback) {
synchronized(this) {
callbacks ?: PropertyChangeRegistry().also { callbacks = it }
}.add(callback)
}
override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback) {
synchronized(this) {
callbacks ?: return
}.remove(callback)
}
}
fun ObservableHost.addOnPropertyChangedCallback(
fieldId: Int,
removeAfterChanged: Boolean = false,
callback: () -> Unit
) {
addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
if (fieldId == propertyId) {
callback()
if (removeAfterChanged)
removeOnPropertyChangedCallback(this)
}
}
})
}
/**
* Injects boilerplate implementation for {@literal @}[androidx.databinding.Bindable] field setters.
*
* # Examples:
* ```kotlin
* @get:Bindable
* var myField = defaultValue
* set(value) = set(value, field, { field = it }, BR.myField) {
* doSomething(it)
* }
* ```
* */
inline fun <reified T> ObservableHost.set(
new: T, old: T, setter: (T) -> Unit, fieldId: Int, afterChanged: (T) -> Unit = {}) {
if (old != new) {
setter(new)
notifyPropertyChanged(fieldId)
afterChanged(new)
}
}
inline fun <reified T> ObservableHost.set(
new: T, old: T, setter: (T) -> Unit, vararg fieldIds: Int, afterChanged: (T) -> Unit = {}) {
if (old != new) {
setter(new)
fieldIds.forEach { notifyPropertyChanged(it) }
afterChanged(new)
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/databinding/RecyclerViewItems.kt
================================================
package com.topjohnwu.magisk.databinding
import androidx.databinding.PropertyChangeRegistry
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
abstract class RvItem {
abstract val layoutRes: Int
}
abstract class ObservableRvItem : RvItem(), ObservableHost {
override var callbacks: PropertyChangeRegistry? = null
}
interface ItemWrapper<E> {
val item: E
}
interface ViewAwareItem {
fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView)
}
interface DiffItem<T : Any> {
fun itemSameAs(other: T): Boolean {
if (this === other) return true
return when (this) {
is ItemWrapper<*> -> item == (other as ItemWrapper<*>).item
is Comparable<*> -> compareValues(this, other as Comparable<*>) == 0
else -> this == other
}
}
fun contentSameAs(other: T) = true
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/databinding/RvItemAdapter.kt
================================================
package com.topjohnwu.magisk.databinding
import android.annotation.SuppressLint
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.BindingAdapter
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableList
import androidx.databinding.ObservableList.OnListChangedCallback
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.BR
class RvItemAdapter<T: RvItem>(
val items: List<T>,
val extraBindings: SparseArray<*>?
) : RecyclerView.Adapter<RvItemAdapter.ViewHolder>() {
private var lifecycleOwner: LifecycleOwner? = null
private var recyclerView: RecyclerView? = null
private val observer by lazy(LazyThreadSafetyMode.NONE) { ListObserver<T>() }
override fun onAttachedToRecyclerView(rv: RecyclerView) {
lifecycleOwner = rv.findViewTreeLifecycleOwner()
recyclerView = rv
if (items is ObservableList)
items.addOnListChangedCallback(observer)
}
override fun onDetachedFromRecyclerView(rv: RecyclerView) {
lifecycleOwner = null
recyclerView = null
if (items is ObservableList)
items.removeOnListChangedCallback(observer)
}
override fun onCreateViewHolder(parent: ViewGroup, layoutRes: Int): ViewHolder {
val inflator = LayoutInflater.from(parent.context)
return ViewHolder(DataBindingUtil.inflate(inflator, layoutRes, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
holder.binding.setVariable(BR.item, item)
extraBindings?.let {
for (i in 0 until it.size()) {
holder.binding.setVariable(it.keyAt(i), it.valueAt(i))
}
}
holder.binding.lifecycleOwner = lifecycleOwner
holder.binding.executePendingBindings()
recyclerView?.let {
if (item is ViewAwareItem)
item.onBind(holder.binding, it)
}
}
override fun getItemCount() = items.size
override fun getItemViewType(position: Int) = items[position].layoutRes
class ViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root)
inner class ListObserver<T: RvItem> : OnListChangedCallback<ObservableList<T>>() {
@SuppressLint("NotifyDataSetChanged")
override fun onChanged(sender: ObservableList<T>) {
notifyDataSetChanged()
}
override fun onItemRangeChanged(
sender: ObservableList<T>,
positionStart: Int,
itemCount: Int
) {
notifyItemRangeChanged(positionStart, itemCount)
}
override fun onItemRangeInserted(
sender: ObservableList<T>?,
positionStart: Int,
itemCount: Int
) {
notifyItemRangeInserted(positionStart, itemCount)
}
override fun onItemRangeMoved(
sender: ObservableList<T>?,
fromPosition: Int,
toPosition: Int,
itemCount: Int
) {
for (i in 0 until itemCount) {
notifyItemMoved(fromPosition + i, toPosition + i)
}
}
override fun onItemRangeRemoved(
sender: ObservableList<T>?,
positionStart: Int,
itemCount: Int
) {
notifyItemRangeRemoved(positionStart, itemCount)
}
}
}
inline fun bindExtra(body: (SparseArray<Any?>) -> Unit) = SparseArray<Any?>().also(body)
@BindingAdapter("items", "extraBindings", requireAll = false)
fun <T: RvItem> RecyclerView.setAdapter(items: List<T>?, extraBindings: SparseArray<*>?) {
if (items != null) {
val rva = (adapter as? RvItemAdapter<*>)
if (rva == null || rva.items !== items || rva.extraBindings !== extraBindings) {
adapter = RvItemAdapter(items, extraBindings)
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/DarkThemeDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import android.app.Activity
import androidx.appcompat.app.AppCompatDelegate
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.core.R as CoreR
class DarkThemeDialog : DialogBuilder {
override fun build(dialog: MagiskDialog) {
val activity = dialog.ownerActivity!!
dialog.apply {
setTitle(CoreR.string.settings_dark_mode_title)
setMessage(CoreR.string.settings_dark_mode_message)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = CoreR.string.settings_dark_mode_light
icon = R.drawable.ic_day
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_NO, activity) }
}
setButton(MagiskDialog.ButtonType.NEUTRAL) {
text = CoreR.string.settings_dark_mode_system
icon = R.drawable.ic_day_night
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, activity) }
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = CoreR.string.settings_dark_mode_dark
icon = R.drawable.ic_night
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_YES, activity) }
}
}
}
private fun selectTheme(mode: Int, activity: Activity) {
Config.darkTheme = mode
(activity as UIActivity<*>).delegate.localNightMode = mode
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/EnvFixDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import android.widget.Toast
import androidx.core.os.postDelayed
import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.ktx.reboot
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.ui.home.HomeViewModel
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.superuser.internal.UiThreadHandler
import kotlinx.coroutines.launch
class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : DialogBuilder {
override fun build(dialog: MagiskDialog) {
dialog.apply {
setTitle(R.string.env_fix_title)
setMessage(R.string.env_fix_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
doNotDismiss = true
onClick {
dialog.apply {
setTitle(R.string.setup_title)
setMessage(R.string.setup_msg)
resetButtons()
setCancelable(false)
}
dialog.activity.lifecycleScope.launch {
MagiskInstaller.FixEnv().exec { success ->
dialog.dismiss()
context.toast(
if (success) R.string.reboot_delay_toast else R.string.setup_fail,
Toast.LENGTH_LONG
)
if (success)
UiThreadHandler.handler.postDelayed(5000) { reboot() }
}
}
}
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
}
}
if (code == 2 || // No rules block, module policy not loaded
Info.env.versionCode != BuildConfig.APP_VERSION_CODE ||
Info.env.versionString != BuildConfig.APP_VERSION_NAME) {
dialog.setMessage(R.string.env_full_fix_msg)
dialog.setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
onClick {
vm.onMagiskPressed()
dialog.dismiss()
}
}
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/LocalModuleInstallDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import android.net.Uri
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.ui.module.ModuleViewModel
import com.topjohnwu.magisk.view.MagiskDialog
class LocalModuleInstallDialog(
private val viewModel: ModuleViewModel,
private val uri: Uri,
private val displayName: String
) : DialogBuilder {
override fun build(dialog: MagiskDialog) {
dialog.apply {
setTitle(R.string.confirm_install_title)
setMessage(context.getString(R.string.confirm_install, displayName))
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
onClick {
viewModel.apply {
MainDirections.actionFlashFragment(Const.Value.FLASH_ZIP, uri).navigate()
}
}
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
}
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/ManagerInstallDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.download.DownloadEngine
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.view.MagiskDialog
import java.io.File
class ManagerInstallDialog : MarkDownDialog() {
override suspend fun getMarkdownText(): String {
val text = Info.update.note
// Cache the changelog
File(AppContext.cacheDir, "${Info.update.versionCode}.md").writeText(text)
return text
}
override fun build(dialog: MagiskDialog) {
super.build(dialog)
dialog.apply {
setCancelable(true)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.install
onClick { DownloadEngine.startWithActivity(activity, Subject.App()) }
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
}
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/MarkDownDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import android.view.LayoutInflater
import android.widget.TextView
import androidx.annotation.CallSuper
import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.view.MagiskDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.IOException
import com.topjohnwu.magisk.core.R as CoreR
abstract class MarkDownDialog : DialogBuilder {
abstract suspend fun getMarkdownText(): String
@CallSuper
override fun build(dialog: MagiskDialog) {
with(dialog) {
val view = LayoutInflater.from(context).inflate(R.layout.markdown_window_md2, null)
setView(view)
val tv = view.findViewById<TextView>(R.id.md_txt)
activity.lifecycleScope.launch {
try {
val text = withContext(Dispatchers.IO) { getMarkdownText() }
ServiceLocator.markwon.setMarkdown(tv, text)
} catch (e: IOException) {
Timber.e(e)
tv.setText(CoreR.string.download_file_error)
}
}
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import android.content.Context
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.download.DownloadEngine
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Notifications
import kotlinx.parcelize.Parcelize
class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog() {
private val svc get() = ServiceLocator.networkService
override suspend fun getMarkdownText(): String {
val str = svc.fetchString(item.changelog)
return if (str.length > 1000) str.substring(0, 1000) else str
}
@Parcelize
class Module(
override val module: OnlineModule,
override val autoLaunch: Boolean,
override val notifyId: Int = Notifications.nextId()
) : Subject.Module() {
override fun pendingIntent(context: Context) = FlashFragment.installIntent(context, file)
}
override fun build(dialog: MagiskDialog) {
super.build(dialog)
dialog.apply {
fun download(install: Boolean) {
DownloadEngine.startWithActivity(activity, Module(item, install))
}
val title = context.getString(R.string.repo_install_title,
item.name, item.version, item.versionCode)
setTitle(title)
setCancelable(true)
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = R.string.download
onClick { download(false) }
}
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.install
onClick { download(true) }
}
setButton(MagiskDialog.ButtonType.NEUTRAL) {
text = android.R.string.cancel
}
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/SecondSlotWarningDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.view.MagiskDialog
class SecondSlotWarningDialog : DialogBuilder {
override fun build(dialog: MagiskDialog) {
dialog.apply {
setTitle(android.R.string.dialog_alert_title)
setMessage(R.string.install_inactive_slot_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
}
setCancelable(true)
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/SuperuserRevokeDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.view.MagiskDialog
class SuperuserRevokeDialog(
private val appName: String,
private val onSuccess: () -> Unit
) : DialogBuilder {
override fun build(dialog: MagiskDialog) {
dialog.apply {
setTitle(R.string.su_revoke_title)
setMessage(R.string.su_revoke_msg, appName)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
onClick { onSuccess() }
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
}
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/dialog/UninstallDialog.kt
================================================
package com.topjohnwu.magisk.dialog
import android.app.ProgressDialog
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.arch.NavigationActivity
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.events.DialogBuilder
import com.topjohnwu.magisk.ui.flash.FlashFragment
import com.topjohnwu.magisk.view.MagiskDialog
import kotlinx.coroutines.launch
class UninstallDialog : DialogBuilder {
override fun build(dialog: MagiskDialog) {
dialog.apply {
setTitle(R.string.uninstall_magisk_title)
setMessage(R.string.uninstall_magisk_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = R.string.restore_img
onClick { restore(dialog.activity) }
}
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = R.string.complete_uninstall
onClick { completeUninstall(dialog) }
}
}
}
@Suppress("DEPRECATION")
private fun restore(activity: UIActivity<*>) {
val dialog = ProgressDialog(activity).apply {
setMessage(activity.getString(R.string.restore_img_msg))
show()
}
activity.lifecycleScope.launch {
MagiskInstaller.Restore().exec { success ->
dialog.dismiss()
if (success) {
activity.toast(R.string.restore_done, Toast.LENGTH_SHORT)
} else {
activity.toast(R.string.restore_fail, Toast.LENGTH_LONG)
}
}
}
}
private fun completeUninstall(dialog: MagiskDialog) {
(dialog.ownerActivity as NavigationActivity<*>)
.navigation.navigate(FlashFragment.uninstall())
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/events/ViewEvents.kt
================================================
package com.topjohnwu.magisk.events
import android.content.Context
import android.view.View
import androidx.annotation.StringRes
import androidx.navigation.NavDirections
import com.google.android.material.snackbar.Snackbar
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.ContextExecutor
import com.topjohnwu.magisk.arch.NavigationActivity
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.base.ContentResultCallback
import com.topjohnwu.magisk.core.base.relaunch
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Shortcuts
class PermissionEvent(
private val permission: String,
private val callback: (Boolean) -> Unit
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) =
activity.withPermission(permission, callback)
}
class BackPressEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
activity.onBackPressed()
}
}
class DieEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
activity.finish()
}
}
class ShowUIEvent(private val delegate: View.AccessibilityDelegate?)
: ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
activity.setContentView()
activity.setAccessibilityDelegate(delegate)
}
}
class RecreateEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
activity.relaunch()
}
}
class AuthEvent(
private val callback: () -> Unit
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
activity.withAuthentication { if (it) callback() }
}
}
class GetContentEvent(
private val type: String,
private val callback: ContentResultCallback
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
activity.getContent(type, callback)
}
}
class NavigationEvent(
private val directions: NavDirections,
private val pop: Boolean
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
(activity as? NavigationActivity<*>)?.apply {
if (pop) navigation.popBackStack()
directions.navigate()
}
}
}
class AddHomeIconEvent : ViewEvent(), ContextExecutor {
override fun invoke(context: Context) {
Shortcuts.addHomeIcon(context)
}
}
class SnackbarEvent(
private val msg: TextHolder,
private val length: Int = Snackbar.LENGTH_SHORT,
private val builder: Snackbar.() -> Unit = {}
) : ViewEvent(), ActivityExecutor {
constructor(
@StringRes res: Int,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(res.asText(), length, builder)
constructor(
msg: String,
length: Int = Snackbar.LENGTH_SHORT,
builder: Snackbar.() -> Unit = {}
) : this(msg.asText(), length, builder)
override fun invoke(activity: UIActivity<*>) {
activity.showSnackbar(msg.getText(activity.resources), length, builder)
}
}
class DialogEvent(
private val builder: DialogBuilder
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
MagiskDialog(activity).apply(builder::build).show()
}
}
interface DialogBuilder {
fun build(dialog: MagiskDialog)
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
================================================
package com.topjohnwu.magisk.ui
import android.Manifest
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.view.forEach
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.arch.NavigationActivity
import com.topjohnwu.magisk.arch.startAnimations
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.SplashController
import com.topjohnwu.magisk.core.base.SplashScreenHost
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.model.module.LocalModule
import com.topjohnwu.magisk.core.tasks.AppMigration
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
import com.topjohnwu.magisk.ui.theme.Theme
import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Shortcuts
import kotlinx.coroutines.launch
import java.io.File
import com.topjohnwu.magisk.core.R as CoreR
class MainViewModel : BaseViewModel()
class MainActivity : NavigationActivity<ActivityMainMd2Binding>(), SplashScreenHost {
override val layoutRes = R.layout.activity_main_md2
override val viewModel by viewModel<MainViewModel>()
override val navHostId: Int = R.id.main_nav_host
override val splashController = SplashController(this)
override val snackbarView: View
get() {
val fragmentOverride = currentFragment?.snackbarView
return fragmentOverride ?: super.snackbarView
}
override val snackbarAnchorView: View?
get() {
val fragmentAnchor = currentFragment?.snackbarAnchorView
return when {
fragmentAnchor?.isVisible == true -> fragmentAnchor
binding.mainNavigation.isVisible -> return binding.mainNavigation
else -> null
}
}
private var isRootFragment = true
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(Theme.selected.themeRes)
splashController.preOnCreate()
super.onCreate(savedInstanceState)
splashController.onCreate(savedInstanceState)
}
override fun onResume() {
super.onResume()
splashController.onResume()
}
@SuppressLint("InlinedApi")
override fun onCreateUi(savedInstanceState: Bundle?) {
setContentView()
showUnsupportedMessage()
askForHomeShortcut()
// Ask permission to post notifications for background update check
if (Config.checkUpdate) {
withPermission(Manifest.permission.POST_NOTIFICATIONS) {
Config.checkUpdate = it
}
}
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
navigation.addOnDestinationChangedListener { _, destination, _ ->
isRootFragment = when (destination.id) {
R.id.homeFragment,
R.id.modulesFragment,
R.id.superuserFragment,
R.id.logFragment -> true
else -> false
}
setDisplayHomeAsUpEnabled(!isRootFragment)
requestNavigationHidden(!isRootFragment)
binding.mainNavigation.menu.forEach {
if (it.itemId == destination.id) {
it.isChecked = true
}
}
}
setSupportActionBar(binding.mainToolbar)
binding.mainNavigation.setOnItemSelectedListener {
getScreen(it.itemId)?.navigate()
true
}
binding.mainNavigation.setOnItemReselectedListener {
// https://issuetracker.google.com/issues/124538620
}
binding.mainNavigation.menu.apply {
findItem(R.id.superuserFragment)?.isEnabled = Info.showSuperUser
findItem(R.id.modulesFragment)?.isEnabled = Info.env.isActive && LocalModule.loaded()
}
val section =
if (intent.action == Intent.ACTION_APPLICATION_PREFERENCES)
Const.Nav.SETTINGS
else
intent.getStringExtra(Const.Key.OPEN_SECTION)
getScreen(section)?.navigate()
if (!isRootFragment) {
requestNavigationHidden(requiresAnimation = savedInstanceState == null)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> onBackPressed()
else -> return super.onOptionsItemSelected(item)
}
return true
}
fun setDisplayHomeAsUpEnabled(isEnabled: Boolean) {
binding.mainToolbar.startAnimations()
when {
isEnabled -> binding.mainToolbar.setNavigationIcon(R.drawable.ic_back_md2)
else -> binding.mainToolbar.navigationIcon = null
}
}
internal fun requestNavigationHidden(hide: Boolean = true, requiresAnimation: Boolean = true) {
val bottomView = binding.mainNavigation
if (requiresAnimation) {
bottomView.isVisible = true
bottomView.isHidden = hide
} else {
bottomView.isGone = hide
}
}
fun invalidateToolbar() {
//binding.mainToolbar.startAnimations()
binding.mainToolbar.invalidate()
}
private fun getScreen(name: String?): NavDirections? {
return when (name) {
Const.Nav.SUPERUSER -> MainDirections.actionSuperuserFragment()
Const.Nav.MODULES -> MainDirections.actionModuleFragment()
Const.Nav.SETTINGS -> HomeFragmentDirections.actionHomeFragmentToSettingsFragment()
else -> null
}
}
private fun getScreen(id: Int): NavDirections? {
return when (id) {
R.id.homeFragment -> MainDirections.actionHomeFragment()
R.id.modulesFragment -> MainDirections.actionModuleFragment()
R.id.superuserFragment -> MainDirections.actionSuperuserFragment()
R.id.logFragment -> MainDirections.actionLogFragment()
else -> null
}
}
@SuppressLint("InlinedApi")
override fun showInvalidStateMessage(): Unit = runOnUiThread {
MagiskDialog(this).apply {
setTitle(CoreR.string.unsupport_nonroot_stub_title)
setMessage(CoreR.string.unsupport_nonroot_stub_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = CoreR.string.install
onClick {
withPermission(REQUEST_INSTALL_PACKAGES) {
if (!it) {
toast(CoreR.string.install_unknown_denied, Toast.LENGTH_SHORT)
showInvalidStateMessage()
} else {
lifecycleScope.launch {
AppMigration.restore(this@MainActivity)
}
}
}
}
}
setCancelable(false)
show()
}
}
private fun showUnsupportedMessage() {
if (Info.env.isUnsupported) {
MagiskDialog(this).apply {
setTitle(CoreR.string.unsupport_magisk_title)
setMessage(CoreR.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
setCancelable(false)
}.show()
}
if (!Info.isEmulator && Info.env.isActive && System.getenv("PATH")
?.split(':')
?.filterNot { File("$it/magisk").exists() }
?.any { File("$it/su").exists() } == true) {
MagiskDialog(this).apply {
setTitle(CoreR.string.unsupport_general_title)
setMessage(CoreR.string.unsupport_other_su_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
setCancelable(false)
}.show()
}
if (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
MagiskDialog(this).apply {
setTitle(CoreR.string.unsupport_general_title)
setMessage(CoreR.string.unsupport_system_app_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
setCancelable(false)
}.show()
}
if (applicationInfo.flags and ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0) {
MagiskDialog(this).apply {
setTitle(CoreR.string.unsupport_general_title)
setMessage(CoreR.string.unsupport_external_storage_msg)
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
setCancelable(false)
}.show()
}
}
private fun askForHomeShortcut() {
if (isRunningAsStub && !Config.askedHome &&
ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
// Ask and show dialog
Config.askedHome = true
MagiskDialog(this).apply {
setTitle(CoreR.string.add_shortcut_title)
setMessage(CoreR.string.add_shortcut_msg)
setButton(MagiskDialog.ButtonType.NEGATIVE) {
text = android.R.string.cancel
}
setButton(MagiskDialog.ButtonType.POSITIVE) {
text = android.R.string.ok
onClick {
Shortcuts.addHomeIcon(this@MainActivity)
}
}
setCancelable(true)
}.show()
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/AppProcessInfo.kt
================================================
package com.topjohnwu.magisk.ui.deny
import android.annotation.SuppressLint
import android.content.pm.ApplicationInfo
import android.content.pm.ComponentInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.GET_ACTIVITIES
import android.content.pm.PackageManager.GET_PROVIDERS
import android.content.pm.PackageManager.GET_RECEIVERS
import android.content.pm.PackageManager.GET_SERVICES
import android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
import android.content.pm.ServiceInfo
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import androidx.core.os.ProcessCompat
import com.topjohnwu.magisk.core.ktx.getLabel
import java.util.Locale
import java.util.TreeSet
class CmdlineListItem(line: String) {
val packageName: String
val process: String
init {
val split = line.split(Regex("\\|"), 2)
packageName = split[0]
process = split.getOrElse(1) { packageName }
}
}
const val ISOLATED_MAGIC = "isolated"
@SuppressLint("InlinedApi")
class AppProcessInfo(
private val info: ApplicationInfo,
pm: PackageManager,
denyList: List<CmdlineListItem>
) : Comparable<AppProcessInfo> {
private val denyList = denyList.filter {
it.packageName == info.packageName || it.packageName == ISOLATED_MAGIC
}
val label = info.getLabel(pm)
val iconImage: Drawable = runCatching { info.loadIcon(pm) }.getOrDefault(pm.defaultActivityIcon)
val packageName: String get() = info.packageName
val processes = fetchProcesses(pm)
override fun compareTo(other: AppProcessInfo) = comparator.compare(this, other)
fun isSystemApp() = info.flags and ApplicationInfo.FLAG_SYSTEM != 0
fun isApp() = ProcessCompat.isApplicationUid(info.uid)
private fun createProcess(name: String, pkg: String = info.packageName) =
ProcessInfo(name, pkg, denyList.any { it.process == name && it.packageName == pkg })
private fun ComponentInfo.getProcName(): String = processName
?: applicationInfo.processName
?: applicationInfo.packageName
private val ServiceInfo.isIsolated get() = (flags and ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
private val ServiceInfo.useAppZygote get() = (flags and ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0
private fun Array<out ComponentInfo>?.toProcessList() =
orEmpty().map { createProcess(it.getProcName()) }
private fun Array<ServiceInfo>?.toProcessList() = orEmpty().map {
if (it.isIsolated) {
if (it.useAppZygote) {
val proc = info.processName ?: info.packageName
createProcess("${proc}_zygote")
} else {
val proc = if (SDK_INT >= Build.VERSION_CODES.Q)
"${it.getProcName()}:${it.name}" else it.getProcName()
createProcess(proc, ISOLATED_MAGIC)
}
} else {
createProcess(it.getProcName())
}
}
private fun fetchProcesses(pm: PackageManager): Collection<ProcessInfo> {
val flag = MATCH_DISABLED_COMPONENTS or MATCH_UNINSTALLED_PACKAGES or
GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS
val packageInfo = try {
pm.getPackageInfo(info.packageName, flag)
} catch (e: Exception) {
// Exceed binder data transfer limit, parse the package locally
pm.getPackageArchiveInfo(info.sourceDir, flag) ?: return emptyList()
}
val processSet = TreeSet<ProcessInfo>(compareBy({ it.name }, { it.isIsolated }))
processSet += packageInfo.activities.toProcessList()
processSet += packageInfo.services.toProcessList()
processSet += packageInfo.receivers.toProcessList()
processSet += packageInfo.providers.toProcessList()
return processSet
}
companion object {
private val comparator = compareBy<AppProcessInfo>(
{ it.label.lowercase(Locale.ROOT) },
{ it.info.packageName }
)
}
}
data class ProcessInfo(
val name: String,
val packageName: String,
var isEnabled: Boolean
) {
val isIsolated = packageName == ISOLATED_MAGIC
val isAppZygote = name.endsWith("_zygote")
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListFragment.kt
================================================
package com.topjohnwu.magisk.ui.deny
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.appcompat.widget.SearchView
import androidx.core.view.MenuProvider
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.ktx.hideKeyboard
import com.topjohnwu.magisk.databinding.FragmentDenyMd2Binding
import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addItemSpacing
import rikka.recyclerview.fixEdgeEffect
import com.topjohnwu.magisk.core.R as CoreR
class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
override val layoutRes = R.layout.fragment_deny_md2
override val viewModel by viewModel<DenyListViewModel>()
private lateinit var searchView: SearchView
override fun onStart() {
super.onStart()
activity?.setTitle(CoreR.string.denylist)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.appList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (newState != RecyclerView.SCROLL_STATE_IDLE) activity?.hideKeyboard()
}
})
binding.appList.apply {
addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1)
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
fixEdgeEffect()
}
}
override fun onPreBind(binding: FragmentDenyMd2Binding) = Unit
override fun onBackPressed(): Boolean {
if (searchView.isIconfiedByDefault && !searchView.isIconified) {
searchView.isIconified = true
return true
}
return super.onBackPressed()
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_deny_md2, menu)
searchView = menu.findItem(R.id.action_search).actionView as SearchView
searchView.queryHint = searchView.context.getString(CoreR.string.hide_filter_hint)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
viewModel.query = query ?: ""
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
viewModel.query = newText ?: ""
return true
}
})
}
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_show_system -> {
val check = !item.isChecked
viewModel.isShowSystem = check
item.isChecked = check
return true
}
R.id.action_show_OS -> {
val check = !item.isChecked
viewModel.isShowOS = check
item.isChecked = check
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onPrepareMenu(menu: Menu) {
val showSystem = menu.findItem(R.id.action_show_system)
val showOS = menu.findItem(R.id.action_show_OS)
showOS.isEnabled = showSystem.isChecked
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListRvItem.kt
================================================
package com.topjohnwu.magisk.ui.deny
import android.view.View
import android.view.ViewGroup
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.startAnimations
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.addOnPropertyChangedCallback
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.superuser.Shell
import kotlin.math.roundToInt
class DenyListRvItem(
val info: AppProcessInfo
) : ObservableRvItem(), DiffItem<DenyListRvItem>, Comparable<DenyListRvItem> {
override val layoutRes get() = R.layout.item_hide_md2
val processes = info.processes.map { ProcessRvItem(it) }
@get:Bindable
var isExpanded = false
set(value) = set(value, field, { field = it }, BR.expanded)
var itemsChecked = 0
set(value) = set(value, field, { field = it }, BR.checkedPercent)
val isChecked get() = itemsChecked != 0
@get:Bindable
val checkedPercent get() = (itemsChecked.toFloat() / processes.size * 100).roundToInt()
private var _state: Boolean? = false
set(value) = set(value, field, { field = it }, BR.state)
@get:Bindable
var state: Boolean?
get() = _state
set(value) = set(value, _state, { _state = it }, BR.state) {
if (value == true) {
processes
.filterNot { it.isEnabled }
.filter { isExpanded || it.defaultSelection }
.forEach { it.toggle() }
} else {
Shell.cmd("magisk --denylist rm ${info.packageName}").submit()
processes.filter { it.isEnabled }.forEach {
if (it.process.isIsolated) {
it.toggle()
} else {
it.isEnabled = !it.isEnabled
notifyPropertyChanged(BR.enabled)
}
}
}
}
init {
processes.forEach { it.addOnPropertyChangedCallback(BR.enabled) { recalculateChecked() } }
addOnPropertyChangedCallback(BR.expanded) { recalculateChecked() }
recalculateChecked()
}
fun toggleExpand(v: View) {
(v.parent as? ViewGroup)?.startAnimations()
isExpanded = !isExpanded
}
private fun recalculateChecked() {
itemsChecked = processes.count { it.isEnabled }
_state = if (isExpanded) {
when (itemsChecked) {
0 -> false
processes.size -> true
else -> null
}
} else {
val defaultProcesses = processes.filter { it.defaultSelection }
when (defaultProcesses.count { it.isEnabled }) {
0 -> false
defaultProcesses.size -> true
else -> null
}
}
}
override fun compareTo(other: DenyListRvItem) = comparator.compare(this, other)
companion object {
private val comparator = compareBy<DenyListRvItem>(
{ it.itemsChecked == 0 },
{ it.info }
)
}
}
class ProcessRvItem(
val process: ProcessInfo
) : ObservableRvItem(), DiffItem<ProcessRvItem> {
override val layoutRes get() = R.layout.item_hide_process_md2
val displayName = if (process.isIsolated) "(isolated) ${process.name}" else process.name
@get:Bindable
var isEnabled
get() = process.isEnabled
set(value) = set(value, process.isEnabled, { process.isEnabled = it }, BR.enabled) {
val arg = if (it) "add" else "rm"
val (name, pkg) = process
Shell.cmd("magisk --denylist $arg $pkg \'$name\'").submit()
}
fun toggle() {
isEnabled = !isEnabled
}
val defaultSelection get() =
process.isIsolated || process.isAppZygote || process.name == process.packageName
override fun itemSameAs(other: ProcessRvItem) =
process.name == other.process.name && process.packageName == other.process.packageName
override fun contentSameAs(other: ProcessRvItem) =
process.isEnabled == other.process.isEnabled
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt
================================================
package com.topjohnwu.magisk.ui.deny
import android.annotation.SuppressLint
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.ktx.concurrentMap
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.filterList
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.toCollection
import kotlinx.coroutines.withContext
class DenyListViewModel : AsyncLoadViewModel() {
var isShowSystem = false
set(value) {
field = value
doQuery(query)
}
var isShowOS = false
set(value) {
field = value
doQuery(query)
}
var query = ""
set(value) {
field = value
doQuery(value)
}
val items = filterList<DenyListRvItem>(viewModelScope)
val extraBindings = bindExtra {
it.put(BR.viewModel, this)
}
@get:Bindable
var loading = true
private set(value) = set(value, field, { field = it }, BR.loading)
@SuppressLint("InlinedApi")
override suspend fun doLoadWork() {
loading = true
val apps = withContext(Dispatchers.Default) {
val pm = AppContext.packageManager
val denyList = Shell.cmd("magisk --denylist ls").exec().out
.map { CmdlineListItem(it) }
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES).run {
asFlow()
.filter { AppContext.packageName != it.packageName }
.concurrentMap { AppProcessInfo(it, pm, denyList) }
.filter { it.processes.isNotEmpty() }
.concurrentMap { DenyListRvItem(it) }
.toCollection(ArrayList(size))
}
apps.sort()
apps
}
items.set(apps)
doQuery(query)
}
private fun doQuery(s: String) {
items.filter {
fun filterSystem() = isShowSystem || !it.info.isSystemApp()
fun filterOS() = (isShowSystem && isShowOS) || it.info.isApp()
fun filterQuery(): Boolean {
fun inName() = it.info.label.contains(s, true)
fun inPackage() = it.info.packageName.contains(s, true)
fun inProcesses() = it.processes.any { p -> p.process.name.contains(s, true) }
return inName() || inPackage() || inProcesses()
}
(it.isChecked || (filterSystem() && filterOS())) && filterQuery()
}
loading = false
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/flash/ConsoleItem.kt
================================================
package com.topjohnwu.magisk.ui.flash
import android.view.View
import android.widget.TextView
import androidx.core.view.updateLayoutParams
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.ViewAwareItem
import kotlin.math.max
class ConsoleItem(
override val item: String
) : RvItem(), ViewAwareItem, DiffItem<ConsoleItem>, ItemWrapper<String> {
override val layoutRes = R.layout.item_console_md2
private var parentWidth = -1
override fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView) {
if (parentWidth < 0)
parentWidth = (recyclerView.parent as View).width
val view = binding.root as TextView
view.measure(0, 0)
// We want our recyclerView at least as wide as screen
val desiredWidth = max(view.measuredWidth, parentWidth)
view.updateLayoutParams { width = desiredWidth }
if (recyclerView.width < desiredWidth) {
recyclerView.requestLayout()
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt
================================================
package com.topjohnwu.magisk.ui.flash
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Bundle
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.view.MenuProvider
import androidx.core.view.isVisible
import androidx.navigation.NavDeepLinkBuilder
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.cmp
import com.topjohnwu.magisk.databinding.FragmentFlashMd2Binding
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.core.R as CoreR
class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
override val layoutRes = R.layout.fragment_flash_md2
override val viewModel by viewModel<FlashViewModel>()
override val snackbarView: View get() = binding.snackbarContainer
override val snackbarAnchorView: View?
get() = if (binding.restartBtn.isShown) binding.restartBtn else super.snackbarAnchorView
private var defaultOrientation = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.args = FlashFragmentArgs.fromBundle(requireArguments())
}
override fun onStart() {
super.onStart()
activity?.setTitle(CoreR.string.flash_screen_title)
viewModel.state.observe(this) {
activity?.supportActionBar?.setSubtitle(
when (it) {
FlashViewModel.State.FLASHING -> CoreR.string.flashing
FlashViewModel.State.SUCCESS -> CoreR.string.done
FlashViewModel.State.FAILED -> CoreR.string.failure
}
)
if (it == FlashViewModel.State.SUCCESS && viewModel.showReboot) {
binding.restartBtn.apply {
if (!this.isVisible) this.show()
if (!this.isFocused) this.requestFocus()
}
}
}
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_flash, menu)
}
override fun onMenuItemSelected(item: MenuItem): Boolean {
return viewModel.onMenuItemClicked(item)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
defaultOrientation = activity?.requestedOrientation ?: -1
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
if (savedInstanceState == null) {
viewModel.startFlashing()
}
}
@SuppressLint("WrongConstant")
override fun onDestroyView() {
if (defaultOrientation != -1) {
activity?.requestedOrientation = defaultOrientation
}
super.onDestroyView()
}
override fun onKeyEvent(event: KeyEvent): Boolean {
return when (event.keyCode) {
KeyEvent.KEYCODE_VOLUME_UP,
KeyEvent.KEYCODE_VOLUME_DOWN -> true
else -> false
}
}
override fun onBackPressed(): Boolean {
if (viewModel.flashing.value == true)
return true
return super.onBackPressed()
}
override fun onPreBind(binding: FragmentFlashMd2Binding) = Unit
companion object {
private fun createIntent(context: Context, args: FlashFragmentArgs) =
NavDeepLinkBuilder(context)
.setGraph(R.navigation.main)
.setComponentName(MainActivity::class.java.cmp(context.packageName))
.setDestination(R.id.flashFragment)
.setArguments(args.toBundle())
.createPendingIntent()
private fun flashType(isSecondSlot: Boolean) =
if (isSecondSlot) Const.Value.FLASH_INACTIVE_SLOT else Const.Value.FLASH_MAGISK
/* Flashing is understood as installing / flashing magisk itself */
fun flash(isSecondSlot: Boolean) = MainDirections.actionFlashFragment(
action = flashType(isSecondSlot)
)
/* Patching is understood as injecting img files with magisk */
fun patch(uri: Uri) = MainDirections.actionFlashFragment(
action = Const.Value.PATCH_FILE,
additionalData = uri
)
/* Uninstalling is understood as removing magisk entirely */
fun uninstall() = MainDirections.actionFlashFragment(
action = Const.Value.UNINSTALL
)
/* Installing is understood as flashing modules / zips */
fun installIntent(context: Context, file: Uri) = FlashFragmentArgs(
action = Const.Value.FLASH_ZIP,
additionalData = file,
).let { createIntent(context, it) }
fun install(file: Uri) = MainDirections.actionFlashFragment(
action = Const.Value.FLASH_ZIP,
additionalData = file,
)
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
================================================
package com.topjohnwu.magisk.ui.flash
import android.view.MenuItem
import androidx.databinding.Bindable
import androidx.databinding.ObservableArrayList
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.ktx.reboot
import com.topjohnwu.magisk.core.ktx.synchronized
import com.topjohnwu.magisk.core.ktx.timeFormatStandard
import com.topjohnwu.magisk.core.ktx.toTime
import com.topjohnwu.magisk.core.tasks.FlashZip
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.superuser.CallbackList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class FlashViewModel : BaseViewModel() {
enum class State {
FLASHING, SUCCESS, FAILED
}
private val _state = MutableLiveData(State.FLASHING)
val state: LiveData<State> get() = _state
val flashing = state.map { it == State.FLASHING }
@get:Bindable
var showReboot = Info.isRooted
set(value) = set(value, field, { field = it }, BR.showReboot)
val items = ObservableArrayList<ConsoleItem>()
lateinit var args: FlashFragmentArgs
private val logItems = mutableListOf<String>().synchronized()
private val outItems = object : CallbackList<String>() {
override fun onAddElement(e: String?) {
e ?: return
items.add(ConsoleItem(e))
logItems.add(e)
}
}
fun startFlashing() {
val (action, uri) = args
viewModelScope.launch {
val result = when (action) {
Const.Value.FLASH_ZIP -> {
uri ?: return@launch
FlashZip(uri, outItems, logItems).exec()
}
Const.Value.UNINSTALL -> {
showReboot = false
MagiskInstaller.Uninstall(outItems, logItems).exec()
}
Const.Value.FLASH_MAGISK -> {
if (Info.isEmulator)
MagiskInstaller.Emulator(outItems, logItems).exec()
else
MagiskInstaller.Direct(outItems, logItems).exec()
}
Const.Value.FLASH_INACTIVE_SLOT -> {
showReboot = false
MagiskInstaller.SecondSlot(outItems, logItems).exec()
}
Const.Value.PATCH_FILE -> {
uri ?: return@launch
showReboot = false
MagiskInstaller.Patch(uri, outItems, logItems).exec()
}
else -> {
back()
return@launch
}
}
onResult(result)
}
}
private fun onResult(success: Boolean) {
_state.value = if (success) State.SUCCESS else State.FAILED
}
fun onMenuItemClicked(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_save -> savePressed()
}
return true
}
private fun savePressed() = withExternalRW {
viewModelScope.launch(Dispatchers.IO) {
val name = "magisk_install_log_%s.log".format(
System.currentTimeMillis().toTime(timeFormatStandard)
)
val file = MediaStoreUtils.getFile(name)
file.uri.outputStream().bufferedWriter().use { writer ->
synchronized(logItems) {
logItems.forEach {
writer.write(it)
writer.newLine()
}
}
}
SnackbarEvent(file.toString()).publish()
}
}
fun restartPressed() = reboot()
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/home/DeveloperItem.kt
================================================
package com.topjohnwu.magisk.ui.home
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.core.R as CoreR
interface Dev {
val name: String
}
private interface JohnImpl : Dev {
override val name get() = "topjohnwu"
}
private interface VvbImpl : Dev {
override val name get() = "vvb2060"
}
private interface YUImpl : Dev {
override val name get() = "yujincheng08"
}
private interface RikkaImpl : Dev {
override val name get() = "RikkaW"
}
private interface CanyieImpl : Dev {
override val name get() = "canyie"
}
sealed class DeveloperItem : Dev {
abstract val items: List<IconLink>
val handle get() = "@${name}"
object John : DeveloperItem(), JohnImpl {
override val items =
listOf(
object : IconLink.Twitter(), JohnImpl {},
IconLink.Github.Project
)
}
object Vvb : DeveloperItem(), VvbImpl {
override val items =
listOf<IconLink>(
object : IconLink.Twitter(), VvbImpl {},
object : IconLink.Github.User(), VvbImpl {}
)
}
object YU : DeveloperItem(), YUImpl {
override val items =
listOf<IconLink>(
object : IconLink.Twitter() { override val name = "shanasaimoe" },
object : IconLink.Github.User(), YUImpl {},
object : IconLink.Sponsor(), YUImpl {}
)
}
object Rikka : DeveloperItem(), RikkaImpl {
override val items =
listOf<IconLink>(
object : IconLink.Twitter() { override val name = "rikkawww" },
object : IconLink.Github.User(), RikkaImpl {}
)
}
object Canyie : DeveloperItem(), CanyieImpl {
override val items =
listOf<IconLink>(
object : IconLink.Twitter() { override val name = "canyie2977" },
object : IconLink.Github.User(), CanyieImpl {}
)
}
}
sealed class IconLink : RvItem() {
abstract val icon: Int
abstract val title: Int
abstract val link: String
override val layoutRes get() = R.layout.item_icon_link
abstract class PayPal : IconLink(), Dev {
override val icon get() = CoreR.drawable.ic_paypal
override val title get() = CoreR.string.paypal
override val link get() = "https://paypal.me/$name"
object Project : PayPal() {
override val name: String get() = "magiskdonate"
}
}
object Patreon : IconLink() {
override val icon get() = CoreR.drawable.ic_patreon
override val title get() = CoreR.string.patreon
override val link get() = Const.Url.PATREON_URL
}
abstract class Twitter : IconLink(), Dev {
override val icon get() = CoreR.drawable.ic_twitter
override val title get() = CoreR.string.twitter
override val link get() = "https://twitter.com/$name"
}
abstract class Github : IconLink() {
override val icon get() = CoreR.drawable.ic_github
override val title get() = CoreR.string.github
abstract class User : Github(), Dev {
override val link get() = "https://github.com/$name"
}
object Project : Github() {
override val link get() = Const.Url.SOURCE_CODE_URL
}
}
abstract class Sponsor : IconLink(), Dev {
override val icon get() = CoreR.drawable.ic_favorite
override val title get() = CoreR.string.github
override val link get() = "https://github.com/sponsors/$name"
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt
================================================
package com.topjohnwu.magisk.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.MenuProvider
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.DownloadEngine
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
import com.topjohnwu.magisk.core.R as CoreR
import androidx.navigation.findNavController
import com.topjohnwu.magisk.arch.NavigationActivity
class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
override val layoutRes = R.layout.fragment_home_md2
override val viewModel by viewModel<HomeViewModel>()
override fun onStart() {
super.onStart()
activity?.setTitle(CoreR.string.section_home)
DownloadEngine.observeProgress(this, viewModel::onProgressUpdate)
}
private fun checkTitle(text: TextView, icon: ImageView) {
text.post {
if (text.layout?.getEllipsisCount(0) != 0) {
with (icon) {
layoutParams.width = 0
layoutParams.height = 0
requestLayout()
}
}
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
super.onCreateView(inflater, container, savedInstanceState)
// If titles are squished, hide icons
with(binding.homeMagiskWrapper) {
checkTitle(homeMagiskTitle, homeMagiskIcon)
}
with(binding.homeManagerWrapper) {
checkTitle(homeManagerTitle, homeManagerIcon)
}
return binding.root
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_home_md2, menu)
if (!Info.isRooted)
menu.removeItem(R.id.action_reboot)
}
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings ->
activity?.let {
NavigationActivity.navigate(
HomeFragmentDirections.actionHomeFragmentToSettingsFragment(),
it.findNavController(R.id.main_nav_host),
it.contentResolver,
)
}
R.id.action_reboot -> activity?.let { RebootMenu.inflate(it).show() }
else -> return super.onOptionsItemSelected(item)
}
return true
}
override fun onResume() {
super.onResume()
viewModel.stateManagerProgress = 0
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt
================================================
package com.topjohnwu.magisk.ui.home
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.core.net.toUri
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
import com.topjohnwu.magisk.arch.ContextExecutor
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.download.Subject.App
import com.topjohnwu.magisk.core.ktx.await
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.repository.NetworkService
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.dialog.EnvFixDialog
import com.topjohnwu.magisk.dialog.ManagerInstallDialog
import com.topjohnwu.magisk.dialog.UninstallDialog
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.superuser.Shell
import kotlin.math.roundToInt
import com.topjohnwu.magisk.core.R as CoreR
class HomeViewModel(
private val svc: NetworkService
) : AsyncLoadViewModel() {
enum class State {
LOADING, INVALID, OUTDATED, UP_TO_DATE
}
val magiskTitleBarrierIds =
intArrayOf(R.id.home_magisk_icon, R.id.home_magisk_title, R.id.home_magisk_button)
val appTitleBarrierIds =
intArrayOf(R.id.home_manager_icon, R.id.home_manager_title, R.id.home_manager_button)
@get:Bindable
var isNoticeVisible = Config.safetyNotice
set(value) = set(value, field, { field = it }, BR.noticeVisible)
val magiskState
get() = when {
Info.isRooted && Info.env.isUnsupported -> State.OUTDATED
!Info.env.isActive -> State.INVALID
Info.env.versionCode < BuildConfig.APP_VERSION_CODE -> State.OUTDATED
else -> State.UP_TO_DATE
}
@get:Bindable
var appState = State.LOADING
set(value) = set(value, field, { field = it }, BR.appState)
val magiskInstalledVersion
get() = Info.env.run {
if (isActive)
("$versionString ($versionCode)" + if (isDebug) " (D)" else "").asText()
else
CoreR.string.not_available.asText()
}
@get:Bindable
var managerRemoteVersion = CoreR.string.loading.asText()
set(value) = set(value, field, { field = it }, BR.managerRemoteVersion)
val managerInstalledVersion
get() = "${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})" +
if (BuildConfig.DEBUG) " (D)" else ""
@get:Bindable
var stateManagerProgress = 0
set(value) = set(value, field, { field = it }, BR.stateManagerProgress)
val extraBindings = bindExtra {
it.put(BR.viewModel, this)
}
companion object {
private var checkedEnv = false
}
override suspend fun doLoadWork() {
appState = State.LOADING
Info.fetchUpdate(svc)?.apply {
appState = when {
BuildConfig.APP_VERSION_CODE < versionCode -> State.OUTDATED
else -> State.UP_TO_DATE
}
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
managerRemoteVersion =
("$version (${versionCode})" + if (isDebug) " (D)" else "").asText()
} ?: run {
appState = State.INVALID
managerRemoteVersion = CoreR.string.not_available.asText()
}
ensureEnv()
}
override fun onNetworkChanged(network: Boolean) = startLoading()
fun onProgressUpdate(progress: Float, subject: Subject) {
if (subject is App)
stateManagerProgress = progress.times(100f).roundToInt()
}
fun onLinkPressed(link: String) = object : ViewEvent(), ContextExecutor {
override fun invoke(context: Context) {
val intent = Intent(Intent.ACTION_VIEW, link.toUri())
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
context.toast(CoreR.string.open_link_failed_toast, Toast.LENGTH_SHORT)
}
}
}.publish()
fun onDeletePressed() = UninstallDialog().show()
fun onManagerPressed() = when (appState) {
State.LOADING -> SnackbarEvent(CoreR.string.loading).publish()
State.INVALID -> SnackbarEvent(CoreR.string.no_connection).publish()
else -> withExternalRW {
withInstallPermission {
ManagerInstallDialog().show()
}
}
}
fun onMagiskPressed() = withExternalRW {
HomeFragmentDirections.actionHomeFragmentToInstallFragment().navigate()
}
fun hideNotice() {
Config.safetyNotice = false
isNoticeVisible = false
}
private suspend fun ensureEnv() {
if (magiskState == State.INVALID || checkedEnv) return
val cmd = "env_check ${Info.env.versionString} ${Info.env.versionCode}"
val code = Shell.cmd(cmd).await().code
if (code != 0) {
EnvFixDialog(this, code).show()
}
checkedEnv = true
}
val showTest = false
fun onTestPressed() = object : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
/* Entry point to trigger test events within the app */
}
}.publish()
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/home/RebootMenu.kt
================================================
package com.topjohnwu.magisk.ui.home
import android.app.Activity
import android.os.Build
import android.os.PowerManager
import android.view.ContextThemeWrapper
import android.view.MenuItem
import android.widget.PopupMenu
import androidx.core.content.getSystemService
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.ktx.reboot as systemReboot
object RebootMenu {
private fun reboot(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_reboot_normal -> systemReboot()
R.id.action_reboot_userspace -> systemReboot("userspace")
R.id.action_reboot_bootloader -> systemReboot("bootloader")
R.id.action_reboot_download -> systemReboot("download")
R.id.action_reboot_edl -> systemReboot("edl")
R.id.action_reboot_recovery -> systemReboot("recovery")
R.id.action_reboot_safe_mode -> {
val status = !item.isChecked
item.isChecked = status
Config.bootloop = if (status) 2 else 0
}
else -> Unit
}
return true
}
fun inflate(activity: Activity): PopupMenu {
val themeWrapper = ContextThemeWrapper(activity, R.style.Foundation_PopupMenu)
val menu = PopupMenu(themeWrapper, activity.findViewById(R.id.action_reboot))
activity.menuInflater.inflate(R.menu.menu_reboot, menu.menu)
menu.setOnMenuItemClickListener(RebootMenu::reboot)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
activity.getSystemService<PowerManager>()?.isRebootingUserspaceSupported == true) {
menu.menu.findItem(R.id.action_reboot_userspace).isVisible = true
}
if (Const.Version.atLeast_28_0()) {
menu.menu.findItem(R.id.action_reboot_safe_mode).isChecked = Config.bootloop >= 2
} else {
menu.menu.findItem(R.id.action_reboot_safe_mode).isVisible = false
}
return menu
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt
================================================
package com.topjohnwu.magisk.ui.install
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
import com.topjohnwu.magisk.core.R as CoreR
class InstallFragment : BaseFragment<FragmentInstallMd2Binding>() {
override val layoutRes = R.layout.fragment_install_md2
override val viewModel by viewModel<InstallViewModel>()
override fun onStart() {
super.onStart()
requireActivity().setTitle(CoreR.string.install)
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt
================================================
package com.topjohnwu.magisk.ui.install
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.text.Spanned
import android.text.SpannedString
import android.widget.Toast
import androidx.databinding.Bindable
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.ContentResultCallback
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.repository.NetworkService
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.dialog.SecondSlotWarningDialog
import com.topjohnwu.magisk.events.GetContentEvent
import com.topjohnwu.magisk.ui.flash.FlashFragment
import io.noties.markwon.Markwon
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import timber.log.Timber
import java.io.File
import java.io.IOException
import com.topjohnwu.magisk.core.R as CoreR
class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel() {
val isRooted get() = Info.isRooted
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && Info.ramdisk)
val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator
@get:Bindable
var step = if (skipOptions) 1 else 0
set(value) = set(value, field, { field = it }, BR.step)
private var methodId = -1
@get:Bindable
var method
get() = methodId
set(value) = set(value, methodId, { methodId = it }, BR.method) {
when (it) {
R.id.method_patch -> {
GetContentEvent("*/*", UriCallback()).publish()
}
R.id.method_inactive_slot -> {
SecondSlotWarningDialog().show()
}
}
}
val data: LiveData<Uri?> get() = uri
@get:Bindable
var notes: Spanned = SpannedString("")
set(value) = set(value, field, { field = it }, BR.notes)
init {
viewModelScope.launch(Dispatchers.IO) {
try {
val noteFile = File(AppContext.cacheDir, "${APP_VERSION_CODE}.md")
val noteText = when {
noteFile.exists() -> noteFile.readText()
else -> {
val note = svc.fetchUpdate(APP_VERSION_CODE)?.note.orEmpty()
if (note.isEmpty()) return@launch
noteFile.writeText(note)
note
}
}
val spanned = markwon.toMarkdown(noteText)
withContext(Dispatchers.Main) {
notes = spanned
}
} catch (e: IOException) {
Timber.e(e)
}
}
}
fun install() {
when (method) {
R.id.method_patch -> FlashFragment.patch(data.value!!).navigate(true)
R.id.method_direct -> FlashFragment.flash(false).navigate(true)
R.id.method_inactive_slot -> FlashFragment.flash(true).navigate(true)
else -> error("Unknown value")
}
}
override fun onSaveState(state: Bundle) {
state.putParcelable(
INSTALL_STATE_KEY, InstallState(
methodId,
step,
Config.keepVerity,
Config.keepEnc,
Config.recovery
)
)
}
override fun onRestoreState(state: Bundle) {
state.getParcelable<InstallState>(INSTALL_STATE_KEY)?.let {
methodId = it.method
step = it.step
Config.keepVerity = it.keepVerity
Config.keepEnc = it.keepEnc
Config.recovery = it.recovery
}
}
@Parcelize
class UriCallback : ContentResultCallback {
override fun onActivityLaunch() {
AppContext.toast(CoreR.string.patch_file_msg, Toast.LENGTH_LONG)
}
override fun onActivityResult(result: Uri) {
uri.value = result
}
}
@Parcelize
class InstallState(
val method: Int,
val step: Int,
val keepVerity: Boolean,
val keepEnc: Boolean,
val recovery: Boolean,
) : Parcelable
companion object {
private const val INSTALL_STATE_KEY = "install_state"
private val uri = MutableLiveData<Uri?>()
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.kt
================================================
package com.topjohnwu.magisk.ui.log
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.widget.HorizontalScrollView
import androidx.core.view.MenuProvider
import androidx.core.view.isVisible
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.AccessibilityUtils
import com.topjohnwu.magisk.utils.MotionRevealHelper
import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addItemSpacing
import rikka.recyclerview.fixEdgeEffect
import com.topjohnwu.magisk.core.R as CoreR
class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider {
override val layoutRes = R.layout.fragment_log_md2
override val viewModel by viewModel<LogViewModel>()
override val snackbarView: View?
get() = if (isMagiskLogVisible) binding.logFilterSuperuser.snackbarContainer
else super.snackbarView
override val snackbarAnchorView get() = binding.logFilterToggle
private var actionSave: MenuItem? = null
private var isMagiskLogVisible
get() = binding.logFilter.isVisible
set(value) {
MotionRevealHelper.withViews(binding.logFilter, binding.logFilterToggle, value)
actionSave?.isVisible = !value
with(activity as MainActivity) {
invalidateToolbar()
requestNavigationHidden(value)
setDisplayHomeAsUpEnabled(value)
}
}
override fun onStart() {
super.onStart()
activity?.setTitle(CoreR.string.logs)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.logFilterToggle.setOnClickListener {
isMagiskLogVisible = true
}
binding.logFilterSuperuser.logSuperuser.apply {
addEdgeSpacing(bottom = R.dimen.l1)
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
fixEdgeEffect()
}
if (!AccessibilityUtils.isAnimationEnabled(requireContext().contentResolver)) {
val scrollView = view.findViewById<HorizontalScrollView>(R.id.log_scroll_magisk)
scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER)
}
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_log_md2, menu)
actionSave = menu.findItem(R.id.action_save)?.also {
it.isVisible = !isMagiskLogVisible
}
}
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_save -> viewModel.saveMagiskLog()
R.id.action_clear ->
if (!isMagiskLogVisible) viewModel.clearMagiskLog()
else viewModel.clearLog()
}
return super.onOptionsItemSelected(item)
}
override fun onPreBind(binding: FragmentLogMd2Binding) = Unit
override fun onBackPressed(): Boolean {
if (binding.logFilter.isVisible) {
isMagiskLogVisible = false
return true
}
return super.onBackPressed()
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/log/LogRvItem.kt
================================================
package com.topjohnwu.magisk.ui.log
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textview.MaterialTextView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.ViewAwareItem
class LogRvItem(
override val item: String
) : ObservableRvItem(), DiffItem<LogRvItem>, ItemWrapper<String>, ViewAwareItem {
override val layoutRes = R.layout.item_log_textview
override fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView) {
val view = binding.root as MaterialTextView
view.measure(0, 0)
val desiredWidth = view.measuredWidth
val layoutParams = view.layoutParams
layoutParams.width = desiredWidth
if (recyclerView.width < desiredWidth) {
recyclerView.requestLayout()
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt
================================================
package com.topjohnwu.magisk.ui.log
import android.system.Os
import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.ktx.timeFormatStandard
import com.topjohnwu.magisk.core.ktx.toTime
import com.topjohnwu.magisk.core.repository.LogRepository
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.diffList
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.view.TextItem
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.FileInputStream
class LogViewModel(
private val repo: LogRepository
) : AsyncLoadViewModel() {
@get:Bindable
var loading = true
private set(value) = set(value, field, { field = it }, BR.loading)
// --- empty view
val itemEmpty = TextItem(R.string.log_data_none)
val itemMagiskEmpty = TextItem(R.string.log_data_magisk_none)
// --- su log
val items = diffList<SuLogRvItem>()
val extraBindings = bindExtra {
it.put(BR.viewModel, this)
}
// --- magisk log
val logs = diffList<LogRvItem>()
var magiskLogRaw = " "
override suspend fun doLoadWork() {
loading = true
val (suLogs, suDiff) = withContext(Dispatchers.Default) {
magiskLogRaw = repo.fetchMagiskLogs()
val newLogs = magiskLogRaw.split('\n').map { LogRvItem(it) }
logs.update(newLogs)
val suLogs = repo.fetchSuLogs().map { SuLogRvItem(it) }
suLogs to items.calculateDiff(suLogs)
}
items.firstOrNull()?.isTop = false
items.lastOrNull()?.isBottom = false
items.update(suLogs, suDiff)
items.firstOrNull()?.isTop = true
items.lastOrNull()?.isBottom = true
loading = false
}
fun saveMagiskLog() = withExternalRW {
viewModelScope.launch(Dispatchers.IO) {
val filename = "magisk_log_%s.log".format(
System.currentTimeMillis().toTime(timeFormatStandard))
val logFile = MediaStoreUtils.getFile(filename)
logFile.uri.outputStream().bufferedWriter().use { file ->
file.write("---Detected Device Info---\n\n")
file.write("isAB=${Info.isAB}\n")
file.write("isSAR=${Info.isSAR}\n")
file.write("ramdisk=${Info.ramdisk}\n")
val uname = Os.uname()
file.write("kernel=${uname.sysname} ${uname.machine} ${uname.release} ${uname.version}\n")
file.write("\n\n---System Properties---\n\n")
ProcessBuilder("getprop").start()
.inputStream.reader().use { it.copyTo(file) }
file.write("\n\n---Environment Variables---\n\n")
System.getenv().forEach { (key, value) -> file.write("${key}=${value}\n") }
file.write("\n\n---System MountInfo---\n\n")
FileInputStream("/proc/self/mountinfo").reader().use { it.copyTo(file) }
file.write("\n---Magisk Logs---\n")
file.write("${Info.env.versionString} (${Info.env.versionCode})\n\n")
if (Info.env.isActive) file.write(magiskLogRaw)
file.write("\n---Manager Logs---\n")
file.write("${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})\n\n")
ProcessBuilder("logcat", "-d").start()
.inputStream.reader().use { it.copyTo(file) }
}
SnackbarEvent(logFile.toString()).publish()
}
}
fun clearMagiskLog() = repo.clearMagiskLogs {
SnackbarEvent(R.string.logs_cleared).publish()
startLoading()
}
fun clearLog() = viewModelScope.launch {
repo.clearLogs()
SnackbarEvent(R.string.logs_cleared).publish()
startLoading()
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/log/SuLogRvItem.kt
================================================
package com.topjohnwu.magisk.ui.log
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.ktx.timeDateFormat
import com.topjohnwu.magisk.core.ktx.toTime
import com.topjohnwu.magisk.core.model.su.SuLog
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.core.R as CoreR
class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
override val layoutRes = R.layout.item_log_access_md2
val info = genInfo()
@get:Bindable
var isTop = false
set(value) = set(value, field, { field = it }, BR.top)
@get:Bindable
var isBottom = false
set(value) = set(value, field, { field = it }, BR.bottom)
override fun itemSameAs(other: SuLogRvItem) = log.appName == other.log.appName
private fun genInfo(): String {
val res = AppContext.resources
val sb = StringBuilder()
val date = log.time.toTime(timeDateFormat)
val toUid = res.getString(CoreR.string.target_uid, log.toUid)
val fromPid = res.getString(CoreR.string.pid, log.fromPid)
sb.append("$date\n$toUid $fromPid")
if (log.target != -1) {
val pid = if (log.target == 0) "magiskd" else log.target.toString()
val target = res.getString(CoreR.string.target_pid, pid)
sb.append(" $target")
}
if (log.context.isNotEmpty()) {
val context = res.getString(CoreR.string.selinux_context, log.context)
sb.append("\n$context")
}
if (log.gids.isNotEmpty()) {
val gids = res.getString(CoreR.string.supp_group, log.gids)
sb.append("\n$gids")
}
sb.append("\n${log.command}")
return sb.toString()
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ActionFragment.kt
================================================
package com.topjohnwu.magisk.ui.module
import android.annotation.SuppressLint
import android.content.pm.ActivityInfo
import android.os.Bundle
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewTreeObserver
import android.widget.Toast
import androidx.core.view.MenuProvider
import androidx.core.view.isVisible
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.databinding.FragmentActionMd2Binding
import com.topjohnwu.magisk.core.R as CoreR
class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider {
override val layoutRes = R.layout.fragment_action_md2
override val viewModel by viewModel<ActionViewModel>()
override val snackbarView: View get() = binding.snackbarContainer
private var defaultOrientation = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.args = ActionFragmentArgs.fromBundle(requireArguments())
}
override fun onStart() {
super.onStart()
activity?.setTitle(viewModel.args.name)
binding.closeBtn.setOnClickListener {
activity?.onBackPressed()
}
viewModel.state.observe(this) {
if (it != ActionViewModel.State.RUNNING) {
binding.closeBtn.apply {
if (!this.isVisible) this.show()
if (!this.isFocused) this.requestFocus()
}
}
if (it != ActionViewModel.State.SUCCESS) return@observe
view?.viewTreeObserver?.addOnWindowFocusChangeListener(
object : ViewTreeObserver.OnWindowFocusChangeListener {
override fun onWindowFocusChanged(hasFocus: Boolean) {
if (hasFocus) return
view?.viewTreeObserver?.removeOnWindowFocusChangeListener(this)
view?.context?.apply {
toast(
getString(CoreR.string.done_action, viewModel.args.name),
Toast.LENGTH_SHORT
)
}
viewModel.back()
}
}
)
}
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_flash, menu)
}
override fun onMenuItemSelected(item: MenuItem): Boolean {
return viewModel.onMenuItemClicked(item)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
defaultOrientation = activity?.requestedOrientation ?: -1
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
if (savedInstanceState == null) {
viewModel.startRunAction()
}
}
@SuppressLint("WrongConstant")
override fun onDestroyView() {
if (defaultOrientation != -1) {
activity?.requestedOrientation = defaultOrientation
}
super.onDestroyView()
}
override fun onKeyEvent(event: KeyEvent): Boolean {
return when (event.keyCode) {
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> true
else -> false
}
}
override fun onBackPressed(): Boolean {
if (viewModel.state.value == ActionViewModel.State.RUNNING) return true
return super.onBackPressed()
}
override fun onPreBind(binding: FragmentActionMd2Binding) = Unit
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ActionViewModel.kt
================================================
package com.topjohnwu.magisk.ui.module
import android.view.MenuItem
import androidx.databinding.ObservableArrayList
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.ktx.synchronized
import com.topjohnwu.magisk.core.ktx.timeFormatStandard
import com.topjohnwu.magisk.core.ktx.toTime
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.ui.flash.ConsoleItem
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.IOException
class ActionViewModel : BaseViewModel() {
enum class State {
RUNNING, SUCCESS, FAILED
}
private val _state = MutableLiveData(State.RUNNING)
val state: LiveData<State> get() = _state
val items = ObservableArrayList<ConsoleItem>()
lateinit var args: ActionFragmentArgs
private val logItems = mutableListOf<String>().synchronized()
private val outItems = object : CallbackList<String>() {
override fun onAddElement(e: String?) {
e ?: return
items.add(ConsoleItem(e))
logItems.add(e)
}
}
fun startRunAction() = viewModelScope.launch {
onResult(withContext(Dispatchers.IO) {
try {
Shell.cmd("run_action \'${args.id}\'")
.to(outItems, logItems)
.exec().isSuccess
} catch (e: IOException) {
Timber.e(e)
false
}
})
}
private fun onResult(success: Boolean) {
_state.value = if (success) State.SUCCESS else State.FAILED
}
fun onMenuItemClicked(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_save -> savePressed()
}
return true
}
private fun savePressed() = withExternalRW {
viewModelScope.launch(Dispatchers.IO) {
val name = "%s_action_log_%s.log".format(
args.name,
System.currentTimeMillis().toTime(timeFormatStandard)
)
val file = MediaStoreUtils.getFile(name)
file.uri.outputStream().bufferedWriter().use { writer ->
synchronized(logItems) {
logItems.forEach {
writer.write(it)
writer.newLine()
}
}
}
SnackbarEvent(file.toString()).publish()
}
}
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt
================================================
package com.topjohnwu.magisk.ui.module
import android.os.Bundle
import android.view.View
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseFragment
import com.topjohnwu.magisk.arch.viewModel
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.displayName
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import rikka.recyclerview.addEdgeSpacing
import rikka.recyclerview.addInvalidateItemDecorationsObserver
import rikka.recyclerview.addItemSpacing
import rikka.recyclerview.fixEdgeEffect
import com.topjohnwu.magisk.core.R as CoreR
class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
override val layoutRes = R.layout.fragment_module_md2
override val viewModel by viewModel<ModuleViewModel>()
override fun onStart() {
super.onStart()
activity?.title = resources.getString(CoreR.string.modules)
viewModel.data.observe(this) {
it ?: return@observe
val displayName = runCatching { it.displayName }.getOrNull() ?: return@observe
viewModel.requestInstallLocalModule(it, displayName)
viewModel.data.value = null
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.moduleList.apply {
addEdgeSpacing(top = R.dimen.l_50, bottom = R.dimen.l1)
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
fixEdgeEffect()
post { addInvalidateItemDecorationsObserver() }
}
}
override fun onPreBind(binding: FragmentModuleMd2Binding) = Unit
}
================================================
FILE: app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ModuleRvItem.kt
================================================
package com.topjohnwu.magisk.ui.module
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.module.LocalModule
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.magisk.core.R as CoreR
object InstallModule : RvItem(), DiffItem<InstallModule> {
override val layoutRes = R.layout.item_module_download
}
class LocalModuleRvItem(
override val item: LocalModule
) : ObservableRvItem(), DiffItem<LocalModuleRvItem>, ItemWrapper<LocalModule> {
override val layoutRes = R.layout.item_module_md2
val showNotice: Boolean
val showAction: Boolean
val noticeText: TextHolder
init {
val isZygisk = item.isZygisk
val isRiru = item.isRiru
val zygiskUnloaded = isZygisk && item.zygiskUnloaded
showNotice = zygiskUnloaded ||
(Info.isZygiskEnabled && isRiru) ||
(!Info.isZygiskEnabled && isZygisk)
showAction = item.hasAction && !showNotice
noticeText =
when {
zygiskUnloaded -> CoreR.string.zygisk_module_unloaded.asText()
isRiru -> CoreR.string.suspend_text_riru.asText(CoreR.string.zygisk.asText())
else -> CoreR.string.suspend_text_zygisk.asText(CoreR.string.zygisk.asText())
}
}
@get:Bindable
var isEnabled = item.enable
set(value) = set(value, field, { field = it }, BR.enabled, BR.updateReady) {
item.enable = value
}
@get:Bindable
var isRemoved = item.remove
set(value) = set(value, field, { field = it }, BR.removed, BR.updateReady) {
item.remove = value
}
@get:Bindable
val showUpdate get() = item.updateInfo != null
@get:Bindable
val updateReady get() = item.outdated && !isRemoved && isEnabled
val isUpdated = item.updated
fun fetchedUpdateInfo() {
notifyPropertyChanged(BR.showUpdate)
notifyPropertyChanged(BR.updateReady)
}
fun delete() {
gitextract_zn19wufn/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── config.yml
│ ├── actions/
│ │ └── setup/
│ │ ├── action.yml
│ │ └── sccache.sh
│ ├── ci.prop
│ ├── kvm.sh
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.MD
├── app/
│ ├── .gitignore
│ ├── apk/
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── arch/
│ │ │ │ ├── AsyncLoadViewModel.kt
│ │ │ │ ├── BaseFragment.kt
│ │ │ │ ├── BaseViewModel.kt
│ │ │ │ ├── NavigationActivity.kt
│ │ │ │ ├── UIActivity.kt
│ │ │ │ ├── ViewEvent.kt
│ │ │ │ └── ViewModelHolder.kt
│ │ │ ├── databinding/
│ │ │ │ ├── DataBindingAdapters.kt
│ │ │ │ ├── DiffObservableList.kt
│ │ │ │ ├── MergeObservableList.kt
│ │ │ │ ├── ObservableHost.kt
│ │ │ │ ├── RecyclerViewItems.kt
│ │ │ │ └── RvItemAdapter.kt
│ │ │ ├── dialog/
│ │ │ │ ├── DarkThemeDialog.kt
│ │ │ │ ├── EnvFixDialog.kt
│ │ │ │ ├── LocalModuleInstallDialog.kt
│ │ │ │ ├── ManagerInstallDialog.kt
│ │ │ │ ├── MarkDownDialog.kt
│ │ │ │ ├── OnlineModuleInstallDialog.kt
│ │ │ │ ├── SecondSlotWarningDialog.kt
│ │ │ │ ├── SuperuserRevokeDialog.kt
│ │ │ │ └── UninstallDialog.kt
│ │ │ ├── events/
│ │ │ │ └── ViewEvents.kt
│ │ │ ├── ui/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── deny/
│ │ │ │ │ ├── AppProcessInfo.kt
│ │ │ │ │ ├── DenyListFragment.kt
│ │ │ │ │ ├── DenyListRvItem.kt
│ │ │ │ │ └── DenyListViewModel.kt
│ │ │ │ ├── flash/
│ │ │ │ │ ├── ConsoleItem.kt
│ │ │ │ │ ├── FlashFragment.kt
│ │ │ │ │ └── FlashViewModel.kt
│ │ │ │ ├── home/
│ │ │ │ │ ├── DeveloperItem.kt
│ │ │ │ │ ├── HomeFragment.kt
│ │ │ │ │ ├── HomeViewModel.kt
│ │ │ │ │ └── RebootMenu.kt
│ │ │ │ ├── install/
│ │ │ │ │ ├── InstallFragment.kt
│ │ │ │ │ └── InstallViewModel.kt
│ │ │ │ ├── log/
│ │ │ │ │ ├── LogFragment.kt
│ │ │ │ │ ├── LogRvItem.kt
│ │ │ │ │ ├── LogViewModel.kt
│ │ │ │ │ └── SuLogRvItem.kt
│ │ │ │ ├── module/
│ │ │ │ │ ├── ActionFragment.kt
│ │ │ │ │ ├── ActionViewModel.kt
│ │ │ │ │ ├── ModuleFragment.kt
│ │ │ │ │ ├── ModuleRvItem.kt
│ │ │ │ │ └── ModuleViewModel.kt
│ │ │ │ ├── settings/
│ │ │ │ │ ├── BaseSettingsItem.kt
│ │ │ │ │ ├── SettingsFragment.kt
│ │ │ │ │ ├── SettingsItems.kt
│ │ │ │ │ └── SettingsViewModel.kt
│ │ │ │ ├── superuser/
│ │ │ │ │ ├── PolicyRvItem.kt
│ │ │ │ │ ├── SuperuserFragment.kt
│ │ │ │ │ └── SuperuserViewModel.kt
│ │ │ │ ├── surequest/
│ │ │ │ │ ├── SuRequestActivity.kt
│ │ │ │ │ └── SuRequestViewModel.kt
│ │ │ │ └── theme/
│ │ │ │ ├── Theme.kt
│ │ │ │ ├── ThemeFragment.kt
│ │ │ │ └── ThemeViewModel.kt
│ │ │ ├── utils/
│ │ │ │ ├── AccessibilityUtils.kt
│ │ │ │ ├── MotionRevealHelper.kt
│ │ │ │ └── TextHolder.kt
│ │ │ ├── view/
│ │ │ │ ├── MagiskDialog.kt
│ │ │ │ ├── TappableHeadlineItem.kt
│ │ │ │ └── TextItem.kt
│ │ │ └── widget/
│ │ │ └── ConcealableBottomNavigationView.java
│ │ └── res/
│ │ ├── anim/
│ │ │ ├── fragment_enter.xml
│ │ │ ├── fragment_enter_pop.xml
│ │ │ ├── fragment_exit.xml
│ │ │ └── fragment_exit_pop.xml
│ │ ├── color/
│ │ │ ├── color_card_background_color_selector.xml
│ │ │ ├── color_error_transient.xml
│ │ │ ├── color_menu_tint.xml
│ │ │ ├── color_on_primary_transient.xml
│ │ │ ├── color_primary_error_transient.xml
│ │ │ ├── color_primary_transient.xml
│ │ │ ├── color_state_primary_transient.xml
│ │ │ └── color_text_transient.xml
│ │ ├── drawable/
│ │ │ ├── avd_bug_from_filled.xml
│ │ │ ├── avd_bug_to_filled.xml
│ │ │ ├── avd_circle_check_from_filled.xml
│ │ │ ├── avd_circle_check_to_filled.xml
│ │ │ ├── avd_home_from_filled.xml
│ │ │ ├── avd_home_to_filled.xml
│ │ │ ├── avd_module_from_filled.xml
│ │ │ ├── avd_module_to_filled.xml
│ │ │ ├── avd_settings_from_filled.xml
│ │ │ ├── avd_settings_to_filled.xml
│ │ │ ├── avd_superuser_from_filled.xml
│ │ │ ├── avd_superuser_to_filled.xml
│ │ │ ├── bg_line_bottom_rounded.xml
│ │ │ ├── bg_line_top_rounded.xml
│ │ │ ├── bg_selection_circle_green.xml
│ │ │ ├── ic_action_md2.xml
│ │ │ ├── ic_back_md2.xml
│ │ │ ├── ic_bug_filled_md2.xml
│ │ │ ├── ic_bug_md2.xml
│ │ │ ├── ic_bug_outlined_md2.xml
│ │ │ ├── ic_check_circle_checked_md2.xml
│ │ │ ├── ic_check_circle_md2.xml
│ │ │ ├── ic_check_circle_unchecked_md2.xml
│ │ │ ├── ic_check_md2.xml
│ │ │ ├── ic_close_md2.xml
│ │ │ ├── ic_day.xml
│ │ │ ├── ic_day_night.xml
│ │ │ ├── ic_delete_md2.xml
│ │ │ ├── ic_download_md2.xml
│ │ │ ├── ic_folder_list.xml
│ │ │ ├── ic_forth_md2.xml
│ │ │ ├── ic_home_filled_md2.xml
│ │ │ ├── ic_home_md2.xml
│ │ │ ├── ic_home_outlined_md2.xml
│ │ │ ├── ic_install.xml
│ │ │ ├── ic_manager.xml
│ │ │ ├── ic_module_filled_md2.xml
│ │ │ ├── ic_module_md2.xml
│ │ │ ├── ic_module_outlined_md2.xml
│ │ │ ├── ic_module_storage_md2.xml
│ │ │ ├── ic_night.xml
│ │ │ ├── ic_notifications_md2.xml
│ │ │ ├── ic_paint.xml
│ │ │ ├── ic_restart.xml
│ │ │ ├── ic_save_md2.xml
│ │ │ ├── ic_search_md2.xml
│ │ │ ├── ic_settings_filled_md2.xml
│ │ │ ├── ic_settings_md2.xml
│ │ │ ├── ic_settings_outlined_md2.xml
│ │ │ ├── ic_superuser_filled_md2.xml
│ │ │ ├── ic_superuser_md2.xml
│ │ │ ├── ic_superuser_outlined_md2.xml
│ │ │ └── ic_update_md2.xml
│ │ ├── layout/
│ │ │ ├── activity_main_md2.xml
│ │ │ ├── activity_request.xml
│ │ │ ├── dialog_magisk_base.xml
│ │ │ ├── dialog_settings_app_name.xml
│ │ │ ├── dialog_settings_download_path.xml
│ │ │ ├── dialog_settings_update_channel.xml
│ │ │ ├── fragment_action_md2.xml
│ │ │ ├── fragment_deny_md2.xml
│ │ │ ├── fragment_flash_md2.xml
│ │ │ ├── fragment_home_md2.xml
│ │ │ ├── fragment_install_md2.xml
│ │ │ ├── fragment_log_md2.xml
│ │ │ ├── fragment_module_md2.xml
│ │ │ ├── fragment_settings_md2.xml
│ │ │ ├── fragment_superuser_md2.xml
│ │ │ ├── fragment_theme_md2.xml
│ │ │ ├── include_home_magisk.xml
│ │ │ ├── include_home_manager.xml
│ │ │ ├── include_log_magisk.xml
│ │ │ ├── include_log_superuser.xml
│ │ │ ├── item_console_md2.xml
│ │ │ ├── item_developer.xml
│ │ │ ├── item_hide_md2.xml
│ │ │ ├── item_hide_process_md2.xml
│ │ │ ├── item_icon_link.xml
│ │ │ ├── item_list_single_line.xml
│ │ │ ├── item_log_access_md2.xml
│ │ │ ├── item_log_textview.xml
│ │ │ ├── item_log_track_md2.xml
│ │ │ ├── item_module_download.xml
│ │ │ ├── item_module_md2.xml
│ │ │ ├── item_policy_md2.xml
│ │ │ ├── item_settings.xml
│ │ │ ├── item_settings_section.xml
│ │ │ ├── item_spinner.xml
│ │ │ ├── item_tappable_headline.xml
│ │ │ ├── item_text.xml
│ │ │ ├── item_theme.xml
│ │ │ ├── item_theme_container.xml
│ │ │ └── markdown_window_md2.xml
│ │ ├── menu/
│ │ │ ├── menu_bottom_nav.xml
│ │ │ ├── menu_deny_md2.xml
│ │ │ ├── menu_flash.xml
│ │ │ ├── menu_home_md2.xml
│ │ │ ├── menu_log_md2.xml
│ │ │ └── menu_reboot.xml
│ │ ├── navigation/
│ │ │ └── main.xml
│ │ ├── values/
│ │ │ ├── attrs.xml
│ │ │ ├── dimens.xml
│ │ │ ├── ids.xml
│ │ │ ├── styles_md2.xml
│ │ │ ├── styles_md2_appearance.xml
│ │ │ ├── styles_md2_impl.xml
│ │ │ ├── styles_view_md2.xml
│ │ │ ├── theme_overlay.xml
│ │ │ ├── themes.xml
│ │ │ ├── themes_md2.xml
│ │ │ └── themes_override.xml
│ │ ├── values-night/
│ │ │ ├── styles_md2.xml
│ │ │ └── themes_md2.xml
│ │ └── values-v27/
│ │ └── themes.xml
│ ├── apk-ng/
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── arch/
│ │ │ │ ├── AsyncLoadViewModel.kt
│ │ │ │ ├── BaseViewModel.kt
│ │ │ │ └── ViewModelFactory.kt
│ │ │ ├── terminal/
│ │ │ │ ├── TerminalBuffer.kt
│ │ │ │ ├── TerminalEmulator.kt
│ │ │ │ ├── TerminalProcess.kt
│ │ │ │ ├── TerminalRow.kt
│ │ │ │ ├── TerminalStyle.kt
│ │ │ │ └── WcWidth.kt
│ │ │ ├── ui/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── MainScreen.kt
│ │ │ │ ├── component/
│ │ │ │ │ ├── Dialog.kt
│ │ │ │ │ └── MenuPositionProvider.kt
│ │ │ │ ├── deny/
│ │ │ │ │ ├── AppProcessInfo.kt
│ │ │ │ │ ├── DenyListScreen.kt
│ │ │ │ │ └── DenyListViewModel.kt
│ │ │ │ ├── flash/
│ │ │ │ │ ├── FlashScreen.kt
│ │ │ │ │ ├── FlashUtils.kt
│ │ │ │ │ └── FlashViewModel.kt
│ │ │ │ ├── home/
│ │ │ │ │ ├── HomeScreen.kt
│ │ │ │ │ └── HomeViewModel.kt
│ │ │ │ ├── install/
│ │ │ │ │ └── InstallViewModel.kt
│ │ │ │ ├── log/
│ │ │ │ │ ├── LogScreen.kt
│ │ │ │ │ ├── LogViewModel.kt
│ │ │ │ │ └── MagiskLogParser.kt
│ │ │ │ ├── module/
│ │ │ │ │ ├── ActionScreen.kt
│ │ │ │ │ ├── ActionViewModel.kt
│ │ │ │ │ ├── ModuleScreen.kt
│ │ │ │ │ └── ModuleViewModel.kt
│ │ │ │ ├── navigation/
│ │ │ │ │ ├── CollectNavEvents.kt
│ │ │ │ │ ├── Navigator.kt
│ │ │ │ │ └── Routes.kt
│ │ │ │ ├── settings/
│ │ │ │ │ ├── SettingsScreen.kt
│ │ │ │ │ └── SettingsViewModel.kt
│ │ │ │ ├── superuser/
│ │ │ │ │ ├── SuperuserDetailScreen.kt
│ │ │ │ │ ├── SuperuserScreen.kt
│ │ │ │ │ └── SuperuserViewModel.kt
│ │ │ │ ├── surequest/
│ │ │ │ │ ├── SuRequestActivity.kt
│ │ │ │ │ ├── SuRequestScreen.kt
│ │ │ │ │ └── SuRequestViewModel.kt
│ │ │ │ ├── terminal/
│ │ │ │ │ ├── TerminalRenderer.kt
│ │ │ │ │ └── TerminalScreen.kt
│ │ │ │ ├── theme/
│ │ │ │ │ ├── MagiskTheme.kt
│ │ │ │ │ └── Theme.kt
│ │ │ │ └── util/
│ │ │ │ └── DrawablePainter.kt
│ │ │ └── utils/
│ │ │ └── AccessibilityUtils.kt
│ │ └── res/
│ │ ├── color/
│ │ │ ├── color_card_background_color_selector.xml
│ │ │ ├── color_error_transient.xml
│ │ │ ├── color_menu_tint.xml
│ │ │ ├── color_on_primary_transient.xml
│ │ │ ├── color_primary_error_transient.xml
│ │ │ ├── color_primary_transient.xml
│ │ │ ├── color_state_primary_transient.xml
│ │ │ └── color_text_transient.xml
│ │ ├── drawable/
│ │ │ ├── avd_bug_from_filled.xml
│ │ │ ├── avd_bug_to_filled.xml
│ │ │ ├── avd_circle_check_from_filled.xml
│ │ │ ├── avd_circle_check_to_filled.xml
│ │ │ ├── avd_home_from_filled.xml
│ │ │ ├── avd_home_to_filled.xml
│ │ │ ├── avd_module_from_filled.xml
│ │ │ ├── avd_module_to_filled.xml
│ │ │ ├── avd_settings_from_filled.xml
│ │ │ ├── avd_settings_to_filled.xml
│ │ │ ├── avd_superuser_from_filled.xml
│ │ │ ├── avd_superuser_to_filled.xml
│ │ │ ├── ic_bug_filled_md2.xml
│ │ │ ├── ic_bug_md2.xml
│ │ │ ├── ic_bug_outlined_md2.xml
│ │ │ ├── ic_check_circle_checked_md2.xml
│ │ │ ├── ic_check_circle_md2.xml
│ │ │ ├── ic_check_circle_unchecked_md2.xml
│ │ │ ├── ic_check_md2.xml
│ │ │ ├── ic_delete_md2.xml
│ │ │ ├── ic_download_md2.xml
│ │ │ ├── ic_home_filled_md2.xml
│ │ │ ├── ic_home_md2.xml
│ │ │ ├── ic_home_outlined_md2.xml
│ │ │ ├── ic_install.xml
│ │ │ ├── ic_manager.xml
│ │ │ ├── ic_module_filled_md2.xml
│ │ │ ├── ic_module_md2.xml
│ │ │ ├── ic_module_outlined_md2.xml
│ │ │ ├── ic_module_storage_md2.xml
│ │ │ ├── ic_notifications_md2.xml
│ │ │ ├── ic_restart.xml
│ │ │ ├── ic_save_md2.xml
│ │ │ ├── ic_search_md2.xml
│ │ │ ├── ic_settings_filled_md2.xml
│ │ │ ├── ic_settings_md2.xml
│ │ │ ├── ic_settings_outlined_md2.xml
│ │ │ ├── ic_superuser_filled_md2.xml
│ │ │ ├── ic_superuser_md2.xml
│ │ │ ├── ic_superuser_outlined_md2.xml
│ │ │ └── ic_update_md2.xml
│ │ ├── values/
│ │ │ ├── attrs.xml
│ │ │ ├── dimens.xml
│ │ │ ├── styles_md2.xml
│ │ │ ├── styles_md2_appearance.xml
│ │ │ ├── styles_md2_impl.xml
│ │ │ ├── themes.xml
│ │ │ ├── themes_md2.xml
│ │ │ └── themes_override.xml
│ │ ├── values-night/
│ │ │ ├── styles_md2.xml
│ │ │ └── themes_md2.xml
│ │ └── values-v27/
│ │ └── themes.xml
│ ├── build.gradle.kts
│ ├── buildSrc/
│ │ ├── build.gradle.kts
│ │ ├── settings.gradle.kts
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ ├── AddCommentTask.kt
│ │ ├── DesugarClassVisitorFactory.kt
│ │ ├── Plugin.kt
│ │ ├── Setup.kt
│ │ └── Stub.kt
│ ├── core/
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── aidl/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ └── core/
│ │ │ └── utils/
│ │ │ └── IRootUtils.aidl
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── core/
│ │ │ │ ├── App.kt
│ │ │ │ ├── AppContext.kt
│ │ │ │ ├── Config.kt
│ │ │ │ ├── Const.kt
│ │ │ │ ├── Hacks.kt
│ │ │ │ ├── Info.kt
│ │ │ │ ├── JobService.kt
│ │ │ │ ├── Provider.kt
│ │ │ │ ├── Receiver.kt
│ │ │ │ ├── Service.kt
│ │ │ │ ├── base/
│ │ │ │ │ ├── BaseActivity.kt
│ │ │ │ │ ├── BaseJobService.kt
│ │ │ │ │ ├── BaseProvider.kt
│ │ │ │ │ ├── BaseReceiver.kt
│ │ │ │ │ ├── BaseService.kt
│ │ │ │ │ └── SplashScreen.kt
│ │ │ │ ├── data/
│ │ │ │ │ ├── RetrofitInterfaces.kt
│ │ │ │ │ ├── SuLogDao.kt
│ │ │ │ │ └── magiskdb/
│ │ │ │ │ ├── MagiskDB.kt
│ │ │ │ │ ├── PolicyDao.kt
│ │ │ │ │ ├── SettingsDao.kt
│ │ │ │ │ └── StringDao.kt
│ │ │ │ ├── di/
│ │ │ │ │ ├── Networking.kt
│ │ │ │ │ └── ServiceLocator.kt
│ │ │ │ ├── download/
│ │ │ │ │ ├── DownloadEngine.kt
│ │ │ │ │ ├── DownloadProcessor.kt
│ │ │ │ │ ├── Interfaces.kt
│ │ │ │ │ └── Subject.kt
│ │ │ │ ├── ktx/
│ │ │ │ │ ├── XAndroid.kt
│ │ │ │ │ ├── XJVM.kt
│ │ │ │ │ └── XSU.kt
│ │ │ │ ├── model/
│ │ │ │ │ ├── UpdateInfo.kt
│ │ │ │ │ ├── module/
│ │ │ │ │ │ ├── LocalModule.kt
│ │ │ │ │ │ ├── Module.kt
│ │ │ │ │ │ └── OnlineModule.kt
│ │ │ │ │ └── su/
│ │ │ │ │ ├── SuLog.kt
│ │ │ │ │ └── SuPolicy.kt
│ │ │ │ ├── repository/
│ │ │ │ │ ├── DBConfig.kt
│ │ │ │ │ ├── LogRepository.kt
│ │ │ │ │ ├── NetworkService.kt
│ │ │ │ │ └── PreferenceConfig.kt
│ │ │ │ ├── signing/
│ │ │ │ │ ├── ApkSignerV2.java
│ │ │ │ │ ├── ByteArrayStream.java
│ │ │ │ │ ├── JarMap.java
│ │ │ │ │ ├── SignApk.java
│ │ │ │ │ └── ZipUtils.java
│ │ │ │ ├── su/
│ │ │ │ │ ├── SuCallbackHandler.kt
│ │ │ │ │ ├── SuEvents.kt
│ │ │ │ │ └── SuRequestHandler.kt
│ │ │ │ ├── tasks/
│ │ │ │ │ ├── AppMigration.kt
│ │ │ │ │ ├── FlashZip.kt
│ │ │ │ │ └── MagiskInstaller.kt
│ │ │ │ ├── utils/
│ │ │ │ │ ├── AXML.kt
│ │ │ │ │ ├── Desugar.java
│ │ │ │ │ ├── DummyList.kt
│ │ │ │ │ ├── Keygen.kt
│ │ │ │ │ ├── LocaleSetting.kt
│ │ │ │ │ ├── MediaStoreUtils.kt
│ │ │ │ │ ├── NetworkObserver.kt
│ │ │ │ │ ├── ProgressInputStream.kt
│ │ │ │ │ ├── RequestAuthentication.kt
│ │ │ │ │ ├── RequestInstall.kt
│ │ │ │ │ ├── RootUtils.kt
│ │ │ │ │ └── ShellInit.kt
│ │ │ │ └── view/
│ │ │ │ ├── Notifications.kt
│ │ │ │ └── Shortcuts.kt
│ │ │ └── test/
│ │ │ ├── AdditionalTest.kt
│ │ │ ├── BaseTest.kt
│ │ │ ├── Environment.kt
│ │ │ └── MagiskAppTest.kt
│ │ └── res/
│ │ ├── drawable/
│ │ │ ├── ic_extension.xml
│ │ │ ├── ic_favorite.xml
│ │ │ ├── ic_fingerprint.xml
│ │ │ ├── ic_github.xml
│ │ │ ├── ic_logo.xml
│ │ │ ├── ic_magisk.xml
│ │ │ ├── ic_magisk_outline.xml
│ │ │ ├── ic_magisk_padded.xml
│ │ │ ├── ic_more.xml
│ │ │ ├── ic_patreon.xml
│ │ │ ├── ic_paypal.xml
│ │ │ ├── ic_superuser.xml
│ │ │ ├── ic_twitter.xml
│ │ │ ├── sc_extension.xml
│ │ │ └── sc_superuser.xml
│ │ ├── drawable-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ ├── sc_extension.xml
│ │ │ └── sc_superuser.xml
│ │ ├── values/
│ │ │ ├── arrays.xml
│ │ │ ├── colors.xml
│ │ │ ├── resources.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ ├── values-ar/
│ │ │ └── strings.xml
│ │ ├── values-ast/
│ │ │ └── strings.xml
│ │ ├── values-az/
│ │ │ └── strings.xml
│ │ ├── values-b+sr+Latn/
│ │ │ └── strings.xml
│ │ ├── values-be/
│ │ │ └── strings.xml
│ │ ├── values-bg/
│ │ │ └── strings.xml
│ │ ├── values-bn/
│ │ │ └── strings.xml
│ │ ├── values-ca/
│ │ │ └── strings.xml
│ │ ├── values-cs/
│ │ │ └── strings.xml
│ │ ├── values-de/
│ │ │ └── strings.xml
│ │ ├── values-el/
│ │ │ └── strings.xml
│ │ ├── values-es/
│ │ │ └── strings.xml
│ │ ├── values-et/
│ │ │ └── strings.xml
│ │ ├── values-fa/
│ │ │ └── strings.xml
│ │ ├── values-fr/
│ │ │ └── strings.xml
│ │ ├── values-hi/
│ │ │ └── strings.xml
│ │ ├── values-hn/
│ │ │ └── strings.xml
│ │ ├── values-hr/
│ │ │ └── strings.xml
│ │ ├── values-hu/
│ │ │ └── strings.xml
│ │ ├── values-in/
│ │ │ └── strings.xml
│ │ ├── values-it/
│ │ │ └── strings.xml
│ │ ├── values-iw/
│ │ │ └── strings.xml
│ │ ├── values-ja/
│ │ │ └── strings.xml
│ │ ├── values-ka/
│ │ │ └── strings.xml
│ │ ├── values-kk/
│ │ │ └── strings.xml
│ │ ├── values-ko/
│ │ │ └── strings.xml
│ │ ├── values-ku/
│ │ │ └── strings.xml
│ │ ├── values-lt/
│ │ │ └── strings.xml
│ │ ├── values-mk/
│ │ │ └── strings.xml
│ │ ├── values-ml/
│ │ │ └── strings.xml
│ │ ├── values-nb/
│ │ │ └── strings.xml
│ │ ├── values-night/
│ │ │ └── colors.xml
│ │ ├── values-nl/
│ │ │ └── strings.xml
│ │ ├── values-pa/
│ │ │ └── strings.xml
│ │ ├── values-pl/
│ │ │ └── strings.xml
│ │ ├── values-pt-rBR/
│ │ │ └── strings.xml
│ │ ├── values-pt-rPT/
│ │ │ └── strings.xml
│ │ ├── values-ro/
│ │ │ └── strings.xml
│ │ ├── values-ru/
│ │ │ └── strings.xml
│ │ ├── values-sk/
│ │ │ └── strings.xml
│ │ ├── values-sq/
│ │ │ └── strings.xml
│ │ ├── values-sr/
│ │ │ └── strings.xml
│ │ ├── values-sv/
│ │ │ └── strings.xml
│ │ ├── values-sw/
│ │ │ └── strings.xml
│ │ ├── values-ta/
│ │ │ └── strings.xml
│ │ ├── values-th/
│ │ │ └── strings.xml
│ │ ├── values-tr/
│ │ │ └── strings.xml
│ │ ├── values-uk/
│ │ │ └── strings.xml
│ │ ├── values-ur/
│ │ │ └── strings.xml
│ │ ├── values-v31/
│ │ │ └── themes.xml
│ │ ├── values-v34/
│ │ │ └── resources.xml
│ │ ├── values-vi/
│ │ │ └── strings.xml
│ │ ├── values-zh-rCN/
│ │ │ └── strings.xml
│ │ ├── values-zh-rTW/
│ │ │ └── strings.xml
│ │ └── xml/
│ │ └── locale_config.xml
│ ├── gradle/
│ │ ├── libs.versions.toml
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── settings.gradle.kts
│ ├── shared/
│ │ ├── build.gradle.kts
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ └── java/
│ │ └── com/
│ │ └── topjohnwu/
│ │ └── magisk/
│ │ ├── ProviderInstaller.java
│ │ ├── StubApk.java
│ │ └── utils/
│ │ ├── APKInstall.java
│ │ ├── CompoundEnumeration.java
│ │ └── DynamicClassLoader.java
│ ├── stub/
│ │ ├── .gitignore
│ │ ├── build.gradle.kts
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── topjohnwu/
│ │ │ └── magisk/
│ │ │ ├── ClassLoaders.java
│ │ │ ├── DelegateComponentFactory.java
│ │ │ ├── DownloadActivity.java
│ │ │ ├── DynLoad.java
│ │ │ ├── StubApplication.java
│ │ │ ├── StubRootService.java
│ │ │ ├── dummy/
│ │ │ │ ├── DummyProvider.java
│ │ │ │ ├── DummyReceiver.java
│ │ │ │ └── DummyService.java
│ │ │ └── net/
│ │ │ ├── BadRequest.java
│ │ │ ├── ErrorHandler.java
│ │ │ ├── Networking.java
│ │ │ ├── Request.java
│ │ │ └── ResponseListener.java
│ │ └── res/
│ │ ├── values/
│ │ │ └── strings.xml
│ │ ├── values-ar/
│ │ │ └── strings.xml
│ │ ├── values-ast/
│ │ │ └── strings.xml
│ │ ├── values-az/
│ │ │ └── strings.xml
│ │ ├── values-b+sr+Latn/
│ │ │ └── strings.xml
│ │ ├── values-be/
│ │ │ └── strings.xml
│ │ ├── values-bg/
│ │ │ └── strings.xml
│ │ ├── values-ca/
│ │ │ └── strings.xml
│ │ ├── values-cs/
│ │ │ └── strings.xml
│ │ ├── values-de/
│ │ │ └── strings.xml
│ │ ├── values-el/
│ │ │ └── strings.xml
│ │ ├── values-es/
│ │ │ └── strings.xml
│ │ ├── values-et/
│ │ │ └── strings.xml
│ │ ├── values-fa/
│ │ │ └── strings.xml
│ │ ├── values-fr/
│ │ │ └── strings.xml
│ │ ├── values-hi/
│ │ │ └── strings.xml
│ │ ├── values-hn/
│ │ │ └── strings.xml
│ │ ├── values-hr/
│ │ │ └── strings.xml
│ │ ├── values-hu/
│ │ │ └── strings.xml
│ │ ├── values-in/
│ │ │ └── strings.xml
│ │ ├── values-it/
│ │ │ └── strings.xml
│ │ ├── values-iw/
│ │ │ └── strings.xml
│ │ ├── values-ja/
│ │ │ └── strings.xml
│ │ ├── values-ka/
│ │ │ └── strings.xml
│ │ ├── values-kk/
│ │ │ └── strings.xml
│ │ ├── values-ko/
│ │ │ └── strings.xml
│ │ ├── values-ku/
│ │ │ └── strings.xml
│ │ ├── values-lt/
│ │ │ └── strings.xml
│ │ ├── values-mk/
│ │ │ └── strings.xml
│ │ ├── values-ml/
│ │ │ └── strings.xml
│ │ ├── values-nb/
│ │ │ └── strings.xml
│ │ ├── values-nl/
│ │ │ └── strings.xml
│ │ ├── values-pa/
│ │ │ └── strings.xml
│ │ ├── values-pl/
│ │ │ └── strings.xml
│ │ ├── values-pt-rBR/
│ │ │ └── strings.xml
│ │ ├── values-pt-rPT/
│ │ │ └── strings.xml
│ │ ├── values-ro/
│ │ │ └── strings.xml
│ │ ├── values-ru/
│ │ │ └── strings.xml
│ │ ├── values-sk/
│ │ │ └── strings.xml
│ │ ├── values-sq/
│ │ │ └── strings.xml
│ │ ├── values-sr/
│ │ │ └── strings.xml
│ │ ├── values-sv/
│ │ │ └── strings.xml
│ │ ├── values-sw/
│ │ │ └── strings.xml
│ │ ├── values-ta/
│ │ │ └── strings.xml
│ │ ├── values-th/
│ │ │ └── strings.xml
│ │ ├── values-tr/
│ │ │ └── strings.xml
│ │ ├── values-uk/
│ │ │ └── strings.xml
│ │ ├── values-vi/
│ │ │ └── strings.xml
│ │ ├── values-zh-rCN/
│ │ │ └── strings.xml
│ │ └── values-zh-rTW/
│ │ └── strings.xml
│ └── test/
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ └── java/
│ └── com/
│ └── topjohnwu/
│ └── magisk/
│ └── test/
│ ├── AppMigrationTest.kt
│ └── Runners.kt
├── build.py
├── config.prop.sample
├── docs/
│ ├── README.md
│ ├── app_changes.md
│ ├── boot.md
│ ├── build.md
│ ├── changes.md
│ ├── details.md
│ ├── faq.md
│ ├── guides.md
│ ├── install.md
│ ├── ota.md
│ └── tools.md
├── native/
│ ├── .gitignore
│ └── src/
│ ├── .cargo/
│ │ └── config.toml
│ ├── Android-rs.mk
│ ├── Android.mk
│ ├── Application.mk
│ ├── Cargo.toml
│ ├── base/
│ │ ├── Android.mk
│ │ ├── Cargo.toml
│ │ ├── argh.rs
│ │ ├── base.cpp
│ │ ├── build.rs
│ │ ├── cstr.rs
│ │ ├── cxx_extern.rs
│ │ ├── derive/
│ │ │ ├── Cargo.toml
│ │ │ ├── argh/
│ │ │ │ ├── errors.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── parse_attrs.rs
│ │ │ ├── decodable.rs
│ │ │ └── lib.rs
│ │ ├── dir.rs
│ │ ├── files.rs
│ │ ├── include/
│ │ │ └── base.hpp
│ │ ├── lib.rs
│ │ ├── logging.rs
│ │ ├── misc.rs
│ │ ├── mount.rs
│ │ ├── result.rs
│ │ └── xwrap.rs
│ ├── boot/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── bootimg.cpp
│ │ ├── bootimg.hpp
│ │ ├── build.rs
│ │ ├── cli.rs
│ │ ├── compress.rs
│ │ ├── cpio.rs
│ │ ├── dtb.rs
│ │ ├── format.rs
│ │ ├── lib.rs
│ │ ├── magiskboot.hpp
│ │ ├── patch.rs
│ │ ├── payload.rs
│ │ ├── proto/
│ │ │ └── update_metadata.proto
│ │ └── sign.rs
│ ├── core/
│ │ ├── Cargo.toml
│ │ ├── applet_stub.cpp
│ │ ├── applets.cpp
│ │ ├── bootstages.rs
│ │ ├── build.rs
│ │ ├── daemon.rs
│ │ ├── db.rs
│ │ ├── deny/
│ │ │ ├── cli.cpp
│ │ │ ├── deny.hpp
│ │ │ ├── logcat.cpp
│ │ │ └── utils.cpp
│ │ ├── include/
│ │ │ ├── core.hpp
│ │ │ └── sqlite.hpp
│ │ ├── lib.rs
│ │ ├── logging.rs
│ │ ├── magisk.rs
│ │ ├── module.rs
│ │ ├── mount.rs
│ │ ├── package.rs
│ │ ├── resetprop/
│ │ │ ├── .gitignore
│ │ │ ├── cli.rs
│ │ │ ├── mod.rs
│ │ │ ├── persist.rs
│ │ │ ├── proto/
│ │ │ │ └── persistent_properties.proto
│ │ │ └── sys.cpp
│ │ ├── scripting.cpp
│ │ ├── selinux.rs
│ │ ├── socket.rs
│ │ ├── sqlite.cpp
│ │ ├── su/
│ │ │ ├── connect.rs
│ │ │ ├── daemon.rs
│ │ │ ├── db.rs
│ │ │ ├── mod.rs
│ │ │ ├── pts.rs
│ │ │ └── su.cpp
│ │ ├── thread.rs
│ │ ├── utils.cpp
│ │ └── zygisk/
│ │ ├── api.hpp
│ │ ├── daemon.rs
│ │ ├── entry.cpp
│ │ ├── gen_jni_hooks.py
│ │ ├── hook.cpp
│ │ ├── jni_hooks.hpp
│ │ ├── mod.rs
│ │ ├── module.cpp
│ │ ├── module.hpp
│ │ └── zygisk.hpp
│ ├── exported_sym.txt
│ ├── external/
│ │ ├── Android.mk
│ │ ├── lz4-sys/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ ├── lib.rs
│ │ │ └── wasm_shim.rs
│ │ ├── xz-embedded/
│ │ │ ├── xz.h
│ │ │ ├── xz_config.h
│ │ │ ├── xz_crc32.c
│ │ │ ├── xz_dec_lzma2.c
│ │ │ ├── xz_dec_stream.c
│ │ │ ├── xz_lzma2.h
│ │ │ ├── xz_private.h
│ │ │ └── xz_stream.h
│ │ └── xz_config/
│ │ └── config.h
│ ├── include/
│ │ ├── codegen.rs
│ │ ├── consts.hpp
│ │ └── consts.rs
│ ├── init/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ ├── getinfo.cpp
│ │ ├── getinfo.rs
│ │ ├── init.hpp
│ │ ├── init.rs
│ │ ├── lib.rs
│ │ ├── logging.rs
│ │ ├── mount.cpp
│ │ ├── mount.rs
│ │ ├── preload.c
│ │ ├── rootdir.cpp
│ │ ├── rootdir.rs
│ │ ├── selinux.rs
│ │ └── twostage.rs
│ ├── rustfmt.toml
│ └── sepolicy/
│ ├── Cargo.toml
│ ├── api.cpp
│ ├── build.rs
│ ├── cli.rs
│ ├── include/
│ │ └── sepolicy.hpp
│ ├── lib.rs
│ ├── policy.hpp
│ ├── policydb.cpp
│ ├── rules.rs
│ ├── sepolicy.cpp
│ └── statement.rs
├── scripts/
│ ├── addon.d.sh
│ ├── app_functions.sh
│ ├── avd.sh
│ ├── boot_patch.sh
│ ├── cuttlefish.sh
│ ├── flash_script.sh
│ ├── host_patch.sh
│ ├── live_setup.sh
│ ├── module_installer.sh
│ ├── release.sh
│ ├── test_common.sh
│ ├── uninstaller.sh
│ ├── update_binary.sh
│ └── util_functions.sh
└── tools/
├── bootctl
├── bootctl.patch
├── elf-cleaner/
│ ├── .gitignore
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
├── futility
├── keys/
│ ├── kernel.keyblock
│ ├── kernel_data_key.vbprivk
│ ├── verity.pk8
│ └── verity.x509.pem
└── rustup-wrapper/
├── .gitignore
├── Cargo.toml
└── src/
└── main.rs
SYMBOL INDEX (2130 symbols across 139 files)
FILE: app/apk/src/main/java/com/topjohnwu/magisk/widget/ConcealableBottomNavigationView.java
class ConcealableBottomNavigationView (line 19) | public class ConcealableBottomNavigationView extends BottomNavigationView {
method ConcealableBottomNavigationView (line 26) | public ConcealableBottomNavigationView(@NonNull Context context) {
method ConcealableBottomNavigationView (line 30) | public ConcealableBottomNavigationView(@NonNull Context context, @Null...
method ConcealableBottomNavigationView (line 34) | public ConcealableBottomNavigationView(@NonNull Context context, @Null...
method ConcealableBottomNavigationView (line 38) | public ConcealableBottomNavigationView(@NonNull Context context, @Null...
method recreateAnimator (line 42) | private void recreateAnimator(int height) {
method onMeasure (line 58) | @Override
method onCreateDrawableState (line 65) | @Override
method isHidden (line 74) | public boolean isHidden() {
method setHidden (line 78) | public void setHidden(boolean raised) {
method onSaveInstanceState (line 85) | @NonNull
method onRestoreInstanceState (line 93) | @Override
class SavedState (line 103) | static class SavedState extends AbsSavedState {
method SavedState (line 107) | public SavedState(Parcel source) {
method SavedState (line 112) | public SavedState(Parcelable superState) {
method writeToParcel (line 116) | @Override
method createFromParcel (line 124) | @Override
method newArray (line 129) | @Override
FILE: app/core/src/main/java/com/topjohnwu/magisk/core/signing/ApkSignerV2.java
class ApkSignerV2 (line 37) | public abstract class ApkSignerV2 {
method ApkSignerV2 (line 86) | private ApkSignerV2() {}
class SignerConfig (line 91) | public static final class SignerConfig {
method sign (line 125) | public static ByteBuffer[] sign(
method computeContentDigests (line 231) | private static Map<Integer, byte[]> computeContentDigests(
method getChunkCount (line 321) | private static int getChunkCount(int inputSize, int chunkSize) {
method setUnsignedInt32LittleEngian (line 325) | private static void setUnsignedInt32LittleEngian(int value, byte[] res...
method generateApkSigningBlock (line 332) | private static byte[] generateApkSigningBlock(
method generateApkSigningBlock (line 340) | private static byte[] generateApkSigningBlock(byte[] apkSignatureSchem...
method generateApkSignatureSchemeV2Block (line 372) | private static byte[] generateApkSignatureSchemeV2Block(
method generateSignerBlock (line 399) | private static byte[] generateSignerBlock(
class V2SignatureSchemeBlock (line 509) | private static final class V2SignatureSchemeBlock {
class Signer (line 510) | private static final class Signer {
class SignedData (line 516) | private static final class SignedData {
method encodePublicKey (line 522) | private static byte[] encodePublicKey(PublicKey publicKey) throws Inva...
method encodeCertificates (line 548) | public static List<byte[]> encodeCertificates(List<X509Certificate> ce...
method encodeAsSequenceOfLengthPrefixedElements (line 557) | private static byte[] encodeAsSequenceOfLengthPrefixedElements(List<by...
method encodeAsSequenceOfLengthPrefixedElements (line 562) | private static byte[] encodeAsSequenceOfLengthPrefixedElements(byte[][...
method encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes (line 576) | private static byte[] encodeAsSequenceOfLengthPrefixedPairsOfIntAndLen...
method getByteBuffer (line 603) | private static ByteBuffer getByteBuffer(ByteBuffer source, int size) {
method getSignatureAlgorithmJcaSignatureAlgorithm (line 624) | private static Pair<String, ? extends AlgorithmParameterSpec>
method getSignatureAlgorithmContentDigestAlgorithm (line 656) | private static int getSignatureAlgorithmContentDigestAlgorithm(int sig...
method getContentDigestAlgorithmJcaDigestAlgorithm (line 675) | private static String getContentDigestAlgorithmJcaDigestAlgorithm(int ...
method getContentDigestAlgorithmOutputSizeBytes (line 687) | private static int getContentDigestAlgorithmOutputSizeBytes(int digest...
class ApkParseException (line 702) | public static class ApkParseException extends Exception {
method ApkParseException (line 705) | public ApkParseException(String message) {
method ApkParseException (line 709) | public ApkParseException(String message, Throwable cause) {
class Pair (line 717) | private static class Pair<A, B> {
method Pair (line 721) | private Pair(A first, B second) {
method create (line 726) | public static <A, B> Pair<A, B> create(A first, B second) {
method getFirst (line 730) | public A getFirst() {
method getSecond (line 734) | public B getSecond() {
method hashCode (line 738) | @Override
method equals (line 747) | @Override
FILE: app/core/src/main/java/com/topjohnwu/magisk/core/signing/ByteArrayStream.java
class ByteArrayStream (line 9) | public class ByteArrayStream extends ByteArrayOutputStream {
method readFrom (line 11) | public synchronized void readFrom(InputStream is) {
method readFrom (line 15) | public synchronized void readFrom(InputStream is, int len) {
method getInputStream (line 28) | public ByteArrayInputStream getInputStream() {
method toByteBuffer (line 32) | public ByteBuffer toByteBuffer() {
FILE: app/core/src/main/java/com/topjohnwu/magisk/core/signing/JarMap.java
class JarMap (line 18) | public abstract class JarMap implements Closeable {
method open (line 22) | public static JarMap open(File file, boolean verify) throws IOException {
method open (line 26) | public static JarMap open(InputStream is, boolean verify) throws IOExc...
method getFile (line 30) | public File getFile() {
method getManifest (line 34) | public abstract Manifest getManifest() throws IOException;
method getInputStream (line 36) | public InputStream getInputStream(ZipEntry ze) throws IOException {
method getOutputStream (line 41) | public OutputStream getOutputStream(ZipEntry ze) {
method getRawData (line 49) | public byte[] getRawData(ZipEntry ze) throws IOException {
method entries (line 54) | public abstract Enumeration<JarEntry> entries();
method getEntry (line 56) | public final ZipEntry getEntry(String name) {
method getJarEntry (line 60) | public JarEntry getJarEntry(String name) {
method getMapEntry (line 64) | JarMapEntry getMapEntry(String name) {
class FileMap (line 71) | private static class FileMap extends JarMap {
method FileMap (line 75) | FileMap(File file, boolean verify, int mode) throws IOException {
method getFile (line 79) | @Override
method getManifest (line 84) | @Override
method getInputStream (line 89) | @Override
method getRawData (line 95) | @Override
method entries (line 105) | @Override
method getJarEntry (line 110) | @Override
method close (line 116) | @Override
class StreamMap (line 122) | private static class StreamMap extends JarMap {
method StreamMap (line 126) | StreamMap(InputStream is, boolean verify) throws IOException {
method getManifest (line 135) | @Override
method entries (line 140) | @Override
method close (line 145) | @Override
class JarMapEntry (line 151) | private static class JarMapEntry extends JarEntry {
method JarMapEntry (line 155) | JarMapEntry(JarEntry je, InputStream is) {
method JarMapEntry (line 161) | JarMapEntry(String s) {
FILE: app/core/src/main/java/com/topjohnwu/magisk/core/signing/SignApk.java
class SignApk (line 55) | public class SignApk {
method getDigestAlgorithm (line 78) | private static int getDigestAlgorithm(X509Certificate cert) {
method getSignatureAlgorithm (line 93) | private static String getSignatureAlgorithm(X509Certificate cert) {
method addDigestsToManifest (line 112) | private static Manifest addDigestsToManifest(JarMap jar, int hashes)
method writeSignatureFile (line 191) | private static void writeSignatureFile(Manifest manifest, OutputStream...
method writeSignatureBlock (line 249) | private static void writeSignatureBlock(
method copyFiles (line 282) | private static void copyFiles(Manifest manifest, JarMap in, JarOutputS...
method getStoredEntryDataAlignment (line 372) | private static int getStoredEntryDataAlignment(String entryName, int d...
method signFile (line 386) | private static void signFile(Manifest manifest,
method createV2SignerConfigs (line 422) | private static List<ApkSignerV2.SignerConfig> createV2SignerConfigs(
method getV2SignatureAlgorithm (line 461) | private static int getV2SignatureAlgorithm(String keyAlgorithm, String...
method sign (line 493) | public static void sign(X509Certificate cert, PrivateKey key,
class CountOutputStream (line 542) | private static class CountOutputStream extends FilterOutputStream {
method CountOutputStream (line 545) | public CountOutputStream(OutputStream out) {
method write (line 550) | @Override
method write (line 556) | @Override
method size (line 562) | public int size() {
FILE: app/core/src/main/java/com/topjohnwu/magisk/core/signing/ZipUtils.java
class ZipUtils (line 12) | public abstract class ZipUtils {
method ZipUtils (line 25) | private ZipUtils() {
method findZipEndOfCentralDirectoryRecord (line 34) | public static int findZipEndOfCentralDirectoryRecord(ByteBuffer zipCon...
method isZip64EndOfCentralDirectoryLocatorPresent (line 72) | public static boolean isZip64EndOfCentralDirectoryLocatorPresent(ByteB...
method getZipEocdCentralDirectoryOffset (line 91) | public static long getZipEocdCentralDirectoryOffset(ByteBuffer zipEndO...
method setZipEocdCentralDirectoryOffset (line 101) | public static void setZipEocdCentralDirectoryOffset(ByteBuffer zipEndO...
method getZipEocdCentralDirectorySizeBytes (line 111) | public static long getZipEocdCentralDirectorySizeBytes(ByteBuffer zipE...
method assertByteOrderLittleEndian (line 116) | private static void assertByteOrderLittleEndian(ByteBuffer buffer) {
method getUnsignedInt16 (line 122) | private static int getUnsignedInt16(ByteBuffer buffer, int offset) {
method getUnsignedInt32 (line 126) | private static long getUnsignedInt32(ByteBuffer buffer, int offset) {
method setUnsignedInt32 (line 130) | private static void setUnsignedInt32(ByteBuffer buffer, int offset, lo...
FILE: app/core/src/main/java/com/topjohnwu/magisk/core/utils/Desugar.java
class Desugar (line 12) | public class Desugar {
method getLastModifiedTime (line 13) | public static FileTime getLastModifiedTime(ZipEntry entry) {
method getLastAccessTime (line 21) | public static FileTime getLastAccessTime(ZipEntry entry) {
method getCreationTime (line 29) | public static FileTime getCreationTime(ZipEntry entry) {
method checkRequestedFeatures (line 44) | public static void checkRequestedFeatures(final ZipArchiveEntry ze) {
FILE: app/shared/src/main/java/com/topjohnwu/magisk/ProviderInstaller.java
class ProviderInstaller (line 6) | public class ProviderInstaller {
method install (line 10) | public static void install(Context context) {
FILE: app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java
class StubApk (line 23) | public class StubApk {
method getDynDir (line 27) | private static File getDynDir(ApplicationInfo info) {
method current (line 42) | public static File current(Context c) {
method current (line 46) | public static File current(ApplicationInfo info) {
method update (line 50) | public static File update(Context c) {
method update (line 54) | public static File update(ApplicationInfo info) {
method getResourcesLoader (line 58) | @TargetApi(Build.VERSION_CODES.R)
method addAssetPath (line 72) | public static void addAssetPath(Resources res, String path) {
method restartProcess (line 87) | public static void restartProcess(Activity activity) {
class Data (line 95) | public static class Data {
method Data (line 104) | public Data() { arr = new Object[ARR_SIZE]; }
method Data (line 105) | public Data(Object o) { arr = (Object[]) o; }
method getObject (line 106) | public Object getObject() { return arr; }
method getVersion (line 108) | public int getVersion() { return (int) arr[STUB_VERSION]; }
method setVersion (line 109) | public void setVersion(int version) { arr[STUB_VERSION] = version; }
method getClassToComponent (line 110) | public Map<String, String> getClassToComponent() {
method setClassToComponent (line 114) | public void setClassToComponent(Map<String, String> map) {
method getRootService (line 117) | public Class<?> getRootService() { return (Class<?>) arr[ROOT_SERVIC...
method setRootService (line 118) | public void setRootService(Class<?> service) { arr[ROOT_SERVICE] = s...
FILE: app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
class APKInstall (line 28) | public final class APKInstall {
method transfer (line 30) | public static void transfer(InputStream in, OutputStream out) throws I...
method registerReceiver (line 39) | public static void registerReceiver(
method startSession (line 49) | public static Session startSession(Context context) {
method startSession (line 53) | public static Session startSession(Context context, String pkg,
type Session (line 67) | public interface Session {
method openStream (line 69) | OutputStream openStream(Context context) throws IOException;
method waitIntent (line 71) | Intent waitIntent();
class InstallReceiver (line 74) | private static class InstallReceiver extends BroadcastReceiver impleme...
method InstallReceiver (line 83) | private InstallReceiver(String packageName, Runnable onSuccess, Runn...
method onReceive (line 89) | @Override
method onSuccess (line 129) | private void onSuccess(Context context) {
method waitIntent (line 138) | @Override
method openStream (line 147) | @Override
FILE: app/shared/src/main/java/com/topjohnwu/magisk/utils/CompoundEnumeration.java
class CompoundEnumeration (line 6) | public class CompoundEnumeration<E> implements Enumeration<E> {
method CompoundEnumeration (line 10) | @SafeVarargs
method next (line 15) | private boolean next() {
method hasMoreElements (line 25) | public boolean hasMoreElements() {
method nextElement (line 29) | public E nextElement() {
FILE: app/shared/src/main/java/com/topjohnwu/magisk/utils/DynamicClassLoader.java
class DynamicClassLoader (line 12) | public class DynamicClassLoader extends BaseDexClassLoader {
method DynamicClassLoader (line 14) | public DynamicClassLoader(File apk) {
method DynamicClassLoader (line 18) | public DynamicClassLoader(File apk, ClassLoader parent) {
method loadClass (line 23) | @Override
method getResource (line 48) | @Override
method getResources (line 60) | @Override
FILE: app/stub/src/main/java/com/topjohnwu/magisk/ClassLoaders.java
class MappingClassLoader (line 14) | class MappingClassLoader extends ClassLoader {
method MappingClassLoader (line 18) | MappingClassLoader(ClassLoader parent, Map<String, String> m) {
method loadClass (line 23) | @Override
class StubClassLoader (line 31) | class StubClassLoader extends ClassLoader {
method StubClassLoader (line 35) | StubClassLoader(PackageInfo info) {
method loadClass (line 51) | @Override
class DelegateClassLoader (line 58) | class DelegateClassLoader extends ClassLoader {
method DelegateClassLoader (line 60) | DelegateClassLoader() {
method loadClass (line 64) | @Override
FILE: app/stub/src/main/java/com/topjohnwu/magisk/DelegateComponentFactory.java
class DelegateComponentFactory (line 17) | @SuppressLint("NewApi")
method DelegateComponentFactory (line 22) | public DelegateComponentFactory() {
method instantiateClassLoader (line 26) | @Override
method instantiateApplication (line 31) | @Override
method instantiateActivity (line 36) | @Override
method instantiateReceiver (line 44) | @Override
method instantiateService (line 52) | @Override
method instantiateProvider (line 60) | @Override
method create (line 68) | private <T> T create(String name, Class<T> fallback)
FILE: app/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java
class DownloadActivity (line 46) | public class DownloadActivity extends Activity {
method onCreate (line 53) | @Override
method finish (line 82) | @Override
method error (line 88) | private void error(Throwable e) {
method request (line 93) | private Request request(String url) {
method showDialog (line 97) | private void showDialog() {
method dlAPK (line 107) | private void dlAPK() {
method decryptResources (line 129) | private void decryptResources(OutputStream out) throws Exception {
method loadResources (line 141) | private void loadResources() throws Exception {
FILE: app/stub/src/main/java/com/topjohnwu/magisk/DynLoad.java
class DynLoad (line 29) | @SuppressWarnings("ResultOfMethodCallIgnored")
method createApkData (line 35) | static StubApk.Data createApkData() {
method attachContext (line 43) | static void attachContext(Object o, Context context) {
method loadApk (line 54) | static DynamicClassLoader loadApk(Context context) {
method loadAndInitializeApp (line 116) | static void loadAndInitializeApp(Application context) {
method replaceClassLoader (line 183) | private static void replaceClassLoader(Context context) {
method generateMapping (line 204) | private static Map<String, String> generateMapping(PackageInfo stub, P...
FILE: app/stub/src/main/java/com/topjohnwu/magisk/StubApplication.java
class StubApplication (line 6) | public class StubApplication extends Application {
method attachBaseContext (line 7) | @Override
FILE: app/stub/src/main/java/com/topjohnwu/magisk/StubRootService.java
class StubRootService (line 12) | public class StubRootService extends ContextWrapper {
method StubRootService (line 14) | public StubRootService() {
method attachBaseContext (line 18) | @Override
FILE: app/stub/src/main/java/com/topjohnwu/magisk/dummy/DummyProvider.java
class DummyProvider (line 8) | public class DummyProvider extends ContentProvider {
method onCreate (line 9) | @Override
method query (line 14) | @Override
method getType (line 19) | @Override
method insert (line 24) | @Override
method delete (line 29) | @Override
method update (line 34) | @Override
FILE: app/stub/src/main/java/com/topjohnwu/magisk/dummy/DummyReceiver.java
class DummyReceiver (line 7) | public class DummyReceiver extends BroadcastReceiver {
method onReceive (line 8) | @Override
FILE: app/stub/src/main/java/com/topjohnwu/magisk/dummy/DummyService.java
class DummyService (line 7) | public class DummyService extends Service {
method onBind (line 8) | @Override
FILE: app/stub/src/main/java/com/topjohnwu/magisk/net/BadRequest.java
class BadRequest (line 10) | class BadRequest extends Request {
method BadRequest (line 14) | BadRequest(IOException e) { super(null); ex = e; }
method addHeaders (line 16) | @Override
method execForInputStream (line 19) | @Override
method getAsFile (line 22) | @Override
method execForFile (line 25) | @Override
method getAsString (line 28) | @Override
method execForString (line 31) | @Override
method getAsJSONObject (line 34) | @Override
method execForJSONObject (line 37) | @Override
method getAsJSONArray (line 40) | @Override
method execForJSONArray (line 43) | @Override
method fail (line 46) | private void fail() {
FILE: app/stub/src/main/java/com/topjohnwu/magisk/net/ErrorHandler.java
type ErrorHandler (line 5) | public interface ErrorHandler {
method onError (line 6) | void onError(HttpURLConnection conn, Exception e);
FILE: app/stub/src/main/java/com/topjohnwu/magisk/net/Networking.java
class Networking (line 13) | public class Networking {
method request (line 19) | private static Request request(String url, String method) {
method get (line 31) | public static Request get(String url) {
method checkNetworkStatus (line 35) | public static boolean checkNetworkStatus(Context context) {
FILE: app/stub/src/main/java/com/topjohnwu/magisk/net/Request.java
class Request (line 25) | public class Request {
type Requestor (line 32) | private interface Requestor<T> {
method request (line 33) | T request() throws Exception;
class Result (line 36) | public class Result<T> {
method getResult (line 39) | public T getResult() {
method getCode (line 43) | public int getCode() {
method isSuccess (line 47) | public boolean isSuccess() {
method getConnection (line 51) | public HttpURLConnection getConnection() {
method Request (line 56) | Request(HttpURLConnection c) {
method addHeaders (line 60) | public Request addHeaders(String key, String value) {
method setErrorHandler (line 65) | public Request setErrorHandler(ErrorHandler handler) {
method setExecutor (line 70) | public Request setExecutor(Executor e) {
method connect (line 75) | public Result<Void> connect() {
method execForInputStream (line 85) | public Result<InputStream> execForInputStream() {
method getAsInputStream (line 89) | public void getAsInputStream(ResponseListener<InputStream> rs) {
method getAsFile (line 93) | public void getAsFile(File out, ResponseListener<File> rs) {
method execForFile (line 97) | public void execForFile(File out) {
method getAsBytes (line 101) | public void getAsBytes(ResponseListener<byte[]> rs) {
method execForBytes (line 105) | public Result<byte[]> execForBytes() {
method getAsString (line 109) | public void getAsString(ResponseListener<String> rs) {
method execForString (line 113) | public Result<String> execForString() {
method getAsJSONObject (line 117) | public void getAsJSONObject(ResponseListener<JSONObject> rs) {
method execForJSONObject (line 121) | public Result<JSONObject> execForJSONObject() {
method getAsJSONArray (line 125) | public void getAsJSONArray(ResponseListener<JSONArray> rs) {
method execForJSONArray (line 129) | public Result<JSONArray> execForJSONArray() {
method connect0 (line 133) | private void connect0() throws IOException {
method exec (line 138) | private <T> Result<T> exec(Requestor<T> req) {
method submit (line 149) | private <T> void submit(Requestor<T> req, ResponseListener<T> rs) {
method getInputStream (line 165) | private BufferedInputStream getInputStream() throws IOException {
method dlString (line 177) | private String dlString() throws IOException {
method dlJSONObject (line 184) | private JSONObject dlJSONObject() throws IOException, JSONException {
method dlJSONArray (line 188) | private JSONArray dlJSONArray() throws IOException, JSONException {
method dlFile (line 192) | private File dlFile(File f) throws IOException {
method dlBytes (line 200) | private byte[] dlBytes() throws IOException {
FILE: app/stub/src/main/java/com/topjohnwu/magisk/net/ResponseListener.java
type ResponseListener (line 3) | public interface ResponseListener<T> {
method onResponse (line 4) | void onResponse(T response);
FILE: build.py
function color_print (line 18) | def color_print(code, str):
function error (line 26) | def error(str):
function header (line 31) | def header(str):
function vprint (line 35) | def vprint(str):
function mv (line 96) | def mv(source: Path, target: Path):
function cp (line 104) | def cp(source: Path, target: Path):
function rm (line 112) | def rm(file: Path):
function rm_on_error (line 120) | def rm_on_error(func, path, _):
function rm_rf (line 130) | def rm_rf(path: Path):
function execv (line 138) | def execv(cmds: list, env=None):
function cmd_out (line 144) | def cmd_out(cmds: list):
function clean_elf (line 162) | def clean_elf():
function collect_ndk_build (line 175) | def collect_ndk_build():
function run_ndk_build (line 184) | def run_ndk_build(cmds: list[str]):
function build_cpp_src (line 200) | def build_cpp_src(targets: set[str]):
function run_cargo (line 239) | def run_cargo(cmds: list[str]):
function build_rust_src (line 258) | def build_rust_src(targets: set[str]):
function write_if_diff (line 303) | def write_if_diff(file_name: Path, text: str):
function dump_flags_native (line 314) | def dump_flags_native():
function ensure_toolchain (line 329) | def ensure_toolchain():
function build_native (line 347) | def build_native():
function find_jdk (line 369) | def find_jdk():
function dump_flags_app (line 401) | def dump_flags_app():
function build_apk (line 411) | def build_apk(module: str):
function build_app (line 442) | def build_app():
function build_app_ng (line 461) | def build_app_ng():
function build_stub (line 467) | def build_stub():
function build_test (line 473) | def build_test():
function cleanup (line 492) | def cleanup():
function build_all (line 527) | def build_all():
function gen_ide (line 539) | def gen_ide():
function clippy_cli (line 578) | def clippy_cli():
function cargo_cli (line 602) | def cargo_cli():
function setup_ndk (line 612) | def setup_ndk():
function setup_rustup (line 631) | def setup_rustup():
function push_files (line 664) | def push_files(script: Path):
function setup_avd (line 699) | def setup_avd():
function patch_avd_file (line 709) | def patch_avd_file():
function ensure_paths (line 740) | def ensure_paths():
function ensure_adb (line 765) | def ensure_adb():
function parse_props (line 774) | def parse_props(file: Path) -> dict[str, str]:
function set_build_abis (line 791) | def set_build_abis(abis: set[str]):
function load_config (line 801) | def load_config():
function parse_args (line 834) | def parse_args():
function main (line 941) | def main():
FILE: native/src/base/argh.rs
type CommandInfo (line 323) | pub type CommandInfo = argh_shared::CommandInfo<'static>;
type CommandInfoWithArgs (line 326) | pub type CommandInfoWithArgs = argh_shared::CommandInfoWithArgs<'static>;
type SubCommandInfo (line 329) | pub type SubCommandInfo = argh_shared::SubCommandInfo<'static>;
type ArgsInfo (line 334) | pub trait ArgsInfo {
method get_args_info (line 336) | fn get_args_info() -> CommandInfoWithArgs;
method get_subcommands (line 339) | fn get_subcommands() -> Vec<SubCommandInfo> {
type FromArgs (line 345) | pub trait FromArgs: Sized {
method from_args (line 466) | fn from_args(command_name: &[&str], args: &[&str]) -> Result<Self, Ear...
type TopLevelCommand (line 470) | pub trait TopLevelCommand: FromArgs {}
type SubCommands (line 473) | pub trait SubCommands: FromArgs {
constant COMMANDS (line 475) | const COMMANDS: &'static [&'static CommandInfo];
method dynamic_commands (line 478) | fn dynamic_commands() -> &'static [&'static CommandInfo] {
constant COMMANDS (line 490) | const COMMANDS: &'static [&'static CommandInfo] = &[T::COMMAND];
type SubCommand (line 484) | pub trait SubCommand: FromArgs {
constant COMMAND (line 486) | const COMMAND: &'static CommandInfo;
type DynamicSubCommand (line 494) | pub trait DynamicSubCommand: Sized {
method commands (line 496) | fn commands() -> &'static [&'static CommandInfo];
method try_redact_arg_values (line 506) | fn try_redact_arg_values(
method try_from_args (line 518) | fn try_from_args(command_name: &[&str], args: &[&str]) -> Option<Resul...
type EarlyExit (line 525) | pub struct EarlyExit {
method from (line 533) | fn from(err_msg: String) -> Self {
type FromArgValue (line 547) | pub trait FromArgValue: Sized {
method from_arg_value (line 550) | fn from_arg_value(value: &str) -> Result<Self, String>;
method from_arg_value (line 558) | fn from_arg_value(value: &str) -> Result<Self, String> {
type ParseFlag (line 567) | pub trait ParseFlag {
method set_flag (line 568) | fn set_flag(&mut self, arg: &str);
method set_flag (line 572) | fn set_flag(&mut self, _arg: &str) {
type ParseValueSlot (line 584) | pub trait ParseValueSlot {
method fill_slot (line 585) | fn fill_slot(&mut self, arg: &str, value: &str) -> Result<(), String>;
method fill_slot (line 603) | fn fill_slot(&mut self, arg: &str, value: &str) -> Result<(), String> {
method fill_slot (line 614) | fn fill_slot(&mut self, arg: &str, value: &str) -> Result<(), String> {
method fill_slot (line 622) | fn fill_slot(&mut self, arg: &str, value: &str) -> Result<(), String> {
type ParseValueSlotTy (line 593) | pub struct ParseValueSlotTy<Slot, T> {
type Flag (line 631) | pub trait Flag {
method default (line 633) | fn default() -> Self
method set_flag (line 638) | fn set_flag(&mut self);
method default (line 642) | fn default() -> Self {
method set_flag (line 645) | fn set_flag(&mut self) {
method default (line 651) | fn default() -> Self {
method set_flag (line 655) | fn set_flag(&mut self) {
function parse_struct_args (line 686) | pub fn parse_struct_args(
type ParseStructOptions (line 743) | pub struct ParseStructOptions<'a> {
function parse (line 763) | fn parse(&mut self, arg: &str, remaining_args: &mut &[&str]) -> Result<(...
function unrecognized_argument (line 796) | fn unrecognized_argument(
type ParseStructOption (line 817) | pub enum ParseStructOption<'a> {
type ParseStructPositionals (line 826) | pub struct ParseStructPositionals<'a> {
function parse (line 839) | fn parse(&mut self, index: &mut usize, arg: &str) -> Result<bool, EarlyE...
type ParseStructPositional (line 864) | pub struct ParseStructPositional<'a> {
function parse (line 876) | fn parse(&mut self, arg: &str) -> Result<(), EarlyExit> {
type ParseStructSubCommand (line 898) | pub struct ParseStructSubCommand<'a> {
function parse (line 910) | fn parse(
function prepend_help (line 945) | fn prepend_help<'a>(args: &[&'a str]) -> Vec<&'a str> {
function print_subcommands (line 950) | pub fn print_subcommands<'a>(commands: impl Iterator<Item = &'a CommandI...
function unrecognized_arg (line 958) | fn unrecognized_arg(arg: &str) -> String {
type MissingRequirements (line 965) | pub struct MissingRequirements {
method missing_option (line 976) | pub fn missing_option(&mut self, name: &'static str) {
method missing_subcommands (line 982) | pub fn missing_subcommands(&mut self, commands: impl Iterator<Item = &...
method missing_positional_arg (line 988) | pub fn missing_positional_arg(&mut self, name: &'static str) {
method err_on_any (line 995) | pub fn err_on_any(&self) -> Result<(), String> {
constant NEWLINE_INDENT (line 971) | const NEWLINE_INDENT: &str = "\n ";
type CommandInfo (line 1047) | pub struct CommandInfo<'a> {
type CommandInfoWithArgs (line 1056) | pub struct CommandInfoWithArgs<'a> {
type ErrorCodeInfo (line 1077) | pub struct ErrorCodeInfo<'a> {
type PositionalInfo (line 1086) | pub struct PositionalInfo<'a> {
type SubCommandInfo (line 1104) | pub struct SubCommandInfo<'a> {
type FlagInfo (line 1113) | pub struct FlagInfo<'a> {
type FlagInfoKind (line 1133) | pub enum FlagInfoKind<'a> {
type Optionality (line 1145) | pub enum Optionality {
constant INDENT (line 1162) | pub const INDENT: &str = " ";
constant DESCRIPTION_INDENT (line 1163) | const DESCRIPTION_INDENT: usize = 20;
constant WRAP_WIDTH (line 1164) | const WRAP_WIDTH: usize = 80;
function write_description (line 1167) | pub fn write_description(out: &mut String, cmd: &CommandInfo<'_>) {
function indent_description (line 1204) | fn indent_description(line: &mut String) -> bool {
function char_len (line 1215) | fn char_len(s: &str) -> usize {
function new_line (line 1221) | fn new_line(current_line: &mut String, out: &mut String) {
FILE: native/src/base/base.cpp
function mut_u8_patch (line 52) | rust::Vec<size_t> mut_u8_patch(MutByteSlice buf, ByteSlice from, ByteSli...
function fork_dont_care (line 57) | int fork_dont_care() {
function fork_no_orphan (line 67) | int fork_no_orphan() {
function exec_command (line 77) | int exec_command(exec_t &exec) {
function exec_command_sync (line 123) | int exec_command_sync(exec_t &exec) {
function new_daemon_thread (line 132) | int new_daemon_thread(thread_entry entry, void *arg) {
function init_argv0 (line 146) | void init_argv0(int argc, char **argv) {
function set_nice_name (line 151) | void set_nice_name(Utf8CStr name) {
function T (line 158) | static T parse_num(string_view s) {
function parse_int (line 181) | int parse_int(string_view s) {
function parse_uint32_hex (line 185) | uint32_t parse_uint32_hex(string_view s) {
function switch_mnt_ns (line 189) | int switch_mnt_ns(int pid) {
function string (line 209) | string &replace_all(string &str, string_view from, string_view to) {
function split_impl (line 219) | static auto split_impl(string_view s, string_view delims) {
function split (line 233) | vector<string> split(string_view s, string_view delims) {
function vssprintf (line 238) | int vssprintf(char *dest, size_t size, const char *fmt, va_list ap) {
function ssprintf (line 246) | int ssprintf(char *dest, size_t size, const char *fmt, ...) {
function strscpy (line 255) | size_t strscpy(char *dest, const char *src, size_t size) {
function fmt_and_log_with_rs (line 260) | static int fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ...
function magisk_log_print (line 271) | int magisk_log_print(int prio, const char *tag, const char *fmt, ...) {
function LOGD (line 317) | void LOGD(const char *fmt, ...) {}
function __vloge (line 324) | void __vloge(const char* fmt, va_list ap) {
function string (line 328) | string full_read(int fd) {
function string (line 336) | string full_read(const char *filename) {
function write_zero (line 345) | void write_zero(int fd, size_t size) {
function sDIR (line 355) | sDIR make_dir(DIR *dp) {
function sFILE (line 359) | sFILE make_file(FILE *fp) {
function string (line 396) | string resolve_preinit_dir(const char *base_dir) {
FILE: native/src/base/build.rs
function main (line 6) | fn main() {
FILE: native/src/base/cstr.rs
function dynamic (line 45) | pub fn dynamic(capacity: usize) -> Utf8CString {
function default (line 50) | pub fn default() -> Utf8CStrBufArr<4096> {
function new (line 55) | pub fn new<const N: usize>() -> Utf8CStrBufArr<N> {
function wrap (line 60) | pub fn wrap(buf: &mut [u8]) -> Utf8CStrBufRef<'_> {
function wrap_ptr (line 65) | pub unsafe fn wrap_ptr<'a>(buf: *mut u8, len: usize) -> Utf8CStrBufRef<'...
type Utf8CStrBuf (line 72) | pub trait Utf8CStrBuf: Display + Write + AsRef<Utf8CStr> + Deref<Target ...
method len (line 75) | fn len(&self) -> usize;
method push_str (line 76) | fn push_str(&mut self, s: &str) -> usize;
method capacity (line 79) | fn capacity(&self) -> usize;
method clear (line 80) | fn clear(&mut self);
method as_mut_ptr (line 81) | fn as_mut_ptr(&mut self) -> *mut c_char;
method truncate (line 82) | fn truncate(&mut self, new_len: usize);
method rebuild (line 86) | fn rebuild(&mut self) -> Result<(), StrErr>;
method is_empty (line 89) | fn is_empty(&self) -> bool {
method len (line 157) | fn len(&self) -> usize {
method push_str (line 161) | fn push_str(&mut self, s: &str) -> usize {
method capacity (line 167) | fn capacity(&self) -> usize {
method clear (line 171) | fn clear(&mut self) {
method as_mut_ptr (line 176) | fn as_mut_ptr(&mut self) -> *mut c_char {
method truncate (line 180) | fn truncate(&mut self, new_len: usize) {
method rebuild (line 185) | fn rebuild(&mut self) -> Result<(), StrErr> {
type StringExt (line 94) | pub trait StringExt {
method nul_terminate (line 95) | fn nul_terminate(&mut self) -> &mut [u8];
method nul_terminate (line 99) | fn nul_terminate(&mut self) -> &mut [u8] {
method nul_terminate (line 113) | fn nul_terminate(&mut self) -> &mut [u8] {
type Utf8CString (line 126) | pub struct Utf8CString(String);
method with_capacity (line 135) | pub fn with_capacity(capacity: usize) -> Utf8CString {
method ensure_capacity (line 139) | pub fn ensure_capacity(&mut self, capacity: usize) {
method as_ref (line 149) | fn as_ref(&self) -> &Utf8CStr {
method from (line 213) | fn from(mut value: String) -> Self {
method from (line 220) | fn from(value: &str) -> Self {
method borrow (line 237) | fn borrow(&self) -> &Utf8CStr {
method default (line 129) | fn default() -> Self {
type Err (line 229) | type Err = String;
method from_str (line 231) | fn from_str(s: &str) -> Result<Self, Self::Err> {
type Utf8CStrBufRef (line 243) | pub struct Utf8CStrBufRef<'a> {
function from_ptr (line 249) | pub unsafe fn from_ptr(buf: *mut u8, len: usize) -> Utf8CStrBufRef<'a> {
function from (line 255) | fn from(buf: &'a mut [u8]) -> Utf8CStrBufRef<'a> {
type Utf8CStrBufArr (line 262) | pub struct Utf8CStrBufArr<const N: usize> {
function new (line 268) | pub fn new() -> Self {
method default (line 277) | fn default() -> Self {
type StrErr (line 283) | pub enum StrErr {
type Utf8CStr (line 296) | pub struct Utf8CStr([u8]);
method from_cstr (line 299) | pub fn from_cstr(cstr: &CStr) -> Result<&Utf8CStr, StrErr> {
method from_bytes_until_nul (line 305) | fn from_bytes_until_nul(bytes: &[u8]) -> Result<&Utf8CStr, StrErr> {
method from_bytes (line 309) | pub fn from_bytes(bytes: &[u8]) -> Result<&Utf8CStr, StrErr> {
method from_string (line 313) | pub fn from_string(s: &mut String) -> &Utf8CStr {
method from_bytes_unchecked (line 320) | pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Utf8CStr {
method from_ptr (line 324) | pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> Result<&'a Utf8CStr,...
method from_ptr_unchecked (line 331) | pub unsafe fn from_ptr_unchecked<'a>(ptr: *const c_char) -> &'a Utf8CS...
method from_raw_parts (line 338) | pub unsafe fn from_raw_parts<'a>(ptr: *const c_char, len: usize) -> &'...
method as_bytes_with_nul (line 346) | pub fn as_bytes_with_nul(&self) -> &[u8] {
method as_ptr (line 351) | pub fn as_ptr(&self) -> *const c_char {
method as_cstr (line 356) | pub fn as_cstr(&self) -> &CStr {
method as_utf8_cstr (line 362) | pub fn as_utf8_cstr(&self) -> &Utf8CStr {
method as_str (line 367) | pub fn as_str(&self) -> &str {
method as_ref (line 394) | fn as_ref(&self) -> &Utf8CStr {
type Target (line 375) | type Target = str;
method deref (line 378) | fn deref(&self) -> &str {
type Owned (line 384) | type Owned = Utf8CString;
method to_owned (line 386) | fn to_owned(&self) -> Utf8CString {
method is_empty (line 401) | fn is_empty(&self) -> bool {
method len (line 406) | fn len(&self) -> usize {
method with_nix_path (line 411) | fn with_nix_path<T, F>(&self, f: F) -> nix::Result<T>
type Id (line 421) | type Id = type_id!("Utf8CStr");
type Kind (line 422) | type Kind = cxx::kind::Trivial;
type FsPathFollow (line 438) | pub struct FsPathFollow(Utf8CStr);
method as_ref (line 442) | fn as_ref(&self) -> &Utf8CStr {
function copy_cstr_truncate (line 559) | fn copy_cstr_truncate(dest: &mut [u8], src: &[u8]) -> usize {
FILE: native/src/base/cxx_extern.rs
function canonical_path (line 21) | unsafe extern "C" fn canonical_path(path: *const c_char, buf: *mut u8, b...
function mkdirs_for_cxx (line 36) | unsafe extern "C" fn mkdirs_for_cxx(path: *const c_char, mode: mode_t) -...
function rm_rf_for_cxx (line 46) | unsafe extern "C" fn rm_rf_for_cxx(path: *const c_char) -> bool {
function map_file_for_cxx (line 55) | pub(crate) fn map_file_for_cxx(path: &Utf8CStr, rw: bool) -> &'static mu...
function map_file_at_for_cxx (line 59) | pub(crate) fn map_file_at_for_cxx(fd: RawFd, path: &Utf8CStr, rw: bool) ...
function map_fd_for_cxx (line 67) | pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static...
function readlinkat (line 75) | pub(crate) unsafe fn readlinkat(
function cp_afc_for_cxx (line 103) | unsafe extern "C" fn cp_afc_for_cxx(src: *const c_char, dest: *const c_c...
function mv_path_for_cxx (line 115) | unsafe extern "C" fn mv_path_for_cxx(src: *const c_char, dest: *const c_...
function link_path_for_cxx (line 127) | unsafe extern "C" fn link_path_for_cxx(src: *const c_char, dest: *const ...
function clone_attr_for_cxx (line 139) | unsafe extern "C" fn clone_attr_for_cxx(src: *const c_char, dest: *const...
function fclone_attr_for_cxx (line 151) | unsafe extern "C" fn fclone_attr_for_cxx(a: RawFd, b: RawFd) -> bool {
function str_new (line 156) | unsafe extern "C" fn str_new(this: &mut &Utf8CStr, s: *const u8, len: us...
function str_ptr (line 163) | unsafe extern "C" fn str_ptr(this: &&Utf8CStr) -> *const u8 {
function str_len (line 168) | unsafe extern "C" fn str_len(this: &&Utf8CStr) -> usize {
function parse_prop_file_rs (line 172) | pub(crate) fn parse_prop_file_rs(name: &Utf8CStr, f: &FnBoolStrStr) {
function file_readline_for_cxx (line 178) | pub(crate) fn file_readline_for_cxx(fd: RawFd, f: &FnBoolStr) {
FILE: native/src/base/derive/argh/errors.rs
type Errors (line 11) | pub struct Errors {
method duplicate_attrs (line 52) | pub fn duplicate_attrs(
method duplicate_attrs_inner (line 61) | fn duplicate_attrs_inner(&self, attr_kind: &str, first: Span, second: ...
method unexpected_lit (line 83) | fn unexpected_lit(&self, expected: &str, found: &syn::Expr) {
method unexpected_meta (line 124) | fn unexpected_meta(&self, expected: &str, found: &syn::Meta) {
method err (line 148) | pub fn err(&self, spanned: &impl syn::spanned::Spanned, msg: &str) {
method err_span (line 153) | pub fn err_span(&self, span: Span, msg: &str) {
method err_span_tokens (line 158) | pub fn err_span_tokens<T: ToTokens>(&self, tokens: T, msg: &str) {
method push (line 163) | pub fn push(&self, err: syn::Error) {
method ok (line 168) | pub fn ok<T>(&self, r: syn::Result<T>) -> Option<T> {
method to_tokens (line 182) | fn to_tokens(&self, tokens: &mut TokenStream) {
FILE: native/src/base/derive/argh/mod.rs
function impl_from_args (line 26) | pub(crate) fn impl_from_args(input: &syn::DeriveInput) -> TokenStream {
type Optionality (line 46) | enum Optionality {
method eq (line 55) | fn eq(&self, other: &Optionality) -> bool {
method is_required (line 64) | fn is_required(&self) -> bool {
type StructField (line 71) | struct StructField<'a> {
function new (line 99) | fn new(errors: &Errors, field: &'a syn::Field, attrs: FieldAttrs) -> Opt...
function positional_arg_name (line 216) | pub(crate) fn positional_arg_name(&self) -> String {
function option_arg_name (line 224) | fn option_arg_name(&self) -> String {
function to_kebab_case (line 234) | fn to_kebab_case(s: &str) -> String {
function impl_from_args_struct (line 247) | fn impl_from_args_struct(
function impl_from_args_struct_from_args (line 303) | fn impl_from_args_struct_from_args<'a>(
function get_help_triggers (line 425) | fn get_help_triggers(type_attrs: &TypeAttrs) -> Vec<String> {
function ensure_only_trailing_positionals_are_optional (line 450) | fn ensure_only_trailing_positionals_are_optional(errors: &Errors, fields...
function ensure_unique_names (line 475) | fn ensure_unique_names(errors: &Errors, fields: &[StructField<'_>]) {
function top_or_sub_cmd_impl (line 511) | fn top_or_sub_cmd_impl(
function declare_local_storage_for_from_args_fields (line 551) | fn declare_local_storage_for_from_args_fields<'a>(
function unwrap_from_args_fields (line 599) | fn unwrap_from_args_fields<'a>(
function flag_str_to_output_table_map_entries (line 630) | fn flag_str_to_output_table_map_entries<'a>(fields: &'a [StructField<'a>...
function append_missing_requirements (line 646) | fn append_missing_requirements<'a>(
function ty_expect_switch (line 698) | fn ty_expect_switch(errors: &Errors, ty: &syn::Type) -> bool {
function ty_inner (line 737) | fn ty_inner<'a>(wrapper_names: &[&str], ty: &'a syn::Type) -> Option<&'a...
function impl_from_args_enum (line 762) | fn impl_from_args_enum(
function enum_only_single_field_unnamed_variants (line 860) | fn enum_only_single_field_unnamed_variants<'a>(
FILE: native/src/base/derive/argh/parse_attrs.rs
type FieldAttrs (line 14) | pub struct FieldAttrs {
method parse (line 65) | pub fn parse(errors: &Errors, field: &syn::Field) -> Self {
method parse_attr_from_str_fn (line 169) | fn parse_attr_from_str_fn(&mut self, errors: &Errors, m: &syn::MetaLis...
method parse_attr_default (line 173) | fn parse_attr_default(&mut self, errors: &Errors, m: &syn::MetaNameVal...
method parse_attr_arg_name (line 177) | fn parse_attr_arg_name(&mut self, errors: &Errors, m: &syn::MetaNameVa...
method parse_attr_long (line 181) | fn parse_attr_long(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
method parse_attr_short (line 198) | fn parse_attr_short(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
type FieldKind (line 28) | pub enum FieldKind {
type FieldType (line 49) | pub struct FieldType {
type Description (line 58) | pub struct Description {
function check_long_name (line 210) | pub(crate) fn check_long_name(errors: &Errors, spanned: &impl syn::spann...
function parse_attr_fn_name (line 225) | fn parse_attr_fn_name(
function parse_attr_field_type (line 238) | fn parse_attr_field_type(
function is_matching_attr (line 257) | fn is_matching_attr(name: &str, attr: &syn::Attribute) -> bool {
function is_doc_attr (line 262) | fn is_doc_attr(attr: &syn::Attribute) -> bool {
function is_argh_attr (line 267) | fn is_argh_attr(attr: &syn::Attribute) -> bool {
function argh_attr_to_meta_list (line 272) | fn argh_attr_to_meta_list(
type TypeAttrs (line 287) | pub struct TypeAttrs {
method parse (line 300) | pub fn parse(errors: &Errors, derive_input: &syn::DeriveInput) -> Self {
method check_error_codes (line 372) | fn check_error_codes(&self, errors: &Errors) {
method parse_attr_error_code (line 403) | fn parse_attr_error_code(&mut self, errors: &Errors, ml: &syn::MetaLis...
method parse_attr_example (line 418) | fn parse_attr_example(&mut self, errors: &Errors, m: &syn::MetaNameVal...
method parse_attr_name (line 422) | fn parse_attr_name(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
method parse_attr_note (line 431) | fn parse_attr_note(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
method parse_attr_subcommand (line 435) | fn parse_attr_subcommand(&mut self, errors: &Errors, ident: &syn::Iden...
method parse_help_triggers (line 444) | fn parse_help_triggers(m: &syn::MetaList, errors: &Errors, this: &mut ...
type VariantAttrs (line 468) | pub struct VariantAttrs {
method parse (line 474) | pub fn parse(errors: &Errors, variant: &syn::Variant) -> Self {
function check_option_description (line 520) | fn check_option_description(errors: &Errors, desc: &str, span: Span) {
function parse_attr_single_string (line 533) | fn parse_attr_single_string(
function parse_attr_multi_string (line 546) | fn parse_attr_multi_string(errors: &Errors, m: &syn::MetaNameValue, list...
function parse_attr_doc (line 552) | fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Opt...
function unescape_doc (line 586) | fn unescape_doc(s: String) -> String {
function parse_attr_description (line 610) | fn parse_attr_description(errors: &Errors, m: &syn::MetaNameValue, slot:...
function check_enum_type_attrs (line 632) | pub fn check_enum_type_attrs(errors: &Errors, type_attrs: &TypeAttrs, ty...
function err_unused_enum_attr (line 679) | fn err_unused_enum_attr(errors: &Errors, location: &impl syn::spanned::S...
FILE: native/src/base/derive/decodable.rs
function derive_decodable (line 6) | pub(crate) fn derive_decodable(input: proc_macro::TokenStream) -> proc_m...
function gen_encode (line 45) | fn gen_encode(data: &Data) -> TokenStream {
function gen_decode (line 71) | fn gen_decode(data: &Data) -> TokenStream {
FILE: native/src/base/derive/lib.rs
function derive_decodable (line 9) | pub fn derive_decodable(input: TokenStream) -> TokenStream {
function argh_derive (line 15) | pub fn argh_derive(input: TokenStream) -> TokenStream {
FILE: native/src/base/dir.rs
type DirEntry (line 17) | pub struct DirEntry<'a> {
function as_ptr (line 24) | pub fn as_ptr(&self) -> *mut dirent {
function name (line 28) | pub fn name(&self) -> &Utf8CStr {
function resolve_path (line 38) | pub fn resolve_path(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'stati...
function is_dir (line 42) | pub fn is_dir(&self) -> bool {
function is_file (line 46) | pub fn is_file(&self) -> bool {
function is_symlink (line 50) | pub fn is_symlink(&self) -> bool {
function is_block_device (line 54) | pub fn is_block_device(&self) -> bool {
function is_char_device (line 58) | pub fn is_char_device(&self) -> bool {
function is_fifo (line 62) | pub fn is_fifo(&self) -> bool {
function is_socket (line 66) | pub fn is_socket(&self) -> bool {
function unlink (line 70) | pub fn unlink(&self) -> OsResult<'_, ()> {
function read_link (line 79) | pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'_, ()> {
function open_as_dir (line 83) | pub fn open_as_dir(&self) -> OsResult<'_, Directory> {
function open_as_file (line 95) | pub fn open_as_file(&self, flags: OFlag) -> OsResult<'_, File> {
function rename_to (line 107) | pub fn rename_to<'a, 'entry: 'a>(
type Target (line 117) | type Target = dirent;
method deref (line 119) | fn deref(&self) -> &dirent {
type Directory (line 125) | pub struct Directory {
method open_at (line 136) | fn open_at<'a>(&self, name: &'a Utf8CStr, flags: OFlag, mode: mode_t) ...
method path_at (line 146) | fn path_at(&self, name: &Utf8CStr, buf: &mut dyn Utf8CStrBuf) -> OsRes...
method open (line 155) | pub fn open(path: &Utf8CStr) -> OsResult<'_, Directory> {
method read (line 161) | pub fn read(&mut self) -> OsResult<'static, Option<DirEntry<'_>>> {
method rewind (line 192) | pub fn rewind(&mut self) {
method open_as_dir_at (line 196) | pub fn open_as_dir_at<'a>(&self, name: &'a Utf8CStr) -> OsResult<'a, D...
method open_as_file_at (line 201) | pub fn open_as_file_at<'a>(
method read_link_at (line 211) | pub fn read_link_at<'a>(
method mkdir_at (line 230) | pub fn mkdir_at<'a>(&self, name: &'a Utf8CStr, mode: mode_t) -> OsResu...
method create_symlink_at (line 238) | pub fn create_symlink_at<'a>(
method unlink_at (line 250) | pub fn unlink_at<'a>(&self, name: &'a Utf8CStr, flag: UnlinkatFlags) -...
method contains_path (line 254) | pub fn contains_path(&self, path: &Utf8CStr) -> bool {
method resolve_path (line 261) | pub fn resolve_path(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'sta...
method rename_at (line 265) | pub fn rename_at<'a>(
method post_order_walk (line 278) | pub fn post_order_walk<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
method pre_order_walk (line 285) | pub fn pre_order_walk<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
method remove_all (line 292) | pub fn remove_all(mut self) -> LoggedResult<()> {
method copy_into (line 300) | pub fn copy_into(&mut self, dir: &Directory) -> LoggedResult<()> {
method move_into (line 305) | pub fn move_into(&mut self, dir: &Directory) -> LoggedResult<()> {
method link_into (line 319) | pub fn link_into(&mut self, dir: &Directory) -> LoggedResult<()> {
method post_order_walk_impl (line 326) | fn post_order_walk_impl<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
method pre_order_walk_impl (line 351) | fn pre_order_walk_impl<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
method copy_into_impl (line 375) | fn copy_into_impl(
method link_into_impl (line 408) | fn link_into_impl(
type Error (line 432) | type Error = OsError<'static>;
method try_from (line 434) | fn try_from(fd: OwnedFd) -> OsResult<'static, Self> {
type WalkResult (line 129) | pub enum WalkResult {
method as_raw_fd (line 442) | fn as_raw_fd(&self) -> RawFd {
method as_fd (line 448) | fn as_fd(&self) -> BorrowedFd<'_> {
method drop (line 454) | fn drop(&mut self) {
FILE: native/src/base/files.rs
type ReadExt (line 24) | pub trait ReadExt {
method skip (line 25) | fn skip(&mut self, len: usize) -> io::Result<()>;
method read_pod (line 26) | fn read_pod<F: Pod>(&mut self, data: &mut F) -> io::Result<()>;
method skip (line 30) | fn skip(&mut self, mut len: usize) -> io::Result<()> {
method read_pod (line 41) | fn read_pod<F: Pod>(&mut self, data: &mut F) -> io::Result<()> {
type ReadSeekExt (line 46) | pub trait ReadSeekExt {
method skip (line 47) | fn skip(&mut self, len: usize) -> io::Result<()>;
method skip (line 51) | fn skip(&mut self, len: usize) -> io::Result<()> {
type BufReadExt (line 60) | pub trait BufReadExt {
method for_each_line (line 61) | fn for_each_line<F: FnMut(&mut String) -> bool>(&mut self, f: F);
method for_each_prop (line 62) | fn for_each_prop<F: FnMut(&str, &str) -> bool>(&mut self, f: F);
method for_each_line (line 66) | fn for_each_line<F: FnMut(&mut String) -> bool>(&mut self, mut f: F) {
method for_each_prop (line 85) | fn for_each_prop<F: FnMut(&str, &str) -> bool>(&mut self, mut f: F) {
type WriteExt (line 102) | pub trait WriteExt {
method write_zeros (line 103) | fn write_zeros(&mut self, len: usize) -> io::Result<()>;
method write_pod (line 104) | fn write_pod<F: Pod>(&mut self, data: &F) -> io::Result<()>;
method write_zeros (line 108) | fn write_zeros(&mut self, mut len: usize) -> io::Result<()> {
method write_pod (line 118) | fn write_pod<F: Pod>(&mut self, data: &F) -> io::Result<()> {
type FileOrStd (line 123) | pub enum FileOrStd {
method as_file (line 131) | pub fn as_file(&self) -> &File {
function open_fd (line 143) | fn open_fd(path: &Utf8CStr, flags: OFlag, mode: mode_t) -> OsResult<'_, ...
function fd_path (line 151) | pub fn fd_path(fd: RawFd, buf: &mut dyn Utf8CStrBuf) -> OsResult<'static...
type FileAttr (line 158) | pub struct FileAttr {
method new (line 171) | pub fn new() -> Self {
method is (line 181) | fn is(&self, mode: mode_t) -> bool {
method is_dir (line 185) | pub fn is_dir(&self) -> bool {
method is_file (line 189) | pub fn is_file(&self) -> bool {
method is_symlink (line 193) | pub fn is_symlink(&self) -> bool {
method is_block_device (line 197) | pub fn is_block_device(&self) -> bool {
method is_char_device (line 201) | pub fn is_char_device(&self) -> bool {
method is_fifo (line 205) | pub fn is_fifo(&self) -> bool {
method is_socket (line 209) | pub fn is_socket(&self) -> bool {
method is_whiteout (line 213) | pub fn is_whiteout(&self) -> bool {
method default (line 165) | fn default() -> Self {
constant XATTR_NAME_SELINUX (line 218) | const XATTR_NAME_SELINUX: &CStr = c"security.selinux";
method follow_link (line 222) | pub fn follow_link(&self) -> &FsPathFollow {
method open (line 226) | pub fn open(&self, flags: OFlag) -> OsResult<'_, File> {
method create (line 230) | pub fn create(&self, flags: OFlag, mode: mode_t) -> OsResult<'_, File> {
method exists (line 234) | pub fn exists(&self) -> bool {
method rename_to (line 238) | pub fn rename_to<'a>(&'a self, name: &'a Utf8CStr) -> OsResult<'a, ()> {
method remove (line 246) | pub fn remove(&self) -> OsResult<'_, ()> {
method read_link (line 251) | pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'_, ()> {
method mkdir (line 262) | pub fn mkdir(&self, mode: mode_t) -> OsResult<'_, ()> {
method realpath (line 270) | pub fn realpath(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'_, ()> {
method get_attr (line 292) | pub fn get_attr(&self) -> OsResult<'_, FileAttr> {
method set_attr (line 304) | pub fn set_attr<'a>(&'a self, attr: &'a FileAttr) -> OsResult<'a, ()> {
method get_secontext (line 330) | pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> OsResult<'_, (...
method set_secontext (line 352) | pub fn set_secontext<'a>(&'a self, con: &'a Utf8CStr) -> OsResult<'a, ()> {
method parent_dir (line 365) | pub fn parent_dir(&self) -> Option<&str> {
method file_name (line 373) | pub fn file_name(&self) -> Option<&str> {
method create_symlink_to (line 381) | pub fn create_symlink_to<'a>(&'a self, target: &'a Utf8CStr) -> OsResult...
method mkfifo (line 389) | pub fn mkfifo(&self, mode: mode_t) -> OsResult<'_, ()> {
method remove_all (line 401) | pub fn remove_all(&self) -> LoggedResult<()> {
method mkdirs (line 419) | pub fn mkdirs(&self, mode: mode_t) -> LoggedResult<()> {
method copy_to (line 443) | pub fn copy_to(&self, path: &Utf8CStr) -> LoggedResult<()> {
method move_to (line 476) | pub fn move_to(&self, path: &Utf8CStr) -> LoggedResult<()> {
method link_to (line 492) | pub fn link_to(&self, path: &Utf8CStr) -> LoggedResult<()> {
method exists (line 514) | pub fn exists(&self) -> bool {
method chmod (line 518) | pub fn chmod(&self, mode: mode_t) -> OsResult<'_, ()> {
method get_attr (line 528) | pub fn get_attr(&self) -> OsResult<'_, FileAttr> {
method set_attr (line 544) | pub fn set_attr<'a>(&'a self, attr: &'a FileAttr) -> OsResult<'a, ()> {
method get_secontext (line 561) | pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> OsResult<'_, (...
method set_secontext (line 583) | pub fn set_secontext<'a>(&'a self, con: &'a Utf8CStr) -> OsResult<'a, ()> {
type FsPathBuilder (line 597) | pub trait FsPathBuilder {
method join_path (line 598) | fn join_path<T: AsRef<str>>(mut self, path: T) -> Self
method join_path_fmt (line 605) | fn join_path_fmt<T: Display>(mut self, name: T) -> Self
method append_path (line 612) | fn append_path<T: AsRef<str>>(&mut self, path: T) -> &mut Self;
method append_path_fmt (line 613) | fn append_path_fmt<T: Display>(&mut self, name: T) -> &mut Self;
method append_path (line 627) | fn append_path<T: AsRef<str>>(&mut self, path: T) -> &mut Self {
method append_path_fmt (line 632) | fn append_path_fmt<T: Display>(&mut self, name: T) -> &mut Self {
method append_path (line 639) | fn append_path<T: AsRef<str>>(&mut self, path: T) -> &mut Self {
method append_path_fmt (line 644) | fn append_path_fmt<T: Display>(&mut self, name: T) -> &mut Self {
function append_path_impl (line 616) | fn append_path_impl(buf: &mut dyn Utf8CStrBuf, path: &str) {
function fd_get_attr (line 650) | pub fn fd_get_attr(fd: RawFd) -> OsResult<'static, FileAttr> {
function fd_set_attr (line 661) | pub fn fd_set_attr(fd: RawFd, attr: &FileAttr) -> OsResult<'_, ()> {
function fd_get_secontext (line 674) | pub fn fd_get_secontext(fd: RawFd, con: &mut dyn Utf8CStrBuf) -> OsResul...
function fd_set_secontext (line 696) | pub fn fd_set_secontext(fd: RawFd, con: &Utf8CStr) -> OsResult<'_, ()> {
function clone_attr (line 709) | pub fn clone_attr<'a>(a: &'a Utf8CStr, b: &'a Utf8CStr) -> OsResult<'a, ...
function fclone_attr (line 714) | pub fn fclone_attr(a: RawFd, b: RawFd) -> OsResult<'static, ()> {
type MappedFile (line 719) | pub struct MappedFile(&'static mut [u8]);
method open (line 722) | pub fn open(path: &Utf8CStr) -> OsResult<'_, MappedFile> {
method open_rw (line 726) | pub fn open_rw(path: &Utf8CStr) -> OsResult<'_, MappedFile> {
method openat (line 730) | pub fn openat<'a, T: AsFd>(dir: &T, path: &'a Utf8CStr) -> OsResult<'a...
method openat_rw (line 734) | pub fn openat_rw<'a, T: AsFd>(dir: &T, path: &'a Utf8CStr) -> OsResult...
method create (line 738) | pub fn create(fd: BorrowedFd, sz: usize, rw: bool) -> OsResult<MappedF...
method as_ref (line 744) | fn as_ref(&self) -> &[u8] {
method as_mut (line 750) | fn as_mut(&mut self) -> &mut [u8] {
method drop (line 756) | fn drop(&mut self) {
function ioctl (line 765) | fn ioctl(fd: RawFd, request: u32, ...) -> i32;
function map_file (line 769) | pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> OsResult<'_, &'stat...
function map_file_at (line 773) | pub(crate) fn map_file_at<'a>(
function map_fd (line 801) | pub(crate) fn map_fd(fd: BorrowedFd, sz: usize, rw: bool) -> OsResult<'s...
type MountInfo (line 824) | pub struct MountInfo {
function parse_mount_info_line (line 841) | fn parse_mount_info_line(line: &str) -> Option<MountInfo> {
function parse_mount_info (line 889) | pub fn parse_mount_info(pid: &str) -> Vec<MountInfo> {
FILE: native/src/base/include/base.hpp
type stat (line 34) | struct stat
type Utf8CStr (line 73) | struct Utf8CStr
method Utf8CStr (line 304) | Utf8CStr() : Utf8CStr("", 1) {}
method Utf8CStr (line 305) | Utf8CStr(const Utf8CStr &o) = default;
method Utf8CStr (line 306) | Utf8CStr(const char *s) : Utf8CStr(s, strlen(s) + 1) {}
method Utf8CStr (line 307) | Utf8CStr(std::string s) : Utf8CStr(s.data(), s.length() + 1) {}
method size (line 309) | size_t size() const { return this->length(); }
method empty (line 310) | bool empty() const { return this->length() == 0 ; }
method sv (line 311) | std::string_view sv() const { return {data(), length()}; }
class mutex_guard (line 75) | class mutex_guard {
method mutex_guard (line 78) | explicit mutex_guard(pthread_mutex_t &m): mutex(&m) {
method unlock (line 81) | void unlock() {
class run_finally (line 93) | class run_finally {
method run_finally (line 96) | explicit run_finally(Func &&fn) : fn(std::move(fn)) {}
function default_new (line 103) | static void default_new(T *&p) { p = new T(); }
function default_new (line 106) | static void default_new(std::unique_ptr<T> &p) { p.reset(new T()); }
type StringCmp (line 108) | struct StringCmp {
type byte_view (line 117) | struct byte_view {
method byte_view (line 118) | byte_view() : ptr(nullptr), sz(0) {}
method byte_view (line 119) | byte_view(const void *buf, size_t sz) : ptr((uint8_t *) buf), sz(sz) {}
method byte_view (line 122) | byte_view(const byte_view &o) : ptr(o.ptr), sz(o.sz) {}
method byte_view (line 125) | byte_view(const ByteSlice o) : byte_view(o.data(), o.size()) {}
method byte_view (line 129) | byte_view(const char *s) : byte_view(s, strlen(s) + 1) {}
method size (line 132) | size_t size() const { return sz; }
type byte_data (line 140) | struct byte_data : public byte_view {
method byte_data (line 141) | byte_data() = default;
method byte_data (line 142) | byte_data(void *buf, size_t sz) : byte_view(buf, sz) {}
method byte_data (line 145) | byte_data(const byte_data &o) : byte_data(o.ptr, o.sz) {}
method byte_data (line 148) | byte_data(const MutByteSlice o) : byte_data(o.data(), o.size()) {}
type mmap_data (line 157) | struct mmap_data : public byte_data {
method mmap_data (line 160) | mmap_data() = default;
type owned_fd (line 170) | struct owned_fd {
method owned_fd (line 173) | owned_fd() : fd(-1) {}
method owned_fd (line 174) | owned_fd(int fd) : fd(fd) {}
method release (line 178) | int release() { int f = fd; fd = -1; return f; }
method swap (line 179) | void swap(owned_fd &owned) { std::swap(fd, owned.fd); }
function rtrim (line 193) | static inline std::string rtrim(std::string &&s) {
type exec_t (line 221) | struct exec_t {
function exec_command (line 231) | int exec_command(exec_t &exec, Args &&...args) {
function exec_command_sync (line 238) | int exec_command_sync(exec_t &exec, Args &&...args) {
function exec_command_sync (line 244) | int exec_command_sync(Args &&...args) {
function exec_command_async (line 249) | void exec_command_async(Args &&...args) {
function sDIR (line 274) | static inline sDIR open_dir(const char *path) {
function sDIR (line 278) | static inline sDIR xopen_dir(const char *path) {
function sDIR (line 282) | static inline sDIR xopen_dir(int dirfd) {
function sFILE (line 286) | static inline sFILE open_file(const char *path, const char *mode) {
function sFILE (line 290) | static inline sFILE xopen_file(const char *path, const char *mode) {
function sFILE (line 294) | static inline sFILE xopen_file(int fd, const char *mode) {
type Utf8CStr (line 299) | struct Utf8CStr {
method Utf8CStr (line 304) | Utf8CStr() : Utf8CStr("", 1) {}
method Utf8CStr (line 305) | Utf8CStr(const Utf8CStr &o) = default;
method Utf8CStr (line 306) | Utf8CStr(const char *s) : Utf8CStr(s, strlen(s) + 1) {}
method Utf8CStr (line 307) | Utf8CStr(std::string s) : Utf8CStr(s.data(), s.length() + 1) {}
method size (line 309) | size_t size() const { return this->length(); }
method empty (line 310) | bool empty() const { return this->length() == 0 ; }
method sv (line 311) | std::string_view sv() const { return {data(), length()}; }
type FnBoolStrStr (line 324) | struct FnBoolStrStr : public CxxFnBoolStrStr {
method call (line 326) | bool call(rust::Str a, rust::Str b) const {
type FnBoolStr (line 331) | struct FnBoolStr : public CxxFnBoolStr {
method call (line 333) | bool call(Utf8CStr s) const {
function parse_prop_file (line 342) | void parse_prop_file(const char *file, Functor &&fn) {
FILE: native/src/base/lib.rs
type LogLevelCxx (line 33) | pub(crate) enum LogLevelCxx {
type Utf8CStrRef (line 44) | type Utf8CStrRef<'a> = &'a crate::cstr::Utf8CStr;
function mut_u8_patch (line 46) | fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
function fork_dont_care (line 47) | fn fork_dont_care() -> i32;
function set_nice_name (line 48) | fn set_nice_name(name: Utf8CStrRef);
function call (line 51) | fn call(self: &FnBoolStrStr, key: &str, value: &str) -> bool;
function call (line 54) | fn call(self: &FnBoolStr, key: Utf8CStrRef) -> bool;
function log_from_cxx (line 59) | fn log_from_cxx(level: LogLevelCxx, msg: Utf8CStrRef);
function cmdline_logging (line 60) | fn cmdline_logging();
function parse_prop_file_rs (line 61) | fn parse_prop_file_rs(name: Utf8CStrRef, f: &FnBoolStrStr);
function file_readline_for_cxx (line 63) | fn file_readline_for_cxx(fd: i32, f: &FnBoolStr);
function xpipe2 (line 64) | fn xpipe2(fds: &mut [i32; 2], flags: i32) -> i32;
function map_file_for_cxx (line 70) | fn map_file_for_cxx(path: Utf8CStrRef, rw: bool) -> &'static mut [u8];
function map_file_at_for_cxx (line 72) | fn map_file_at_for_cxx(fd: i32, path: Utf8CStrRef, rw: bool) -> &'static...
function map_fd_for_cxx (line 74) | fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8];
type ThreadEntry (line 80) | pub type ThreadEntry = extern "C" fn(usize) -> usize;
function new_daemon_thread (line 82) | pub fn new_daemon_thread(entry: ThreadEntry, arg: usize);
FILE: native/src/base/logging.rs
type LogLevel (line 23) | pub enum LogLevel {
method as_disable_flag (line 59) | fn as_disable_flag(&self) -> LogFlag {
type LogWriter (line 37) | type LogWriter = fn(level: LogLevel, msg: &Utf8CStr);
type Formatter (line 38) | pub(crate) type Formatter<'a> = &'a mut dyn fmt::Write;
type Logger (line 41) | pub struct Logger {
function update_logger (line 46) | pub fn update_logger(f: impl FnOnce(&mut Logger)) {
function exit_on_error (line 54) | pub fn exit_on_error(b: bool) {
function set_log_level_state (line 69) | pub fn set_log_level_state(level: LogLevel, enabled: bool) {
function log_with_writer (line 73) | fn log_with_writer<F: FnOnce(LogWriter)>(level: LogLevel, f: F) {
function log_from_cxx (line 84) | pub fn log_from_cxx(level: LogLevelCxx, msg: &Utf8CStr) {
function log_with_formatter (line 90) | pub fn log_with_formatter<F: FnOnce(Formatter) -> fmt::Result>(level: Lo...
function cmdline_logging (line 98) | pub fn cmdline_logging() {
FILE: native/src/base/misc.rs
function errno (line 12) | pub fn errno() -> &'static mut i32 {
function slice_from_ptr (line 18) | pub unsafe fn slice_from_ptr<'a, T>(buf: *const T, len: usize) -> &'a [T] {
function slice_from_ptr_mut (line 30) | pub unsafe fn slice_from_ptr_mut<'a, T>(buf: *mut T, len: usize) -> &'a ...
type BytesExt (line 40) | pub trait BytesExt {
method find (line 41) | fn find(&self, needle: &[u8]) -> Option<usize>;
method contains (line 42) | fn contains(&self, needle: &[u8]) -> bool {
method find (line 48) | fn find(&self, needle: &[u8]) -> Option<usize> {
type MutBytesExt (line 69) | pub trait MutBytesExt {
method patch (line 70) | fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec<usize>;
method patch (line 74) | fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec<usize> {
type EarlyExitExt (line 79) | pub trait EarlyExitExt<T> {
method on_early_exit (line 80) | fn on_early_exit<F: FnOnce()>(self, print_help_msg: F) -> T;
function on_early_exit (line 84) | fn on_early_exit<F: FnOnce()>(self, print_help_msg: F) -> T {
type PositionalArgParser (line 101) | pub struct PositionalArgParser<'a>(pub slice::Iter<'a, &'a str>);
function required (line 104) | pub fn required(&mut self, field_name: &'static str) -> Result<Utf8CStri...
function optional (line 115) | pub fn optional(&mut self) -> Option<Utf8CString> {
function last_required (line 119) | pub fn last_required(&mut self, field_name: &'static str) -> Result<Utf8...
function last_optional (line 125) | pub fn last_optional(&mut self) -> Result<Option<Utf8CString>, EarlyExit> {
function ensure_end (line 134) | fn ensure_end(&mut self) -> Result<(), EarlyExit> {
type FmtAdaptor (line 142) | pub struct FmtAdaptor<'a, T>(pub &'a mut T)
function write_str (line 147) | fn write_str(&mut self, s: &str) -> fmt::Result {
function write_fmt (line 150) | fn write_fmt(&mut self, args: Arguments<'_>) -> fmt::Result {
type AtomicArc (line 155) | pub struct AtomicArc<T> {
function new (line 160) | pub fn new(arc: Arc<T>) -> AtomicArc<T> {
function load (line 167) | pub fn load(&self) -> Arc<T> {
function swap_ptr (line 174) | fn swap_ptr(&self, raw: *const T) -> Arc<T> {
function swap (line 180) | pub fn swap(&self, arc: Arc<T>) -> Arc<T> {
function store (line 185) | pub fn store(&self, arc: Arc<T>) {
method drop (line 192) | fn drop(&mut self) {
method default (line 199) | fn default() -> Self {
type Chunker (line 204) | pub struct Chunker {
method new (line 211) | pub fn new(chunk_size: usize) -> Self {
method set_chunk_size (line 220) | pub fn set_chunk_size(&mut self, chunk_size: usize) {
method add_data (line 229) | pub fn add_data<'a, 'b: 'a>(&'a mut self, mut buf: &'b [u8]) -> (&'b [...
method get_available (line 255) | pub fn get_available(&mut self) -> &[u8] {
type CmdArgs (line 262) | pub struct CmdArgs(pub Vec<&'static str>);
method new (line 266) | pub fn new(argc: i32, argv: *const *const c_char) -> CmdArgs {
method as_slice (line 278) | pub fn as_slice(&self) -> &[&'static str] {
method iter (line 282) | pub fn iter(&self) -> slice::Iter<'_, &'static str> {
method cstr_iter (line 286) | pub fn cstr_iter(&self) -> impl Iterator<Item = &'static Utf8CStr> {
FILE: native/src/base/mount.rs
method bind_mount_to (line 5) | pub fn bind_mount_to<'a>(&'a self, path: &'a Utf8CStr, rec: bool) -> OsR...
method remount_mount_point_flags (line 21) | pub fn remount_mount_point_flags(&self, flags: MsFlags) -> OsResult<'_, ...
method remount_mount_flags (line 32) | pub fn remount_mount_flags(&self, flags: MsFlags) -> OsResult<'_, ()> {
method remount_with_data (line 43) | pub fn remount_with_data(&self, data: &Utf8CStr) -> OsResult<'_, ()> {
method move_mount_to (line 54) | pub fn move_mount_to<'a>(&'a self, path: &'a Utf8CStr) -> OsResult<'a, (...
method unmount (line 65) | pub fn unmount(&self) -> OsResult<'_, ()> {
method set_mount_private (line 69) | pub fn set_mount_private(&self, rec: bool) -> OsResult<'_, ()> {
FILE: native/src/base/result.rs
type LoggedError (line 18) | pub struct LoggedError {}
method from (line 158) | fn from(e: T) -> Self {
method from (line 164) | fn from(e: T) -> Self {
type LoggedResult (line 19) | pub type LoggedResult<T> = Result<T, LoggedError>;
type SilentLogExt (line 33) | pub trait SilentLogExt<T> {
method silent (line 34) | fn silent(self) -> LoggedResult<T>;
function silent (line 38) | fn silent(self) -> LoggedResult<T> {
function silent (line 44) | fn silent(self) -> LoggedResult<T> {
type ResultExt (line 50) | pub trait ResultExt<T> {
method log (line 51) | fn log(self) -> LoggedResult<T>;
method log_with_msg (line 52) | fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> Lo...
method log_ok (line 53) | fn log_ok(self);
type OptionExt (line 57) | pub trait OptionExt<T> {
method ok_or_log (line 58) | fn ok_or_log(self) -> LoggedResult<T>;
method ok_or_log_msg (line 59) | fn ok_or_log_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> L...
function ok_or_log (line 64) | fn ok_or_log(self) -> LoggedResult<T> {
function ok_or_log_msg (line 69) | fn ok_or_log_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> Log...
function ok_or_log_msg (line 78) | fn ok_or_log_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> Log...
type Loggable (line 87) | trait Loggable {
method do_log (line 88) | fn do_log(self, level: LogLevel, caller: Option<&'static Location>) ->...
method do_log_msg (line 89) | fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
method do_log (line 174) | fn do_log(self, level: LogLevel, caller: Option<&'static Location>) ->...
method do_log_msg (line 183) | fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
function log (line 99) | fn log(self) -> LoggedResult<T> {
function log (line 105) | fn log(self) -> LoggedResult<T> {
function log_with_msg (line 111) | fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> Logg...
function log_with_msg (line 117) | fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> Logg...
function log_ok (line 123) | fn log_ok(self) {
function log_ok (line 129) | fn log_ok(self) {
function log (line 136) | fn log(self) -> LoggedResult<T> {
function log_with_msg (line 141) | fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> Logg...
function log_with_msg (line 147) | fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> Logg...
function log_ok (line 152) | fn log_ok(self) {}
function do_log_msg (line 200) | fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
type LibcReturn (line 215) | pub trait LibcReturn
method check_err (line 221) | fn check_err(self) -> nix::Result<Self::Value>;
method into_os_result (line 223) | fn into_os_result<'a>(
method check_os_err (line 233) | fn check_os_err<'a>(
type Value (line 265) | type Value = NonNull<T>;
method check_err (line 268) | fn check_err(self) -> nix::Result<Self::Value> {
type Value (line 274) | type Value = T;
method check_err (line 277) | fn check_err(self) -> Self {
type OsError (line 283) | pub struct OsError<'a> {
function new (line 291) | pub fn new<'a>(
function last_os_error (line 305) | pub fn last_os_error<'a>(
function set_args (line 313) | pub fn set_args<'a>(self, arg1: Option<&'a str>, arg2: Option<&'a str>) ...
method fmt (line 319) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
type OsResult (line 340) | pub type OsResult<'a, T> = Result<T, OsError<'a>>;
FILE: native/src/base/xwrap.rs
function ptr_to_str (line 15) | fn ptr_to_str<'a>(ptr: *const c_char) -> Option<&'a str> {
function xrealpath (line 24) | unsafe extern "C" fn xrealpath(path: *const c_char, buf: *mut u8, bufsz:...
function xreadlinkat (line 39) | unsafe extern "C" fn xreadlinkat(
function xfopen (line 54) | unsafe extern "C" fn xfopen(path: *const c_char, mode: *const c_char) ->...
function xfdopen (line 64) | unsafe extern "C" fn xfdopen(fd: RawFd, mode: *const c_char) -> *mut lib...
function xopen (line 74) | unsafe extern "C" fn xopen(path: *const c_char, flags: i32, mode: mode_t...
function xopenat (line 84) | unsafe extern "C" fn xopenat(dirfd: RawFd, path: *const c_char, flags: i...
function xwrite (line 94) | unsafe extern "C" fn xwrite(fd: RawFd, buf: *const u8, bufsz: usize) -> ...
function xread (line 103) | unsafe extern "C" fn xread(fd: RawFd, buf: *mut c_void, bufsz: usize) ->...
function xxread (line 113) | unsafe extern "C" fn xxread(fd: RawFd, buf: *mut u8, bufsz: usize) -> is...
function xpipe2 (line 121) | pub(crate) fn xpipe2(fds: &mut [i32; 2], flags: i32) -> i32 {
function xsetns (line 131) | extern "C" fn xsetns(fd: RawFd, nstype: i32) -> i32 {
function xunshare (line 141) | extern "C" fn xunshare(flags: i32) -> i32 {
function xopendir (line 151) | unsafe extern "C" fn xopendir(path: *const c_char) -> *mut libc::DIR {
function xfdopendir (line 161) | extern "C" fn xfdopendir(fd: RawFd) -> *mut libc::DIR {
function xreaddir (line 171) | unsafe extern "C" fn xreaddir(mut dir: ManuallyDrop<Directory>) -> *mut ...
function xsetsid (line 180) | extern "C" fn xsetsid() -> i32 {
function xfstat (line 190) | unsafe extern "C" fn xfstat(fd: RawFd, buf: *mut libc::stat) -> i32 {
function xdup2 (line 200) | extern "C" fn xdup2(oldfd: RawFd, newfd: RawFd) -> RawFd {
function xsymlink (line 210) | unsafe extern "C" fn xsymlink(target: *const c_char, linkpath: *const c_...
function xmount (line 220) | unsafe extern "C" fn xmount(
function xumount2 (line 236) | unsafe extern "C" fn xumount2(target: *const c_char, flags: i32) -> i32 {
function xrename (line 246) | unsafe extern "C" fn xrename(oldname: *const c_char, newname: *const c_c...
function xmkdir (line 256) | unsafe extern "C" fn xmkdir(path: *const c_char, mode: mode_t) -> i32 {
function xmkdirs (line 266) | unsafe extern "C" fn xmkdirs(path: *const c_char, mode: mode_t) -> i32 {
function xsendfile (line 276) | unsafe extern "C" fn xsendfile(
function xfork (line 291) | extern "C" fn xfork() -> i32 {
function xmknod (line 301) | unsafe extern "C" fn xmknod(pathname: *const c_char, mode: mode_t, dev: ...
FILE: native/src/boot/bootimg.cpp
function decompress (line 23) | static void decompress(FileFormat type, int fd, const void *in, size_t s...
function off_t (line 27) | static off_t compress_len(FileFormat type, byte_view in, int fd) {
function dump (line 34) | static void dump(const void *buf, size_t size, const char *filename) {
function restore (line 42) | static size_t restore(int fd, const char *filename) {
function check_env (line 51) | static bool check_env(const char *name) {
function guess_lzma (line 56) | static bool guess_lzma(const uint8_t *buf, size_t len) {
function FileFormat (line 69) | FileFormat check_fmt(const void *buf, size_t len) {
type fdt_header (line 244) | struct [[gnu::packed]] fdt_header {
type fdt32_t (line 245) | struct fdt32_t {
type node_header (line 261) | struct node_header {
function find_dtb_offset (line 284) | static int find_dtb_offset(const uint8_t *buf, unsigned sz) {
function FileFormat (line 315) | static FileFormat check_fmt_lg(const uint8_t *buf, unsigned sz) {
function split_image_dtb (line 611) | int split_image_dtb(Utf8CStr filename, bool skip_decomp) {
function unpack (line 633) | int unpack(Utf8CStr image, bool skip_decomp, bool hdr) {
function repack (line 715) | void repack(Utf8CStr src_img, Utf8CStr out_img, bool skip_comp) {
function cleanup (line 1053) | void cleanup() {
FILE: native/src/boot/bootimg.hpp
type mtk_hdr (line 12) | struct mtk_hdr {
type dhtb_hdr (line 20) | struct dhtb_hdr {
type blob_hdr (line 28) | struct blob_hdr {
type zimage_hdr (line 44) | struct zimage_hdr {
type AvbFooter (line 62) | struct AvbFooter {
type AvbVBMetaImageHeader (line 73) | struct AvbVBMetaImageHeader {
type boot_img_hdr_v0_common (line 145) | struct boot_img_hdr_v0_common {
type boot_img_hdr_v0 (line 158) | struct boot_img_hdr_v0 : public boot_img_hdr_v0_common {
type boot_img_hdr_v1 (line 193) | struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
type boot_img_hdr_v2 (line 199) | struct boot_img_hdr_v2 : public boot_img_hdr_v1 {
type boot_img_hdr_pxa (line 205) | struct boot_img_hdr_pxa : public boot_img_hdr_v0_common {
type boot_img_hdr_v3 (line 291) | struct boot_img_hdr_v3 {
type boot_img_hdr_vnd_v3 (line 305) | struct boot_img_hdr_vnd_v3 {
type boot_img_hdr_v4 (line 322) | struct boot_img_hdr_v4 : public boot_img_hdr_v3 {
type boot_img_hdr_vnd_v4 (line 326) | struct boot_img_hdr_vnd_v4 : public boot_img_hdr_vnd_v3 {
type vendor_ramdisk_table_entry_v4 (line 333) | struct vendor_ramdisk_table_entry_v4 {
function T (line 349) | static T align_to(T v, int a) {
function T (line 355) | static T align_padding(T v, int a) {
type dyn_img_hdr (line 370) | struct dyn_img_hdr {
FILE: native/src/boot/build.rs
function main (line 10) | fn main() {
FILE: native/src/boot/cli.rs
type Cli (line 20) | struct Cli {
type Action (line 27) | enum Action {
type Unpack (line 45) | struct Unpack {
type Repack (line 56) | struct Repack {
type Verify (line 67) | struct Verify {
type Sign (line 76) | struct Sign {
type Extract (line 89) | struct Extract {
type HexPatch (line 100) | struct HexPatch {
type Cpio (line 111) | struct Cpio {
type Dtb (line 120) | struct Dtb {
type Split (line 129) | struct Split {
type Sha1 (line 138) | struct Sha1 {
type Cleanup (line 145) | struct Cleanup {}
type Compress (line 147) | struct Compress {
method from_args (line 154) | fn from_args(command_name: &[&str], args: &[&str]) -> Result<Self, Early...
constant COMMAND (line 174) | const COMMAND: &'static CommandInfo = &CommandInfo {
type Decompress (line 182) | struct Decompress {
function print_usage (line 189) | fn print_usage(cmd: &str) {
function verify_cmd (line 291) | fn verify_cmd(image: &Utf8CStr, cert: Option<&Utf8CStr>) -> bool {
function sign_cmd (line 305) | fn sign_cmd(
function boot_main (line 329) | fn boot_main(cmds: CmdArgs) -> LoggedResult<i32> {
function main (line 441) | pub extern "C" fn main(argc: i32, argv: *const *const c_char, _envp: *co...
FILE: native/src/boot/compress.rs
type WriteFinish (line 27) | pub trait WriteFinish<W: Write>: Write {
method finish (line 28) | fn finish(self: Box<Self>) -> std::io::Result<W>;
function finish (line 46) | fn finish(self: Box<Self>) -> std::io::Result<W> {
function finish (line 53) | fn finish(self: Box<Self>) -> std::io::Result<W> {
constant LZ4_BLOCK_SIZE (line 67) | const LZ4_BLOCK_SIZE: usize = 0x800000;
constant LZ4HC_CLEVEL_MAX (line 68) | const LZ4HC_CLEVEL_MAX: i32 = 12;
constant LZ4_MAGIC (line 69) | const LZ4_MAGIC: u32 = 0x184c2102;
type LZ4BlockEncoder (line 71) | struct LZ4BlockEncoder<W: Write> {
function new (line 80) | fn new(write: W, is_lg: bool) -> Self {
function encode_block (line 92) | fn encode_block(write: &mut W, out_buf: &mut [u8], chunk: &[u8]) -> std:...
method write (line 106) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
method flush (line 111) | fn flush(&mut self) -> std::io::Result<()> {
method write_all (line 115) | fn write_all(&mut self, mut buf: &[u8]) -> std::io::Result<()> {
function finish (line 134) | fn finish(mut self: Box<Self>) -> std::io::Result<W> {
type LZ4BlockDecoder (line 148) | struct LZ4BlockDecoder<R: Read> {
function new (line 157) | fn new(read: R) -> Self {
method read (line 170) | fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
function get_encoder (line 219) | pub fn get_encoder<'a, W: Write + 'a>(
function get_decoder (line 262) | pub fn get_decoder<'a, R: Read + 'a>(
function compress_bytes (line 279) | pub fn compress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: RawFd) {
function decompress_bytes (line 290) | pub fn decompress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: Raw...
function decompress_cmd (line 302) | pub(crate) fn decompress_cmd(infile: &Utf8CStr, outfile: Option<&Utf8CSt...
function compress_cmd (line 363) | pub(crate) fn compress_cmd(
FILE: native/src/boot/cpio.rs
type CpioCommand (line 33) | struct CpioCommand {
type CpioAction (line 40) | enum CpioAction {
type Test (line 57) | struct Test {}
type Restore (line 61) | struct Restore {}
type Patch (line 65) | struct Patch {}
type Exists (line 69) | struct Exists {
type Backup (line 76) | struct Backup {
type Remove (line 85) | struct Remove {
type Move (line 94) | struct Move {
type Extract (line 103) | struct Extract {
type MakeDir (line 110) | struct MakeDir {
type Link (line 119) | struct Link {
type Add (line 128) | struct Add {
type List (line 139) | struct List {
function print_cpio_usage (line 146) | pub(crate) fn print_cpio_usage() {
type CpioHeader (line 186) | struct CpioHeader {
type Cpio (line 203) | struct Cpio {
method new (line 217) | fn new() -> Self {
method load_from_data (line 223) | fn load_from_data(data: &[u8]) -> LoggedResult<Self> {
method load_from_file (line 263) | fn load_from_file(path: &Utf8CStr) -> LoggedResult<Self> {
method dump (line 269) | fn dump(&self, path: &str) -> LoggedResult<()> {
method rm (line 312) | fn rm(&mut self, path: &str, recursive: bool) {
method extract_entry (line 330) | fn extract_entry(&self, path: &str, out: &mut String) -> LoggedResult<...
method extract (line 374) | fn extract(&self, path: Option<&mut String>, out: Option<&mut String>)...
method exists (line 389) | fn exists(&self, path: &str) -> bool {
method add (line 393) | fn add(&mut self, mode: mode_t, path: &str, file: &mut String) -> Logg...
method mkdir (line 438) | fn mkdir(&mut self, mode: mode_t, dir: &str) {
method ln (line 453) | fn ln(&mut self, src: &str, dst: &str) {
method mv (line 468) | fn mv(&mut self, from: &str, to: &str) -> LoggedResult<()> {
method ls (line 478) | fn ls(&self, path: &str, recursive: bool) {
method patch (line 505) | fn patch(&mut self) {
method test (line 539) | fn test(&self) -> i32 {
method restore (line 562) | fn restore(&mut self) -> LoggedResult<()> {
method backup (line 597) | fn backup(&mut self, origin: &mut String, skip_compress: bool) -> Logg...
type CpioEntry (line 207) | struct CpioEntry {
method compress (line 698) | pub(crate) fn compress(&mut self) -> bool {
method decompress (line 715) | pub(crate) fn decompress(&mut self) -> bool {
constant MAGISK_PATCHED (line 501) | const MAGISK_PATCHED: i32 = 1 << 0;
constant UNSUPPORTED_CPIO (line 502) | const UNSUPPORTED_CPIO: i32 = 1 << 1;
method fmt (line 736) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
function cpio_commands (line 769) | pub(crate) fn cpio_commands(file: &Utf8CStr, cmds: &Vec<String>) -> Logg...
function x8u (line 826) | fn x8u(x: &[u8; 8]) -> LoggedResult<u32> {
function align_4 (line 839) | fn align_4(x: usize) -> usize {
function norm_path (line 844) | fn norm_path(path: &str) -> String {
function parse_mode (line 851) | fn parse_mode(s: &str) -> Result<mode_t, String> {
FILE: native/src/boot/dtb.rs
type DtbAction (line 12) | pub(crate) enum DtbAction {
type Print (line 20) | pub(crate) struct Print {
type Patch (line 27) | pub(crate) struct Patch {}
type Test (line 31) | pub(crate) struct Test {}
function print_dtb_usage (line 33) | pub(crate) fn print_dtb_usage() {
constant MAX_PRINT_LEN (line 53) | const MAX_PRINT_LEN: usize = 32;
function print_node (line 55) | fn print_node(node: &FdtNode) {
function for_each_fdt (line 139) | fn for_each_fdt<F: FnMut(usize, Fdt) -> LoggedResult<()>>(
function find_fstab (line 180) | fn find_fstab<'b, 'a: 'b>(fdt: &'b Fdt<'a>) -> Option<FdtNode<'b, 'a>> {
function dtb_print (line 184) | fn dtb_print(file: &Utf8CStr, fstab: bool) -> LoggedResult<()> {
function dtb_test (line 202) | fn dtb_test(file: &Utf8CStr) -> LoggedResult<bool> {
function dtb_patch (line 223) | fn dtb_patch(file: &Utf8CStr) -> LoggedResult<bool> {
function dtb_commands (line 264) | pub(crate) fn dtb_commands(file: &Utf8CStr, action: &DtbAction) -> Logge...
FILE: native/src/boot/format.rs
type Err (line 7) | type Err = ();
method from_str (line 9) | fn from_str(s: &str) -> Result<Self, Self::Err> {
method fmt (line 25) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
method as_cstr (line 31) | fn as_cstr(&self) -> &'static Utf8CStr {
method ext (line 50) | pub fn ext(&self) -> &'static str {
method is_compressed (line 62) | pub fn is_compressed(&self) -> bool {
method formats (line 76) | pub fn formats() -> String {
function fmt2name (line 94) | pub fn fmt2name(fmt: FileFormat) -> *const libc::c_char {
function fmt_compressed (line 98) | pub fn fmt_compressed(fmt: FileFormat) -> bool {
function fmt_compressed_any (line 102) | pub fn fmt_compressed_any(fmt: FileFormat) -> bool {
FILE: native/src/boot/lib.rs
type FileFormat (line 24) | enum FileFormat {
type Utf8CStrRef (line 53) | type Utf8CStrRef<'a> = base::Utf8CStrRef<'a>;
function cleanup (line 55) | fn cleanup();
function unpack (line 56) | fn unpack(image: Utf8CStrRef, skip_decomp: bool, hdr: bool) -> i32;
function repack (line 57) | fn repack(src_img: Utf8CStrRef, out_img: Utf8CStrRef, skip_comp: bool);
function split_image_dtb (line 58) | fn split_image_dtb(filename: Utf8CStrRef, skip_decomp: bool) -> i32;
function check_fmt (line 59) | fn check_fmt(buf: &[u8]) -> FileFormat;
function get_sha (line 64) | fn get_sha(use_sha1: bool) -> Box<SHA>;
function update (line 65) | fn update(self: &mut SHA, data: &[u8]);
function finalize_into (line 66) | fn finalize_into(self: &mut SHA, out: &mut [u8]);
function output_size (line 67) | fn output_size(self: &SHA) -> usize;
function sha256_hash (line 68) | fn sha256_hash(data: &[u8], out: &mut [u8]);
function compress_bytes (line 70) | fn compress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: i32);
function decompress_bytes (line 71) | fn decompress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: i32);
function fmt2name (line 72) | fn fmt2name(fmt: FileFormat) -> *const c_char;
function fmt_compressed (line 73) | fn fmt_compressed(fmt: FileFormat) -> bool;
function fmt_compressed_any (line 74) | fn fmt_compressed_any(fmt: FileFormat) -> bool;
function sign_payload_for_cxx (line 77) | fn sign_payload_for_cxx(payload: &[u8]) -> Vec<u8>;
function payload (line 87) | fn payload(self: &BootImage) -> &[u8];
function tail (line 89) | fn tail(self: &BootImage) -> &[u8];
function is_signed (line 90) | fn is_signed(self: &BootImage) -> bool;
function tail_off (line 91) | fn tail_off(self: &BootImage) -> u64;
function new (line 95) | fn new(img: Utf8CStrRef) -> UniquePtr<BootImage>;
function verify_for_cxx (line 99) | fn verify_for_cxx(self: &BootImage) -> bool;
function check_env (line 104) | pub(crate) fn check_env(env: &str) -> bool {
FILE: native/src/boot/magiskboot.hpp
type FileFormat (line 52) | enum class FileFormat : uint8_t
function FileFormat (line 60) | static inline FileFormat check_fmt(rust::Slice<const uint8_t> bytes) {
FILE: native/src/boot/patch.rs
function remove_pattern (line 37) | fn remove_pattern(buf: &mut [u8], pattern_matcher: unsafe fn(&[u8]) -> O...
function patch_verity (line 64) | pub fn patch_verity(buf: &mut [u8]) -> usize {
function patch_encryption (line 82) | pub fn patch_encryption(buf: &mut [u8]) -> usize {
function hex2byte (line 90) | fn hex2byte(hex: &[u8]) -> Vec<u8> {
function hexpatch (line 105) | pub fn hexpatch(file: &Utf8CStr, from: &Utf8CStr, to: &Utf8CStr) -> bool {
FILE: native/src/boot/payload.rs
constant PAYLOAD_MAGIC (line 23) | const PAYLOAD_MAGIC: &str = "CrAU";
function extract_boot_from_payload (line 25) | pub fn extract_boot_from_payload(
FILE: native/src/boot/sign.rs
type SHA (line 33) | pub enum SHA {
method update (line 39) | pub fn update(&mut self, data: &[u8]) {
method output_size (line 46) | pub fn output_size(&self) -> usize {
method finalize_into (line 53) | pub fn finalize_into(&mut self, out: &mut [u8]) {
function get_sha (line 62) | pub fn get_sha(use_sha1: bool) -> Box<SHA> {
function sha1_hash (line 70) | pub fn sha1_hash(data: &[u8], out: &mut [u8]) {
function sha256_hash (line 76) | pub fn sha256_hash(data: &[u8], out: &mut [u8]) {
type SigningKey (line 83) | enum SigningKey {
type VerifyingKey (line 91) | enum VerifyingKey {
type Verifier (line 98) | struct Verifier {
method from_public_key (line 104) | fn from_public_key(key: SubjectPublicKeyInfoRef) -> LoggedResult<Verif...
method update (line 124) | fn update(&mut self, data: &[u8]) {
method verify (line 128) | fn verify(mut self, signature: &[u8]) -> LoggedResult<()> {
type Signer (line 151) | struct Signer {
method from_private_key (line 157) | fn from_private_key(key: &[u8]) -> LoggedResult<Signer> {
method update (line 189) | fn update(&mut self, data: &[u8]) {
method sign (line 193) | fn sign(mut self) -> LoggedResult<Vec<u8>> {
type AuthenticatedAttributes (line 234) | struct AuthenticatedAttributes {
type BootSignature (line 240) | struct BootSignature {
method verify (line 249) | fn verify(self, payload: &[u8]) -> LoggedResult<()> {
method verify (line 268) | pub fn verify(&self, cert: Option<&Utf8CStr>) -> LoggedResult<()> {
method verify_for_cxx (line 285) | pub fn verify_for_cxx(&self) -> bool {
type Bytes (line 290) | enum Bytes {
method as_ref (line 296) | fn as_ref(&self) -> &[u8] {
constant VERITY_PEM (line 304) | const VERITY_PEM: &[u8] = include_bytes!("../../../tools/keys/verity.x50...
constant VERITY_PK8 (line 305) | const VERITY_PK8: &[u8] = include_bytes!("../../../tools/keys/verity.pk8");
function sign_boot_image (line 307) | pub fn sign_boot_image(
function sign_payload_for_cxx (line 347) | pub fn sign_payload_for_cxx(payload: &[u8]) -> Vec<u8> {
FILE: native/src/core/applet_stub.cpp
function main (line 3) | int main(int argc, char *argv[]) {
FILE: native/src/core/applets.cpp
type Applet (line 8) | struct Applet {
function main (line 22) | int main(int argc, char *argv[]) {
FILE: native/src/core/bootstages.rs
method setup_magisk_env (line 32) | fn setup_magisk_env(&self) -> bool {
method post_fs_data (line 109) | fn post_fs_data(&self) -> bool {
method late_start (line 163) | fn late_start(&self) {
method boot_complete (line 173) | fn boot_complete(&self) {
method boot_stage_handler (line 193) | pub fn boot_stage_handler(&self, client: UnixStream, code: RequestCode) {
function check_data (line 226) | fn check_data() -> bool {
FILE: native/src/core/build.rs
function main (line 10) | fn main() {
FILE: native/src/core/daemon.rs
constant AID_ROOT (line 42) | pub const AID_ROOT: i32 = 0;
constant AID_SHELL (line 43) | pub const AID_SHELL: i32 = 2000;
constant AID_APP_START (line 44) | pub const AID_APP_START: i32 = 10000;
constant AID_APP_END (line 45) | pub const AID_APP_END: i32 = 19999;
constant AID_USER_OFFSET (line 46) | pub const AID_USER_OFFSET: i32 = 100000;
function to_app_id (line 48) | pub const fn to_app_id(uid: i32) -> i32 {
function to_user_id (line 52) | pub const fn to_user_id(uid: i32) -> i32 {
type MagiskD (line 57) | pub struct MagiskD {
method get (line 72) | pub fn get() -> &'static MagiskD {
method sdk_int (line 76) | pub fn sdk_int(&self) -> i32 {
method app_data_dir (line 80) | pub fn app_data_dir(&self) -> &'static Utf8CStr {
method handle_request_sync (line 88) | fn handle_request_sync(&self, mut client: UnixStream, code: RequestCod...
method handle_request_async (line 120) | fn handle_request_async(&self, mut client: UnixStream, code: RequestCo...
method reboot (line 154) | fn reboot(&self) {
method is_client (line 164) | fn is_client(&self, pid: i32) -> bool {
method is_client (line 175) | fn is_client(&self, pid: i32) -> bool {
method handle_requests (line 179) | fn handle_requests(&'static self, mut client: UnixStream) {
function switch_cgroup (line 270) | fn switch_cgroup(cgroup: &str, pid: i32) {
function daemon_entry (line 284) | fn daemon_entry() {
function connect_daemon (line 430) | pub fn connect_daemon(code: RequestCode, create: bool) -> LoggedResult<U...
function connect_daemon_for_cxx (line 486) | pub fn connect_daemon_for_cxx(code: RequestCode, create: bool) -> RawFd {
FILE: native/src/core/db.rs
function sqlite_err_str (line 19) | fn sqlite_err_str(code: i32) -> &'static Utf8CStr {
type SqliteError (line 27) | pub struct SqliteError(i32);
type SqliteResult (line 29) | pub type SqliteResult<T> = Result<T, SqliteError>;
type SqliteReturn (line 31) | pub trait SqliteReturn {
method sql_result (line 32) | fn sql_result(self) -> SqliteResult<()>;
method sql_result (line 36) | fn sql_result(self) -> SqliteResult<()> {
type SqlTable (line 45) | pub trait SqlTable {
method on_row (line 46) | fn on_row(&mut self, columns: &[String], values: &DbValues);
method on_row (line 53) | fn on_row(&mut self, columns: &[String], values: &DbValues) {
method on_row (line 109) | fn on_row(&mut self, columns: &[String], values: &DbValues) {
type DbSettings (line 59) | pub struct DbSettings {
type RootAccess (line 70) | pub enum RootAccess {
type MultiuserMode (line 80) | pub enum MultiuserMode {
method default (line 88) | fn default() -> Self {
method to_str (line 94) | fn to_str(self) -> &'static str {
type Sqlite3 (line 134) | pub struct Sqlite3(NonNull<sqlite3>);
type SqlBindCallback (line 137) | type SqlBindCallback = Option<unsafe extern "C" fn(*mut c_void, i32, Pin...
type SqlExecCallback (line 138) | type SqlExecCallback = Option<unsafe extern "C" fn(*mut c_void, &[String...
function sql_exec_impl (line 141) | fn sql_exec_impl(
type DbArg (line 151) | pub enum DbArg<'a> {
type DbArgs (line 156) | struct DbArgs<'a> {
function bind_arguments (line 161) | unsafe extern "C" fn bind_arguments(v: *mut c_void, idx: i32, stmt: Pin<...
function read_db_row (line 177) | unsafe extern "C" fn read_db_row<T: SqlTable>(
method with_db (line 189) | fn with_db<F: FnOnce(*mut sqlite3) -> i32>(&self, f: F) -> i32 {
method db_exec_impl (line 201) | fn db_exec_impl(
method db_exec_with_rows (line 227) | pub fn db_exec_with_rows<T: SqlTable>(&self, sql: &str, args: &[DbArg], ...
method db_exec (line 236) | pub fn db_exec(&self, sql: &str, args: &[DbArg]) -> i32 {
method set_db_setting (line 240) | pub fn set_db_setting(&self, key: DbEntryKey, value: i32) -> SqliteResul...
method get_db_setting (line 248) | pub fn get_db_setting(&self, key: DbEntryKey) -> i32 {
method get_db_settings (line 273) | pub fn get_db_settings(&self) -> SqliteResult<DbSettings> {
method get_db_string (line 283) | pub fn get_db_string(&self, key: DbEntryKey) -> String {
method rm_db_string (line 299) | pub fn rm_db_string(&self, key: DbEntryKey) -> SqliteResult<()> {
method db_exec_for_cli (line 304) | pub fn db_exec_for_cli(&self, mut file: UnixStream) -> LoggedResult<()> {
method set_db_setting_for_cxx (line 326) | pub fn set_db_setting_for_cxx(&self, key: DbEntryKey, value: i32) -> bool {
function sql_exec_for_cxx (line 332) | unsafe extern "C" fn sql_exec_for_cxx(
FILE: native/src/core/deny/cli.cpp
function usage (line 10) | [[noreturn]] static void usage() {
function denylist_handler (line 29) | void denylist_handler(int client) {
function denylist_cli (line 65) | int denylist_cli(rust::Vec<rust::String> &args) {
FILE: native/src/core/deny/deny.hpp
type DenyRequest (line 7) | namespace DenyRequest {
type DenyResponse (line 20) | namespace DenyResponse {
FILE: native/src/core/deny/logcat.cpp
type logger_entry (line 13) | struct logger_entry {
type log_msg (line 25) | struct log_msg {
type logger_entry (line 28) | struct logger_entry
type AndroidLogEntry (line 32) | struct AndroidLogEntry {
type android_event_header_t (line 45) | struct [[gnu::packed]] android_event_header_t {
type android_event_int_t (line 49) | struct [[gnu::packed]] android_event_int_t {
type android_event_string_t (line 54) | struct [[gnu::packed]] android_event_string_t {
type android_event_list_t (line 60) | struct [[gnu::packed]] android_event_list_t {
type android_event_am_proc_start (line 66) | struct [[gnu::packed]] android_event_am_proc_start {
type logger_list (line 81) | struct logger_list
type logger_list (line 82) | struct logger_list
type logger_list (line 83) | struct logger_list
type log_msg (line 83) | struct log_msg
type logger_entry (line 28) | struct logger_entry
type logger (line 84) | struct logger
type logger_list (line 84) | struct logger_list
type logger_entry (line 85) | struct logger_entry
type stat (line 90) | struct stat
function read_ns (line 93) | static int read_ns(const int pid, struct stat *st) {
function parse_ppid (line 99) | static int parse_ppid(int pid) {
function check_zygote (line 110) | static void check_zygote() {
function process_main_buffer (line 130) | static void process_main_buffer(struct log_msg *msg) {
function process_events_buffer (line 173) | static void process_events_buffer(struct log_msg *msg) {
function run (line 234) | [[noreturn]] void run() {
FILE: native/src/core/deny/utils.cpp
function get_app_id (line 34) | static int get_app_id(const vector<int> &users, const string &pkg) {
function collect_users (line 46) | static void collect_users(vector<int> &users) {
function get_app_id (line 56) | static int get_app_id(const string &pkg) {
function update_app_id (line 64) | static void update_app_id(int app_id, const string &pkg, bool remove) {
function crawl_procfs (line 83) | static void crawl_procfs(const F &fn) {
function str_eql (line 94) | static bool str_eql(string_view a, string_view b) { return a == b; }
function str_starts_with (line 95) | static bool str_starts_with(string_view a, string_view b) { return a.sta...
function proc_name_match (line 98) | static bool proc_name_match(int pid, string_view name) {
function proc_context_match (line 110) | bool proc_context_match(int pid, string_view context) {
function kill_process (line 122) | static void kill_process(const char *name, bool multi = false) {
function validate (line 133) | static bool validate(const char *pkg, const char *proc) {
function add_hide_set (line 169) | static bool add_hide_set(const char *pkg, const char *proc) {
function scan_deny_apps (line 185) | void scan_deny_apps() {
function clear_data (line 213) | static void clear_data() {
function ensure_data (line 218) | static bool ensure_data() {
function add_list (line 251) | static int add_list(const char *pkg, const char *proc) {
function add_list (line 278) | int add_list(int client) {
function rm_list (line 284) | static int rm_list(const char *pkg, const char *proc) {
function rm_list (line 322) | int rm_list(int client) {
function ls_list (line 328) | void ls_list(int client) {
function enable_deny (line 352) | int enable_deny() {
function disable_deny (line 392) | int disable_deny() {
function initialize_denylist (line 400) | void initialize_denylist() {
function is_deny_target (line 407) | bool is_deny_target(int uid, string_view process) {
function update_deny_flags (line 433) | void update_deny_flags(int uid, rust::Str process, uint32_t &flags) {
FILE: native/src/core/include/core.hpp
function connect_daemon (line 22) | inline int connect_daemon(RequestCode req) {
type ModuleInfo (line 30) | struct ModuleInfo
function T (line 37) | T read_any(int fd) {
function write_any (line 44) | void write_any(int fd, T val) {
function read_int (line 48) | inline int read_int(int fd) { return read_any<int>(fd); }
function write_int (line 49) | inline void write_int(int fd, int val) { write_any(fd, val); }
function write_vector (line 54) | void write_vector(int fd, const std::vector<T> &vec) {
function read_vector (line 59) | bool read_vector(int fd, std::vector<T> &vec) {
function Utf8CStr (line 88) | inline Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }
function resolve_preinit_dir_rs (line 89) | inline rust::String resolve_preinit_dir_rs(Utf8CStr base_dir) {
FILE: native/src/core/include/sqlite.hpp
type sqlite3 (line 15) | struct sqlite3
type sqlite3_stmt (line 16) | struct sqlite3_stmt
type DbValues (line 21) | struct DbValues {
method get_str (line 23) | rust::Str get_str(int index) const { return get_text(index); }
type DbStatement (line 27) | struct DbStatement {
type DbArg (line 45) | struct DbArg {
method DbArg (line 54) | DbArg(int64_t v) : type(INT), int_val(v) {}
method DbArg (line 55) | DbArg(const char *v) : type(TEXT), str_val(v) {}
type DbArgs (line 58) | struct DbArgs {
method DbArgs (line 59) | DbArgs() : curr(0) {}
method DbArgs (line 60) | DbArgs(std::initializer_list<DbArg> list) : args(list), curr(0) {}
method empty (line 62) | bool empty() const { return args.empty(); }
function db_exec (line 74) | bool db_exec(const char *sql, DbArgs args, T &data) {
FILE: native/src/core/lib.rs
type RequestCode (line 49) | enum RequestCode {
type RespondCode (line 74) | enum RespondCode {
type DbEntryKey (line 82) | enum DbEntryKey {
type MntNsMode (line 93) | enum MntNsMode {
type SuPolicy (line 100) | enum SuPolicy {
type ModuleInfo (line 107) | struct ModuleInfo {
type ZygiskRequest (line 114) | enum ZygiskRequest {
type ZygiskStateFlags (line 121) | enum ZygiskStateFlags {
type SuRequest (line 129) | struct SuRequest {
method write_to_fd (line 233) | fn write_to_fd(&self, fd: i32) {
type Utf8CStrRef (line 143) | type Utf8CStrRef<'a> = base::Utf8CStrRef<'a>;
function get_magisk_tmp (line 148) | fn get_magisk_tmp() -> Utf8CStrRef<'static>;
function resolve_preinit_dir (line 150) | fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String;
function check_key_combo (line 151) | fn check_key_combo() -> bool;
function unlock_blocks (line 152) | fn unlock_blocks();
function update_deny_flags (line 153) | fn update_deny_flags(uid: i32, process: &str, flags: &mut u32);
function initialize_denylist (line 154) | fn initialize_denylist();
function switch_mnt_ns (line 155) | fn switch_mnt_ns(pid: i32) -> i32;
function exec_root_shell (line 156) | fn exec_root_shell(client: i32, pid: i32, req: &mut SuRequest, mode: Mnt...
function exec_script (line 159) | fn exec_script(script: Utf8CStrRef);
function exec_common_scripts (line 160) | fn exec_common_scripts(stage: Utf8CStrRef);
function exec_module_scripts (line 161) | fn exec_module_scripts(state: Utf8CStrRef, modules: &Vec<ModuleInfo>);
function install_apk (line 162) | fn install_apk(apk: Utf8CStrRef);
function uninstall_pkg (line 163) | fn uninstall_pkg(apk: Utf8CStrRef);
function install_module (line 164) | fn install_module(zip: Utf8CStrRef);
function denylist_cli (line 167) | fn denylist_cli(args: &mut Vec<String>) -> i32;
function denylist_handler (line 168) | fn denylist_handler(client: i32);
function scan_deny_apps (line 169) | fn scan_deny_apps();
function sqlite3_errstr (line 177) | fn sqlite3_errstr(code: i32) -> *const c_char;
function open_and_init_db (line 178) | fn open_and_init_db() -> *mut sqlite3;
function get_int (line 179) | fn get_int(self: &DbValues, index: i32) -> i32;
function get_text (line 181) | fn get_text(self: &DbValues, index: i32) -> &str;
function bind_text (line 182) | fn bind_text(self: Pin<&mut DbStatement>, index: i32, val: &str) -> i32;
function bind_int64 (line 183) | fn bind_int64(self: Pin<&mut DbStatement>, index: i32, val: i64) -> i32;
function android_logging (line 187) | fn android_logging();
function zygisk_logging (line 188) | fn zygisk_logging();
function zygisk_close_logd (line 189) | fn zygisk_close_logd();
function zygisk_get_logd (line 190) | fn zygisk_get_logd() -> i32;
function revert_unmount (line 191) | fn revert_unmount(pid: i32);
function zygisk_should_load_module (line 192) | fn zygisk_should_load_module(flags: u32) -> bool;
function send_fd (line 193) | fn send_fd(socket: i32, fd: i32) -> bool;
function recv_fd (line 194) | fn recv_fd(socket: i32) -> i32;
function recv_fds (line 195) | fn recv_fds(socket: i32) -> Vec<i32>;
function write_to_fd (line 196) | fn write_to_fd(self: &SuRequest, fd: i32);
function pump_tty (line 197) | fn pump_tty(ptmx: i32, pump_stdin: bool);
function get_pty_num (line 198) | fn get_pty_num(fd: i32) -> i32;
function lgetfilecon (line 199) | fn lgetfilecon(path: Utf8CStrRef, con: &mut [u8]) -> bool;
function setfilecon (line 200) | fn setfilecon(path: Utf8CStrRef, con: Utf8CStrRef) -> bool;
function get_prop (line 202) | fn get_prop(name: Utf8CStrRef) -> String;
function resetprop_main (line 203) | unsafe fn resetprop_main(argc: i32, argv: *mut *mut c_char) -> i32;
function connect_daemon_for_cxx (line 206) | fn connect_daemon_for_cxx(code: RequestCode, create: bool) -> i32;
function magisk_main (line 207) | unsafe fn magisk_main(argc: i32, argv: *mut *mut c_char) -> i32;
function default (line 214) | fn default() -> SuRequest;
function sdk_int (line 220) | fn sdk_int(&self) -> i32;
function zygisk_enabled (line 221) | fn zygisk_enabled(&self) -> bool;
function get_db_setting (line 222) | fn get_db_setting(&self, key: DbEntryKey) -> i32;
function set_db_setting_for_cxx (line 224) | fn set_db_setting_for_cxx(&self, key: DbEntryKey, value: i32) -> bool;
function get (line 228) | fn get() -> &'static MagiskD;
FILE: native/src/core/logging.rs
type ALogPriority (line 32) | enum ALogPriority {
function __android_log_write (line 45) | fn __android_log_write(prio: i32, tag: *const c_char, msg: *const c_char);
function strftime (line 46) | fn strftime(buf: *mut c_char, len: usize, fmt: *const c_char, tm: *const...
function level_to_prio (line 49) | fn level_to_prio(level: LogLevel) -> i32 {
function android_log_write (line 58) | fn android_log_write(level: LogLevel, msg: &Utf8CStr) {
function android_logging (line 64) | pub fn android_logging() {
function magisk_logging (line 68) | pub fn magisk_logging() {
function zygisk_logging (line 76) | pub fn zygisk_logging() {
type LogMeta (line 86) | struct LogMeta {
constant MAX_MSG_LEN (line 93) | const MAX_MSG_LEN: usize = PIPE_BUF - size_of::<LogMeta>();
function write_log_to_pipe (line 95) | fn write_log_to_pipe(mut logd: &File, prio: i32, msg: &Utf8CStr) -> io::...
function with_logd_fd (line 120) | fn with_logd_fd<R, F: FnOnce(&File) -> io::Result<R>>(f: F) {
function magisk_log_to_pipe (line 130) | fn magisk_log_to_pipe(prio: i32, msg: &Utf8CStr) {
function zygisk_close_logd (line 137) | pub fn zygisk_close_logd() {
function zygisk_get_logd (line 143) | pub fn zygisk_get_logd() -> i32 {
function zygisk_log_to_pipe (line 178) | fn zygisk_log_to_pipe(prio: i32, msg: &Utf8CStr) {
type LogFile (line 212) | enum LogFile {
method as_write (line 218) | fn as_write(&mut self) -> &mut dyn Write {
function logfile_write_loop (line 226) | fn logfile_write_loop(mut pipe: File) -> io::Result<()> {
function setup_logfile (line 307) | pub fn setup_logfile() {
function start_log_daemon (line 319) | pub fn start_log_daemon() {
FILE: native/src/core/magisk.rs
function print_usage (line 14) | fn print_usage() {
type Cli (line 51) | struct Cli {
type MagiskAction (line 58) | enum MagiskAction {
method exec (line 184) | fn exec(self) -> LoggedResult<i32> {
type LocalVersion (line 83) | struct LocalVersion {}
type Version (line 87) | struct Version {}
type VersionCode (line 91) | struct VersionCode {}
type ListApplets (line 95) | struct ListApplets {}
type RemoveModules (line 99) | struct RemoveModules {
type InstallModule (line 106) | struct InstallModule {
type StartDaemon (line 113) | struct StartDaemon {}
type StopDaemon (line 117) | struct StopDaemon {}
type PostFsData (line 121) | struct PostFsData {}
type ServiceCmd (line 125) | struct ServiceCmd {}
type BootComplete (line 129) | struct BootComplete {}
type ZygoteRestart (line 133) | struct ZygoteRestart {}
type UnlockBlocks (line 137) | struct UnlockBlocks {}
type RestoreCon (line 141) | struct RestoreCon {}
type CloneAttr (line 145) | struct CloneAttr {
type CloneFile (line 154) | struct CloneFile {
type Sqlite (line 163) | struct Sqlite {
type PathCmd (line 170) | struct PathCmd {}
type DenyList (line 174) | struct DenyList {
type PreInitDevice (line 181) | struct PreInitDevice {}
function magisk_main (line 288) | pub fn magisk_main(argc: i32, argv: *mut *mut c_char) -> i32 {
FILE: native/src/core/module.rs
constant MAGISK_BIN_INJECT_PARTITIONS (line 20) | const MAGISK_BIN_INJECT_PARTITIONS: [&Utf8CStr; 4] = [
constant SECONDARY_READ_ONLY_PARTITIONS (line 27) | const SECONDARY_READ_ONLY_PARTITIONS: [&Utf8CStr; 3] =
type FsNodeMap (line 30) | type FsNodeMap = BTreeMap<String, FsNode>;
function bind_mount (line 39) | fn bind_mount(reason: &str, src: &Utf8CStr, dest: &Utf8CStr, rec: bool) {
function mount_dummy (line 47) | fn mount_dummy<'a>(
type PathTracker (line 69) | struct PathTracker<'a> {
function from (line 75) | fn from<'a>(path: &'a mut dyn Utf8CStrBuf) -> PathTracker<'a> {
function append (line 80) | fn append(&mut self, name: &str) -> PathTracker<'_> {
function reborrow (line 89) | fn reborrow(&mut self) -> PathTracker<'_> {
method drop (line 96) | fn drop(&mut self) {
type ModulePaths (line 102) | struct ModulePaths<'a> {
function new (line 109) | fn new<'a>(
function set_module (line 126) | fn set_module(&mut self, module: &str) -> ModulePaths<'_> {
function append (line 134) | fn append(&mut self, name: &str) -> ModulePaths<'_> {
function real (line 143) | fn real(&self) -> &Utf8CStr {
function module (line 148) | fn module(&self) -> &Utf8CStr {
function module_mnt (line 153) | fn module_mnt(&self) -> &Utf8CStr {
type MountPaths (line 159) | struct MountPaths<'a> {
function new (line 165) | fn new<'a>(real: &'a mut dyn Utf8CStrBuf, worker: &'a mut dyn Utf8CStrBu...
function append (line 174) | fn append(&mut self, name: &str) -> MountPaths<'_> {
function reborrow (line 181) | fn reborrow(&mut self) -> MountPaths<'_> {
function real (line 189) | fn real(&self) -> &Utf8CStr {
function worker (line 194) | fn worker(&self) -> &Utf8CStr {
type FsNode (line 199) | enum FsNode {
method new_dir (line 208) | fn new_dir() -> FsNode {
method collect (line 214) | fn collect(&mut self, mut paths: ModulePaths) -> LoggedResult<()> {
method parent_should_be_tmpfs (line 266) | fn parent_should_be_tmpfs(&self, target_path: &Utf8CStr) -> bool {
method children (line 279) | fn children(&mut self) -> Option<&mut FsNodeMap> {
method commit (line 286) | fn commit(&mut self, mut path: MountPaths, is_root_dir: bool) -> Logge...
method commit_tmpfs (line 338) | fn commit_tmpfs(&mut self, mut path: MountPaths) -> LoggedResult<()> {
function get_path_env (line 435) | fn get_path_env() -> String {
function inject_magisk_bins (line 441) | fn inject_magisk_bins(system: &mut FsNode, is_emulator: bool) {
function inject_zygisk_bins (line 567) | fn inject_zygisk_bins(name: &str, system: &mut FsNode) {
function upgrade_modules (line 623) | fn upgrade_modules() -> LoggedResult<()> {
function for_each_module (line 658) | fn for_each_module(mut func: impl FnMut(&DirEntry) -> LoggedResult<()>) ...
function disable_modules (line 668) | pub fn disable_modules() {
function run_uninstall_script (line 681) | fn run_uninstall_script(module_name: &Utf8CStr) {
function remove_modules (line 689) | pub fn remove_modules() {
function collect_modules (line 701) | fn collect_modules(zygisk_enabled: bool, open_zygisk: bool) -> Vec<Modul...
method handle_modules (line 823) | pub fn handle_modules(&self) {
method apply_modules (line 838) | fn apply_modules(&self, module_list: &[ModuleInfo]) {
FILE: native/src/core/mount.rs
constant DYNAMIC_MAJOR_MIN (line 17) | const DYNAMIC_MAJOR_MIN: u32 = 240;
constant DYNAMIC_MAJOR_MAX (line 18) | const DYNAMIC_MAJOR_MAX: u32 = 254;
function setup_preinit_dir (line 20) | pub fn setup_preinit_dir() {
function setup_module_mount (line 67) | pub fn setup_module_mount() {
function clean_mounts (line 80) | pub fn clean_mounts() {
type PartId (line 104) | enum PartId {
type EncryptType (line 112) | enum EncryptType {
function find_preinit_device (line 119) | pub fn find_preinit_device() -> String {
function revert_unmount (line 231) | pub fn revert_unmount(pid: i32) {
FILE: native/src/core/package.rs
constant EOCD_MAGIC (line 18) | const EOCD_MAGIC: u32 = 0x06054B50;
constant APK_SIGNING_BLOCK_MAGIC (line 19) | const APK_SIGNING_BLOCK_MAGIC: [u8; 16] = *b"APK Sig Block 42";
constant SIGNATURE_SCHEME_V2_MAGIC (line 20) | const SIGNATURE_SCHEME_V2_MAGIC: u32 = 0x7109871A;
constant PACKAGES_XML (line 21) | const PACKAGES_XML: &str = "/data/system/packages.xml";
function read_certificate (line 51) | fn read_certificate(apk: &mut File, version: i32) -> Vec<u8> {
function find_apk_path (line 152) | fn find_apk_path(pkg: &str) -> LoggedResult<Utf8CString> {
type Status (line 175) | enum Status {
type ManagerInfo (line 181) | pub struct ManagerInfo {
method check_dyn (line 233) | fn check_dyn(&mut self, daemon: &MagiskD, user: i32, pkg: &str) -> Sta...
method check_stub (line 268) | fn check_stub(&mut self, user: i32, pkg: &str) -> Status {
method check_orig (line 291) | fn check_orig(&mut self, user: i32) -> Status {
method install_stub (line 314) | fn install_stub(&mut self) {
method get_manager (line 336) | fn get_manager(&mut self, daemon: &MagiskD, user: i32, mut install: bo...
method default (line 191) | fn default() -> Self {
type TrackedFile (line 204) | struct TrackedFile {
method new (line 210) | fn new(path: Utf8CString) -> TrackedFile {
method is_same (line 219) | fn is_same(&self) -> bool {
method get_package_uid (line 434) | fn get_package_uid(&self, user: i32, pkg: &str) -> i32 {
method preserve_stub_apk (line 444) | pub fn preserve_stub_apk(&self) {
method get_manager_uid (line 461) | pub fn get_manager_uid(&self, user: i32) -> i32 {
method get_manager (line 467) | pub fn get_manager(&self, user: i32, install: bool) -> (i32, String) {
method ensure_manager (line 473) | pub fn ensure_manager(&self) {
method get_app_no_list (line 480) | pub fn get_app_no_list(&self) -> BitSet {
FILE: native/src/core/resetprop/cli.rs
type ResetProp (line 17) | struct ResetProp {
method get (line 76) | fn get(&self, key: &Utf8CStr) -> Option<String> {
method print_all (line 103) | fn print_all(&self) {
method set (line 123) | fn set(&self, key: &Utf8CStr, val: &Utf8CStr) {
method delete (line 170) | fn delete(&self, key: &Utf8CStr) -> bool {
method wait (line 180) | fn wait(&self) {
method load_file (line 214) | fn load_file(&self, file: &Utf8CStr) -> LoggedResult<()> {
method run (line 229) | fn run(self) -> LoggedResult<()> {
function print_usage (line 38) | fn print_usage(cmd: &str) {
function resetprop_main (line 256) | pub fn resetprop_main(argc: i32, argv: *mut *mut c_char) -> i32 {
function set_prop (line 302) | pub fn set_prop(key: &Utf8CStr, val: &Utf8CStr) {
function load_prop_file (line 311) | pub fn load_prop_file(file: &Utf8CStr) {
function get_prop (line 320) | pub fn get_prop(key: &Utf8CStr) -> String {
FILE: native/src/core/resetprop/mod.rs
type PropInfo (line 17) | struct PropInfo {
method read (line 101) | fn read(&self, reader: &mut PropReader) {
method update (line 105) | fn update(&mut self, val: &Utf8CStr) {
method is_long (line 109) | fn is_long(&self) -> bool {
type CharPtr (line 21) | type CharPtr = *const c_char;
type ReadCallback (line 22) | type ReadCallback = unsafe extern "C" fn(&mut PropReader, CharPtr, CharP...
type ForEachCallback (line 23) | type ForEachCallback = unsafe extern "C" fn(&PropInfo, &mut PropReader);
type PropReader (line 25) | enum PropReader<'a> {
function put_cstr (line 32) | fn put_cstr(&mut self, key: CharPtr, val: CharPtr, serial: u32) {
function put_str (line 52) | fn put_str(&mut self, key: String, val: String, serial: u32) {
function get_sys_prop (line 72) | fn get_sys_prop() -> SysProp;
function prop_info_is_long (line 74) | fn prop_info_is_long(info: &PropInfo) -> bool;
function sys_prop_find (line 76) | fn sys_prop_find(key: CharPtr) -> Option<&'static mut PropInfo>;
function sys_prop_update (line 78) | fn sys_prop_update(info: &mut PropInfo, val: CharPtr, val_len: u32) -> i32;
function sys_prop_add (line 80) | fn sys_prop_add(key: CharPtr, key_len: u32, val: CharPtr, val_len: u32) ...
function sys_prop_delete (line 82) | fn sys_prop_delete(key: CharPtr, prune: bool) -> i32;
function sys_prop_get_context (line 84) | fn sys_prop_get_context(key: CharPtr) -> CharPtr;
function sys_prop_area_serial (line 86) | fn sys_prop_area_serial() -> u32;
type SysProp (line 90) | struct SysProp {
method read (line 115) | fn read(&self, info: &PropInfo, reader: &mut PropReader) {
method find (line 124) | fn find(&self, key: &Utf8CStr) -> Option<&'static PropInfo> {
method find_mut (line 128) | fn find_mut(&self, key: &Utf8CStr) -> Option<&'static mut PropInfo> {
method set (line 132) | fn set(&self, key: &Utf8CStr, val: &Utf8CStr) {
method add (line 138) | fn add(&self, key: &Utf8CStr, val: &Utf8CStr) {
method update (line 149) | fn update(&self, info: &mut PropInfo, val: &Utf8CStr) {
method delete (line 155) | fn delete(&self, key: &Utf8CStr, prune: bool) -> bool {
method for_each (line 159) | fn for_each(&self, reader: &mut PropReader) {
method wait (line 168) | fn wait(&self, info: Option<&PropInfo>, old_serial: u32, new_serial: &...
method get_context (line 174) | fn get_context(&self, key: &Utf8CStr) -> &'static Utf8CStr {
method area_serial (line 178) | fn area_serial(&self) -> u32 {
FILE: native/src/core/resetprop/persist.rs
constant PERSIST_PROP_DIR (line 17) | const PERSIST_PROP_DIR: &str = "/data/property";
constant PERSIST_PROP (line 18) | const PERSIST_PROP: &str = concatcp!(PERSIST_PROP_DIR, "/persistent_prop...
type PropExt (line 20) | trait PropExt {
method find_index (line 21) | fn find_index(&self, name: &Utf8CStr) -> Result<usize, usize>;
method find (line 22) | fn find(self, name: &Utf8CStr) -> Option<PersistentPropertyRecord>;
method find_index (line 26) | fn find_index(&self, name: &Utf8CStr) -> Result<usize, usize> {
method find (line 31) | fn find(self, name: &Utf8CStr) -> Option<PersistentPropertyRecord> {
function check_proto (line 37) | fn check_proto() -> bool {
function file_get_prop (line 41) | fn file_get_prop(name: &Utf8CStr) -> LoggedResult<String> {
function file_set_prop (line 52) | fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedRes...
function proto_read_props (line 77) | fn proto_read_props() -> LoggedResult<PersistentProperties> {
function proto_write_props (line 90) | fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
function persist_get_prop (line 106) | pub(super) fn persist_get_prop(key: &Utf8CStr) -> LoggedResult<String> {
function persist_get_all_props (line 125) | pub(super) fn persist_get_all_props(reader: &mut PropReader) -> LoggedRe...
function persist_delete_prop (line 152) | pub(super) fn persist_delete_prop(key: &Utf8CStr) -> LoggedResult<()> {
function persist_set_prop (line 164) | pub(super) fn persist_set_prop(key: &Utf8CStr, val: &Utf8CStr) -> Logged...
FILE: native/src/core/resetprop/sys.cpp
type SysProp (line 12) | struct SysProp {
function prop_info_is_long (line 20) | bool prop_info_is_long(const prop_info &info) {
function SysProp (line 24) | SysProp get_sys_prop() {
FILE: native/src/core/scripting.cpp
function set_script_env (line 23) | static void set_script_env() {
function exec_script (line 32) | void exec_script(Utf8CStr script) {
function exec_common_scripts (line 77) | void exec_common_scripts(Utf8CStr stage) {
function exec_module_scripts (line 119) | void exec_module_scripts(Utf8CStr stage, const rust::Vec<ModuleInfo> &mo...
function install_apk (line 160) | void install_apk(Utf8CStr apk) {
function uninstall_pkg (line 173) | void uninstall_pkg(Utf8CStr pkg) {
function clear_pkg (line 186) | void clear_pkg(const char *pkg, int user_id) {
function abort (line 193) | static void abort(FILE *fp, const char *fmt, ...) {
function install_module (line 208) | void install_module(Utf8CStr file) {
FILE: native/src/core/selinux.rs
constant UNLABEL_CON (line 7) | const UNLABEL_CON: &Utf8CStr = cstr!("u:object_r:unlabeled:s0");
constant SYSTEM_CON (line 8) | const SYSTEM_CON: &Utf8CStr = cstr!("u:object_r:system_file:s0");
constant ADB_CON (line 9) | const ADB_CON: &Utf8CStr = cstr!("u:object_r:adb_data_file:s0");
constant ROOT_CON (line 10) | const ROOT_CON: &Utf8CStr = cstr!("u:object_r:rootfs:s0");
function restore_syscon_from_unlabeled (line 12) | fn restore_syscon_from_unlabeled(
function restore_syscon (line 36) | fn restore_syscon(path: &mut dyn Utf8CStrBuf) -> LoggedResult<()> {
function restorecon (line 54) | pub(crate) fn restorecon() {
function restore_tmpcon (line 75) | pub(crate) fn restore_tmpcon() -> LoggedResult<()> {
function lgetfilecon (line 99) | pub(crate) fn lgetfilecon(path: &Utf8CStr, con: &mut [u8]) -> bool {
function setfilecon (line 104) | pub(crate) fn setfilecon(path: &Utf8CStr, con: &Utf8CStr) -> bool {
FILE: native/src/core/socket.rs
type Encodable (line 9) | pub trait Encodable {
method encode (line 10) | fn encode(&self, w: &mut impl Write) -> io::Result<()>;
method encode (line 40) | fn encode(&self, w: &mut impl Write) -> io::Result<()> {
method encode (line 73) | fn encode(&self, w: &mut impl Write) -> io::Result<()> {
method encode (line 91) | fn encode(&self, w: &mut impl Write) -> io::Result<()> {
type Decodable (line 13) | pub trait Decodable: Sized + Encodable {
method decode (line 14) | fn decode(r: &mut impl Read) -> io::Result<Self>;
method decode (line 50) | fn decode(r: &mut impl Read) -> io::Result<Self> {
method decode (line 80) | fn decode(r: &mut impl Read) -> io::Result<Self> {
method decode (line 98) | fn decode(r: &mut impl Read) -> io::Result<String> {
type IpcRead (line 106) | pub trait IpcRead {
method read_decodable (line 107) | fn read_decodable<E: Decodable>(&mut self) -> io::Result<E>;
method read_decodable (line 112) | fn read_decodable<E: Decodable>(&mut self) -> io::Result<E> {
type IpcWrite (line 117) | pub trait IpcWrite {
method write_encodable (line 118) | fn write_encodable<E: Encodable + ?Sized>(&mut self, val: &E) -> io::R...
method write_encodable (line 123) | fn write_encodable<E: Encodable + ?Sized>(&mut self, val: &E) -> io::R...
type UnixSocketExt (line 128) | pub trait UnixSocketExt {
method send_fds (line 129) | fn send_fds(&mut self, fd: &[RawFd]) -> io::Result<()>;
method recv_fd (line 130) | fn recv_fd(&mut self) -> io::Result<Option<OwnedFd>>;
method recv_fds (line 131) | fn recv_fds(&mut self) -> io::Result<Vec<OwnedFd>>;
method send_fds (line 135) | fn send_fds(&mut self, fds: &[RawFd]) -> io::Result<()> {
method recv_fd (line 153) | fn recv_fd(&mut self) -> io::Result<Option<OwnedFd>> {
method recv_fds (line 191) | fn recv_fds(&mut self) -> io::Result<Vec<OwnedFd>> {
function send_fd (line 217) | pub fn send_fd(socket: RawFd, fd: RawFd) -> bool {
function recv_fd (line 226) | pub fn recv_fd(socket: RawFd) -> RawFd {
function recv_fds (line 235) | pub fn recv_fds(socket: RawFd) -> Vec<RawFd> {
FILE: native/src/core/sqlite.cpp
function load_sqlite (line 50) | static bool load_sqlite() {
function sql_exec_impl (line 103) | int sql_exec_impl(
function sqlite3 (line 175) | sqlite3 *open_and_init_db() {
function db_exec (line 313) | bool db_exec(const char *sql, DbArgs args, db_exec_callback exec_fn) {
FILE: native/src/core/su/connect.rs
type Extra (line 20) | struct Extra<'a> {
type ExtraVal (line 25) | enum ExtraVal<'a> {
function add_intent (line 33) | fn add_intent(&self, cmd: &mut Command) {
function add_bind (line 56) | fn add_bind(&self, cmd: &mut Command) {
function add_bind_legacy (line 82) | fn add_bind_legacy(&self, cmd: &mut Command) {
type SuAppContext (line 93) | pub(super) struct SuAppContext<'a> {
function exec_cmd (line 102) | fn exec_cmd(&self, action: &'static str, extras: &[Extra], use_provider:...
function app_request (line 168) | fn app_request(&mut self) {
function app_notify (line 232) | fn app_notify(&self) {
function app_log (line 250) | fn app_log(&self) {
function connect_app (line 297) | pub(super) fn connect_app(&mut self) {
FILE: native/src/core/su/daemon.rs
constant DEFAULT_SHELL (line 17) | const DEFAULT_SHELL: &str = "/system/bin/sh";
method default (line 20) | fn default() -> Self {
type SuInfo (line 35) | pub struct SuInfo {
method allow (line 72) | fn allow(uid: i32) -> SuInfo {
method deny (line 85) | fn deny(uid: i32) -> SuInfo {
type AccessInfo (line 44) | struct AccessInfo {
method new (line 100) | fn new(settings: RootSettings) -> AccessInfo {
method is_fresh (line 107) | fn is_fresh(&self) -> bool {
method refresh (line 111) | fn refresh(&mut self) {
method default (line 50) | fn default() -> Self {
method default (line 63) | fn default() -> Self {
method su_daemon_handler (line 117) | pub fn su_daemon_handler(&self, mut client: UnixStream, cred: UCred) {
method get_su_info (line 201) | fn get_su_info(&self, uid: i32) -> Arc<SuInfo> {
method build_su_info (line 217) | fn build_su_info(&self, uid: i32) -> Arc<SuInfo> {
method build_su_info (line 290) | fn build_su_info(&self, uid: i32) -> Arc<SuInfo> {
FILE: native/src/core/su/db.rs
method default (line 10) | fn default() -> Self {
type RootSettings (line 16) | pub struct RootSettings {
method on_row (line 23) | fn on_row(&mut self, columns: &[String], values: &DbValues) {
type UidList (line 36) | struct UidList(Vec<i32>);
method on_row (line 39) | fn on_row(&mut self, _: &[String], values: &DbValues) {
method get_root_settings (line 45) | pub fn get_root_settings(&self, uid: i32, settings: &mut RootSettings) -...
method prune_su_access (line 55) | pub fn prune_su_access(&self) {
method uid_granted_root (line 85) | pub fn uid_granted_root(&self, mut uid: i32) -> bool {
FILE: native/src/core/su/pts.rs
constant TIOCGPTN (line 16) | const TIOCGPTN: u32 = 0x80045430;
function ioctl (line 20) | fn ioctl(fd: c_int, request: u32, ...) -> i32;
function get_pty_num (line 23) | pub fn get_pty_num(fd: i32) -> i32 {
function sync_winsize (line 31) | fn sync_winsize(ptmx: i32) {
function splice (line 38) | fn splice(fd_in: impl AsFd, fd_out: impl AsFd, len: usize) -> OsResult<'...
function pump_via_copy (line 43) | fn pump_via_copy(mut fd_in: &File, mut fd_out: &File) -> LoggedResult<()> {
function pump_via_splice (line 51) | fn pump_via_splice(fd_in: &File, fd_out: &File, pipe: &(File, File)) -> ...
function set_stdin_raw (line 73) | fn set_stdin_raw() -> LoggedResult<Termios> {
function restore_stdin (line 91) | fn restore_stdin(term: Termios) -> LoggedResult<()> {
function pump_tty_impl (line 98) | fn pump_tty_impl(ptmx: File, pump_stdin: bool) -> LoggedResult<()> {
function pump_tty (line 165) | pub fn pump_tty(ptmx: RawFd, pump_stdin: bool) {
FILE: native/src/core/su/su.cpp
function usage (line 38) | [[noreturn]] static void usage(int status) {
function sighandler (line 66) | static void sighandler(int sig) {
function setup_sighandlers (line 81) | static void setup_sighandlers(void (*handler)(int)) {
function su_client_main (line 89) | int su_client_main(int argc, char *argv[]) {
function drop_caps (line 249) | static void drop_caps() {
function proc_is_restricted (line 277) | static bool proc_is_restricted(pid_t pid) {
function set_identity (line 310) | static void set_identity(int uid, const rust::Vec<gid_t> &groups) {
function exec_root_shell (line 328) | void exec_root_shell(int client, int pid, SuRequest &req, MntNsMode mode) {
FILE: native/src/core/thread.rs
constant THREAD_IDLE_MAX_SEC (line 10) | const THREAD_IDLE_MAX_SEC: u64 = 60;
constant CORE_POOL_SIZE (line 11) | const CORE_POOL_SIZE: i32 = 3;
type ThreadPool (line 14) | pub struct ThreadPool {
method pool_loop (line 28) | fn pool_loop(&self, is_core_pool: bool) {
method exec_task_impl (line 67) | fn exec_task_impl(&self, f: impl FnOnce() + Send + 'static) {
method exec_task (line 95) | pub fn exec_task(f: impl FnOnce() + Send + 'static) {
type PoolInfo (line 21) | struct PoolInfo {
FILE: native/src/core/utils.cpp
function read_string (line 14) | bool read_string(int fd, std::string &str) {
function string (line 21) | string read_string(int fd) {
function write_string (line 27) | void write_string(int fd, string_view str) {
function unlock_blocks (line 47) | void unlock_blocks() {
function check_key_combo (line 68) | bool check_key_combo() {
FILE: native/src/core/zygisk/api.hpp
type zygisk (line 102) | namespace zygisk {
type Api (line 104) | struct Api
type AppSpecializeArgs (line 105) | struct AppSpecializeArgs
method AppSpecializeArgs (line 166) | AppSpecializeArgs() = delete;
type ServerSpecializeArgs (line 106) | struct ServerSpecializeArgs
method ServerSpecializeArgs (line 177) | ServerSpecializeArgs() = delete;
class ModuleBase (line 108) | class ModuleBase {
method onLoad (line 113) | virtual void onLoad([[maybe_unused]] Api *api, [[maybe_unused]] JNIE...
method preAppSpecialize (line 127) | virtual void preAppSpecialize([[maybe_unused]] AppSpecializeArgs *ar...
method postAppSpecialize (line 132) | virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeA...
method preServerSpecialize (line 136) | virtual void preServerSpecialize([[maybe_unused]] ServerSpecializeAr...
method postServerSpecialize (line 140) | virtual void postServerSpecialize([[maybe_unused]] const ServerSpeci...
type AppSpecializeArgs (line 143) | struct AppSpecializeArgs {
method AppSpecializeArgs (line 166) | AppSpecializeArgs() = delete;
type ServerSpecializeArgs (line 169) | struct ServerSpecializeArgs {
method ServerSpecializeArgs (line 177) | ServerSpecializeArgs() = delete;
type internal (line 180) | namespace internal {
type api_table (line 181) | struct api_table
type module_abi (line 319) | struct module_abi {
method module_abi (line 328) | module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), ...
type api_table (line 336) | struct api_table {
function entry_impl (line 352) | void entry_impl(api_table *table, JNIEnv *env) {
type Option (line 186) | enum Option : int {
type StateFlag (line 203) | enum StateFlag : uint32_t {
type Api (line 213) | struct Api {
type internal (line 317) | namespace internal {
type api_table (line 181) | struct api_table
type module_abi (line 319) | struct module_abi {
method module_abi (line 328) | module_abi(ModuleBase *module) : api_version(ZYGISK_API_VERSION), ...
type api_table (line 336) | struct api_table {
function entry_impl (line 352) | void entry_impl(api_table *table, JNIEnv *env) {
FILE: native/src/core/zygisk/daemon.rs
constant NBPROP (line 18) | const NBPROP: &Utf8CStr = cstr!("ro.dalvik.vm.native.bridge");
constant ZYGISKLDR (line 19) | const ZYGISKLDR: &str = "libzygisk.so";
constant UNMOUNT_MASK (line 20) | const UNMOUNT_MASK: u32 =
function zygisk_should_load_module (line 23) | pub fn zygisk_should_load_module(flags: u32) -> bool {
function exec_zygiskd (line 28) | fn exec_zygiskd(is_64_bit: bool, remote: UnixStream) {
type ZygiskState (line 62) | pub struct ZygiskState {
method connect_zygiskd (line 69) | fn connect_zygiskd(&mut self, mut client: UnixStream, daemon: &MagiskD...
method reset (line 110) | pub fn reset(&mut self, mut restore: bool) {
method set_prop (line 129) | pub fn set_prop(&mut self) {
method restore_prop (line 148) | pub fn restore_prop(&mut self) {
method zygisk_handler (line 159) | pub fn zygisk_handler(&self, mut client: UnixStream) {
method get_module_fds (line 178) | fn get_module_fds(&self, is_64_bit: bool) -> Option<Vec<RawFd>> {
method get_process_info (line 191) | fn get_process_info(&self, mut client: UnixStream) -> LoggedResult<()> {
method get_mod_dir (line 242) | fn get_mod_dir(&self, mut client: UnixStream) -> LoggedResult<()> {
method zygisk_enabled (line 262) | pub fn zygisk_enabled(&self) -> bool {
FILE: native/src/core/zygisk/entry.cpp
function zygiskd (line 16) | static void zygiskd(int socket) {
function zygisk_main (line 78) | int zygisk_main(int argc, char *argv[]) {
FILE: native/src/core/zygisk/gen_jni_hooks.py
class JType (line 6) | class JType:
method __init__ (line 7) | def __init__(self, cpp: str, jni: str):
class JArray (line 12) | class JArray(JType):
method __init__ (line 13) | def __init__(self, type: JType):
class Argument (line 21) | class Argument:
method __init__ (line 22) | def __init__(self, name: str, type: JType, set_arg=False):
method cpp (line 27) | def cpp(self) -> str:
class Anon (line 32) | class Anon(Argument):
method __init__ (line 35) | def __init__(self, type: JType):
class Return (line 40) | class Return:
method __init__ (line 41) | def __init__(self, value: str, type: JType):
class JNIMethod (line 46) | class JNIMethod:
method __init__ (line 47) | def __init__(self, name: str, ret: Return, args: list[Argument]):
method arg_list_name (line 52) | def arg_list_name(self) -> str:
method arg_list_cpp (line 55) | def arg_list_cpp(self) -> str:
method cpp_fn_type (line 60) | def cpp_fn_type(self) -> str:
method cpp_lambda_sig (line 63) | def cpp_lambda_sig(self) -> str:
method jni_sig (line 66) | def jni_sig(self):
class JNIHook (line 71) | class JNIHook(JNIMethod):
method __init__ (line 72) | def __init__(self, ver: str, ret: Return, args: list[Argument]):
method hook_target (line 76) | def hook_target(self):
method body (line 79) | def body(self, orig_fn_ptr: str):
function ind (line 83) | def ind(i):
class ForkApp (line 96) | class ForkApp(JNIHook):
method __init__ (line 97) | def __init__(self, ver, args):
method hook_target (line 100) | def hook_target(self):
method init_args (line 103) | def init_args(self):
method body (line 106) | def body(self, orig_fn_ptr: str):
class SpecializeApp (line 123) | class SpecializeApp(ForkApp):
method __init__ (line 124) | def __init__(self, ver: str, args: list[Argument]):
method hook_target (line 128) | def hook_target(self):
class ForkServer (line 132) | class ForkServer(ForkApp):
method hook_target (line 133) | def hook_target(self):
method init_args (line 136) | def init_args(self):
function gen_jni_def (line 615) | def gen_jni_def(field: str, methods: list[JNIHook]):
FILE: native/src/core/zygisk/hook.cpp
type HookContext (line 100) | struct HookContext : JniHookDefinitions {
function JniHookDefinitions (line 134) | static JniHookDefinitions *get_defs() {
function DCL_HOOK_FUNC (line 144) | DCL_HOOK_FUNC(static char *, strdup, const char * str) {
function DCL_HOOK_FUNC (line 152) | DCL_HOOK_FUNC(int, fork) {
function DCL_HOOK_FUNC (line 157) | DCL_HOOK_FUNC(static int, unshare, int flags) {
function DCL_HOOK_FUNC (line 170) | DCL_HOOK_FUNC(static int, selinux_android_setcontext,
function DCL_HOOK_FUNC (line 178) | DCL_HOOK_FUNC(static void, android_log_close) {
function DCL_HOOK_FUNC (line 188) | DCL_HOOK_FUNC(static int, dlclose, void *handle) {
function DCL_HOOK_FUNC (line 199) | DCL_HOOK_FUNC(static int, pthread_attr_destroy, void *target) {
function get_fd_max (line 229) | static size_t get_fd_max() {
function NativeBridgeRuntimeCallbacks (line 286) | static const NativeBridgeRuntimeCallbacks* find_runtime_callbacks(struct...
type trace_arg (line 349) | struct trace_arg {
function JNIMethodsDyn (line 464) | JNIMethodsDyn HookContext::get_jni_methods(JNIEnv *env, jclass clazz) co...
function register_jni_methods (line 471) | static void register_jni_methods(JNIEnv *env, jclass clazz, JNIMethods m...
function hook_entry (line 620) | void hook_entry() {
function hookJniNativeMethods (line 625) | void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod ...
FILE: native/src/core/zygisk/jni_hooks.hpp
type JniHookDefinitions (line 4) | struct JniHookDefinitions
type JniHookDefinitions (line 7) | struct JniHookDefinitions {
FILE: native/src/core/zygisk/mod.rs
function exec_companion_entry (line 9) | extern "C" fn exec_companion_entry(client: RawFd, companion_handler: ext...
FILE: native/src/core/zygisk/module.cpp
function zygisk_request (line 14) | static int zygisk_request(int req) {
function sigmask (line 309) | static int sigmask(int how, int signum) {
type stat (line 351) | struct stat
FILE: native/src/core/zygisk/module.hpp
type ZygiskContext (line 8) | struct ZygiskContext
type RegisterInfo (line 244) | struct RegisterInfo {
type IgnoreInfo (line 251) | struct IgnoreInfo {
method is_child (line 276) | bool is_child() const { return pid <= 0; }
type ZygiskModule (line 9) | struct ZygiskModule
method onLoad (line 172) | void onLoad(void *env) {
method clearApi (line 187) | void clearApi() { memset(&api, 0, sizeof(api)); }
type AppSpecializeArgs_v1 (line 11) | struct AppSpecializeArgs_v1
method AppSpecializeArgs_v1 (line 89) | AppSpecializeArgs_v1(const AppSpecializeArgs_v5 *a) :
type AppSpecializeArgs_v3 (line 13) | struct AppSpecializeArgs_v3
method AppSpecializeArgs_v3 (line 51) | AppSpecializeArgs_v3(
type AppSpecializeArgs_v5 (line 15) | struct AppSpecializeArgs_v5
method AppSpecializeArgs_v5 (line 63) | AppSpecializeArgs_v5(
type module_abi_v1 (line 17) | struct module_abi_v1
type api_abi_v1 (line 23) | struct api_abi_v1
type api_abi_v2 (line 24) | struct api_abi_v2
type api_abi_v4 (line 26) | struct api_abi_v4
type AppSpecializeArgs_v3 (line 31) | struct AppSpecializeArgs_v3 {
method AppSpecializeArgs_v3 (line 51) | AppSpecializeArgs_v3(
type AppSpecializeArgs_v5 (line 60) | struct AppSpecializeArgs_v5 : public AppSpecializeArgs_v3 {
method AppSpecializeArgs_v5 (line 63) | AppSpecializeArgs_v5(
type AppSpecializeArgs_v1 (line 71) | struct AppSpecializeArgs_v1 {
method AppSpecializeArgs_v1 (line 89) | AppSpecializeArgs_v1(const AppSpecializeArgs_v5 *a) :
type ServerSpecializeArgs_v1 (line 99) | struct ServerSpecializeArgs_v1 {
method ServerSpecializeArgs_v1 (line 107) | ServerSpecializeArgs_v1(
type module_abi_v1 (line 115) | struct module_abi_v1 {
type api_abi_base (line 133) | struct api_abi_base {
type api_abi_v1 (line 138) | struct api_abi_v1 : public api_abi_base {
type api_abi_v2 (line 147) | struct api_abi_v2 : public api_abi_v1 {
type api_abi_v4 (line 152) | struct api_abi_v4 : public api_abi_base {
type ZygiskModule (line 170) | struct ZygiskModule {
method onLoad (line 172) | void onLoad(void *env) {
method clearApi (line 187) | void clearApi() { memset(&api, 0, sizeof(api)); }
type ZygiskContext (line 227) | struct ZygiskContext {
type RegisterInfo (line 244) | struct RegisterInfo {
type IgnoreInfo (line 251) | struct IgnoreInfo {
method is_child (line 276) | bool is_child() const { return pid <= 0; }
FILE: native/src/core/zygisk/zygisk.hpp
type NativeBridgeRuntimeCallbacks (line 31) | struct NativeBridgeRuntimeCallbacks {
type NativeBridgeCallbacks (line 38) | struct NativeBridgeCallbacks {
FILE: native/src/external/lz4-sys/src/lib.rs
type size_t (line 40) | pub type size_t = usize;
type LZ4FCompressionContext (line 44) | pub struct LZ4FCompressionContext(pub *mut c_void);
type LZ4FDecompressionContext (line 49) | pub struct LZ4FDecompressionContext(pub *mut c_void);
type LZ4FErrorCode (line 52) | pub type LZ4FErrorCode = size_t;
type BlockSize (line 56) | pub enum BlockSize {
method get_size (line 65) | pub fn get_size(&self) -> usize {
type BlockMode (line 77) | pub enum BlockMode {
type ContentChecksum (line 84) | pub enum ContentChecksum {
type FrameType (line 91) | pub enum FrameType {
type BlockChecksum (line 98) | pub enum BlockChecksum {
type LZ4FFrameInfo (line 105) | pub struct LZ4FFrameInfo {
type LZ4FPreferences (line 117) | pub struct LZ4FPreferences {
type LZ4FCompressOptions (line 127) | pub struct LZ4FCompressOptions {
type LZ4FDecompressOptions (line 136) | pub struct LZ4FDecompressOptions {
type LZ4StreamEncode (line 144) | pub struct LZ4StreamEncode(c_void);
type LZ4StreamDecode (line 148) | pub struct LZ4StreamDecode(c_void);
constant LZ4F_VERSION (line 150) | pub const LZ4F_VERSION: c_uint = 100;
function LZ4_compress_default (line 156) | pub fn LZ4_compress_default(
function LZ4_compress_fast (line 165) | pub fn LZ4_compress_fast(
function LZ4_compress_HC (line 175) | pub fn LZ4_compress_HC(
function LZ4_decompress_safe (line 185) | pub fn LZ4_decompress_safe(
function LZ4F_isError (line 193) | pub fn LZ4F_isError(code: size_t) -> c_uint;
function LZ4F_getErrorName (line 196) | pub fn LZ4F_getErrorName(code: size_t) -> *const c_char;
function LZ4F_createCompressionContext (line 212) | pub fn LZ4F_createCompressionContext(
function LZ4F_freeCompressionContext (line 219) | pub fn LZ4F_freeCompressionContext(ctx: LZ4FCompressionContext) -> LZ4FE...
function LZ4F_compressBegin (line 234) | pub fn LZ4F_compressBegin(
function LZ4F_compressBound (line 248) | pub fn LZ4F_compressBound(
function LZ4F_compressUpdate (line 270) | pub fn LZ4F_compressUpdate(
function LZ4F_flush (line 292) | pub fn LZ4F_flush(
function LZ4F_compressEnd (line 313) | pub fn LZ4F_compressEnd(
function LZ4F_createDecompressionContext (line 334) | pub fn LZ4F_createDecompressionContext(
function LZ4F_freeDecompressionContext (line 340) | pub fn LZ4F_freeDecompressionContext(ctx: LZ4FDecompressionContext) -> L...
function LZ4F_getFrameInfo (line 358) | pub fn LZ4F_getFrameInfo(
function LZ4F_decompress (line 401) | pub fn LZ4F_decompress(
function LZ4_versionNumber (line 411) | pub fn LZ4_versionNumber() -> c_int;
function LZ4_compressBound (line 414) | pub fn LZ4_compressBound(size: c_int) -> c_int;
function LZ4_createStream (line 417) | pub fn LZ4_createStream() -> *mut LZ4StreamEncode;
function LZ4_compress_continue (line 423) | pub fn LZ4_compress_continue(
function LZ4_freeStream (line 431) | pub fn LZ4_freeStream(LZ4_stream: *mut LZ4StreamEncode) -> c_int;
function LZ4_setStreamDecode (line 436) | pub fn LZ4_setStreamDecode(
function LZ4_createStreamDecode (line 443) | pub fn LZ4_createStreamDecode() -> *mut LZ4StreamDecode;
function LZ4_decompress_safe_continue (line 450) | pub fn LZ4_decompress_safe_continue(
function LZ4_freeStreamDecode (line 459) | pub fn LZ4_freeStreamDecode(LZ4_stream: *mut LZ4StreamDecode) -> c_int;
function LZ4F_resetDecompressionContext (line 466) | pub fn LZ4F_resetDecompressionContext(ctx: LZ4FDecompressionContext);
function test_version_number (line 471) | fn test_version_number() {
function test_frame_info_size (line 478) | fn test_frame_info_size() {
FILE: native/src/external/lz4-sys/src/wasm_shim.rs
constant USIZE_ALIGN (line 24) | const USIZE_ALIGN: usize = core::mem::align_of::<usize>();
constant USIZE_SIZE (line 25) | const USIZE_SIZE: usize = core::mem::size_of::<usize>();
function rust_lz4_wasm_shim_malloc (line 28) | pub extern "C" fn rust_lz4_wasm_shim_malloc(size: usize) -> *mut c_void {
function rust_lz4_wasm_shim_memcmp (line 33) | pub extern "C" fn rust_lz4_wasm_shim_memcmp(
function rust_lz4_wasm_shim_calloc (line 51) | pub extern "C" fn rust_lz4_wasm_shim_calloc(nmemb: usize, size: usize) -...
function wasm_shim_alloc (line 57) | fn wasm_shim_alloc<const ZEROED: bool>(size: usize) -> *mut c_void {
function rust_lz4_wasm_shim_free (line 82) | pub unsafe extern "C" fn rust_lz4_wasm_shim_free(ptr: *mut c_void) {
function rust_lz4_wasm_shim_memcpy (line 96) | pub unsafe extern "C" fn rust_lz4_wasm_shim_memcpy(
function rust_lz4_wasm_shim_memmove (line 106) | pub unsafe extern "C" fn rust_lz4_wasm_shim_memmove(
function rust_lz4_wasm_shim_memset (line 116) | pub unsafe extern "C" fn rust_lz4_wasm_shim_memset(
FILE: native/src/external/xz-embedded/xz.h
type xz_mode (line 56) | enum xz_mode {
type xz_ret (line 112) | enum xz_ret {
type xz_buf (line 140) | struct xz_buf {
type xz_dec (line 153) | struct xz_dec
type xz_mode (line 198) | enum xz_mode
type xz_dec (line 218) | struct xz_dec
type xz_buf (line 218) | struct xz_buf
type xz_dec (line 231) | struct xz_dec
type xz_dec (line 238) | struct xz_dec
FILE: native/src/external/xz-embedded/xz_config.h
function get_unaligned_le32 (line 76) | static inline uint32_t get_unaligned_le32(const uint8_t *buf)
function get_unaligned_be32 (line 86) | static inline uint32_t get_unaligned_be32(const uint8_t *buf)
function put_unaligned_le32 (line 96) | static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
function put_unaligned_be32 (line 106) | static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
FILE: native/src/external/xz-embedded/xz_crc32.c
function XZ_EXTERN (line 30) | XZ_EXTERN void xz_crc32_init(void)
function XZ_EXTERN (line 49) | XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
FILE: native/src/external/xz-embedded/xz_dec_lzma2.c
type dictionary (line 44) | struct dictionary {
type rc_dec (line 95) | struct rc_dec {
type lzma_len_dec (line 115) | struct lzma_len_dec {
type lzma_dec (line 132) | struct lzma_dec {
type lzma2_dec (line 214) | struct lzma2_dec {
type xz_dec_lzma2 (line 253) | struct xz_dec_lzma2 {
function dict_reset (line 286) | static void dict_reset(struct dictionary *dict, struct xz_buf *b)
function dict_limit (line 300) | static void dict_limit(struct dictionary *dict, size_t out_max)
function dict_has_space (line 309) | static inline bool dict_has_space(const struct dictionary *dict)
function dict_get (line 320) | static inline uint32_t dict_get(const struct dictionary *dict, uint32_t ...
function dict_put (line 333) | static inline void dict_put(struct dictionary *dict, uint8_t byte)
function dict_repeat (line 346) | static bool dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t...
function dict_uncompressed (line 374) | static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
function dict_flush (line 416) | static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b)
function rc_reset (line 438) | static void rc_reset(struct rc_dec *rc)
function rc_read_init (line 449) | static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b)
function rc_limit_exceeded (line 463) | static inline bool rc_limit_exceeded(const struct rc_dec *rc)
function rc_is_finished (line 472) | static inline bool rc_is_finished(const struct rc_dec *rc)
function __always_inline (line 478) | static __always_inline void rc_normalize(struct rc_dec *rc)
function __always_inline (line 497) | static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob)
function __always_inline (line 519) | static __always_inline uint32_t rc_bittree(struct rc_dec *rc,
function __always_inline (line 535) | static __always_inline void rc_bittree_reverse(struct rc_dec *rc,
function rc_direct (line 553) | static inline void rc_direct(struct rc_dec *rc, uint32_t *dest, uint32_t...
type xz_dec_lzma2 (line 572) | struct xz_dec_lzma2
function lzma_literal (line 581) | static void lzma_literal(struct xz_dec_lzma2 *s)
function lzma_len (line 619) | static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l,
function lzma_match (line 646) | static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
function lzma_rep_match (line 688) | static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
function lzma_main (line 722) | static bool lzma_main(struct xz_dec_lzma2 *s)
function lzma_reset (line 767) | static void lzma_reset(struct xz_dec_lzma2 *s)
function lzma_props (line 799) | static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
function lzma2_lzma (line 846) | static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
function xz_ret (line 931) | xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
function xz_dec_lzma2 (line 1104) | xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
function xz_ret (line 1128) | xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props)
function XZ_EXTERN (line 1165) | XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s)
FILE: native/src/external/xz-embedded/xz_dec_stream.c
type xz_dec_hash (line 20) | struct xz_dec_hash {
type xz_dec (line 26) | struct xz_dec {
function fill_temp (line 168) | static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
function dec_vli (line 186) | static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
function dec_block (line 229) | static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
function index_update (line 299) | static void index_update(struct xz_dec *s, const struct xz_buf *b)
function dec_index (line 314) | static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
function crc_validate (line 365) | static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
function check_skip (line 390) | static bool check_skip(struct xz_dec *s, struct xz_buf *b)
function dec_stream_header (line 407) | static enum xz_ret dec_stream_header(struct xz_dec *s)
function dec_stream_footer (line 443) | static enum xz_ret dec_stream_footer(struct xz_dec *s)
type xz_ret (line 470) | enum xz_ret
type xz_dec (line 470) | struct xz_dec
type xz_ret (line 472) | enum xz_ret
function dec_main (line 570) | static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
function xz_ret (line 760) | xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
function xz_dec (line 796) | xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
function XZ_EXTERN (line 826) | XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
function XZ_EXTERN (line 838) | XZ_EXTERN void xz_dec_end(struct xz_dec *s)
FILE: native/src/external/xz-embedded/xz_lzma2.h
type lzma_state (line 42) | enum lzma_state {
function lzma_state_literal (line 64) | static inline void lzma_state_literal(enum lzma_state *state)
function lzma_state_match (line 75) | static inline void lzma_state_match(enum lzma_state *state)
function lzma_state_long_rep (line 81) | static inline void lzma_state_long_rep(enum lzma_state *state)
function lzma_state_short_rep (line 87) | static inline void lzma_state_short_rep(enum lzma_state *state)
function lzma_state_is_literal (line 93) | static inline bool lzma_state_is_literal(enum lzma_state state)
function lzma_get_dist_state (line 147) | static inline uint32_t lzma_get_dist_state(uint32_t len)
FILE: native/src/external/xz-embedded/xz_private.h
type xz_mode (line 109) | enum xz_mode
type xz_dec_lzma2 (line 118) | struct xz_dec_lzma2
type xz_dec_lzma2 (line 122) | struct xz_dec_lzma2
type xz_buf (line 123) | struct xz_buf
type xz_dec_lzma2 (line 126) | struct xz_dec_lzma2
type xz_dec_bcj (line 141) | struct xz_dec_bcj
type xz_dec_bcj (line 148) | struct xz_dec_bcj
type xz_dec_lzma2 (line 149) | struct xz_dec_lzma2
type xz_buf (line 150) | struct xz_buf
FILE: native/src/external/xz-embedded/xz_stream.h
type vli_type (line 43) | typedef uint64_t vli_type;
type xz_check (line 52) | enum xz_check {
FILE: native/src/include/codegen.rs
type ResultExt (line 11) | trait ResultExt<T> {
method ok_or_exit (line 12) | fn ok_or_exit(self) -> T;
function ok_or_exit (line 16) | fn ok_or_exit(self) -> T {
function write_if_diff (line 27) | fn write_if_diff<P: AsRef<Path>>(path: P, bytes: &[u8]) -> io::Result<()> {
function gen_cxx_binding (line 39) | pub fn gen_cxx_binding(name: &str) {
FILE: native/src/include/consts.rs
constant POST_FS_DATA_WAIT_TIME (line 7) | pub const POST_FS_DATA_WAIT_TIME: i32 = 40;
constant APPLET_NAMES (line 8) | pub const APPLET_NAMES: &[&str] = &["su", "resetprop"];
constant MAGISK_FULL_VER (line 12) | pub const MAGISK_FULL_VER: &str = concatcp!(MAGISK_VERSION, "(", MAGISK_...
constant APP_PACKAGE_NAME (line 14) | pub const APP_PACKAGE_NAME: &str = "com.topjohnwu.magisk";
constant LOGFILE (line 16) | pub const LOGFILE: &str = "/cache/magisk.log";
constant SECURE_DIR (line 19) | pub const SECURE_DIR: &str = "/data/adb";
constant MODULEROOT (line 20) | pub const MODULEROOT: &str = concatcp!(SECURE_DIR, "/modules");
constant MODULEUPGRADE (line 21) | pub const MODULEUPGRADE: &str = concatcp!(SECURE_DIR, "/modules_update");
constant DATABIN (line 22) | pub const DATABIN: &str = concatcp!(SECURE_DIR, "/magisk");
constant MAGISKDB (line 23) | pub const MAGISKDB: &str = concatcp!(SECURE_DIR, "/magisk.db");
constant INTERNAL_DIR (line 26) | pub const INTERNAL_DIR: &str = ".magisk";
constant MAIN_CONFIG (line 27) | pub const MAIN_CONFIG: &str = concatcp!(INTERNAL_DIR, "/config");
constant PREINITMIRR (line 28) | pub const PREINITMIRR: &str = concatcp!(INTERNAL_DIR, "/preinit");
constant MODULEMNT (line 29) | pub const MODULEMNT: &str = concatcp!(INTERNAL_DIR, "/modules");
constant WORKERDIR (line 30) | pub const WORKERDIR: &str = concatcp!(INTERNAL_DIR, "/worker");
constant BBPATH (line 31) | pub const BBPATH: &str = concatcp!(INTERNAL_DIR, "/busybox");
constant DEVICEDIR (line 32) | pub const DEVICEDIR: &str = concatcp!(INTERNAL_DIR, "/device");
constant MAIN_SOCKET (line 33) | pub const MAIN_SOCKET: &str = concatcp!(DEVICEDIR, "/socket");
constant PREINITDEV (line 34) | pub const PREINITDEV: &str = concatcp!(DEVICEDIR, "/preinit");
constant LOG_PIPE (line 35) | pub const LOG_PIPE: &str = concatcp!(DEVICEDIR, "/log");
constant ROOTOVL (line 36) | pub const ROOTOVL: &str = concatcp!(INTERNAL_DIR, "/rootdir");
constant ROOTMNT (line 37) | pub const ROOTMNT: &str = concatcp!(ROOTOVL, "/.mount_list");
constant SELINUXMOCK (line 38) | pub const SELINUXMOCK: &str = concatcp!(INTERNAL_DIR, "/selinux");
constant SEPOL_PROC_DOMAIN (line 41) | pub const SEPOL_PROC_DOMAIN: &str = "magisk";
constant MAGISK_PROC_CON (line 42) | pub const MAGISK_PROC_CON: &str = concatcp!("u:r:", SEPOL_PROC_DOMAIN, "...
constant SEPOL_FILE_TYPE (line 44) | pub const SEPOL_FILE_TYPE: &str = "magisk_file";
constant MAGISK_FILE_CON (line 45) | pub const MAGISK_FILE_CON: &str = concatcp!("u:object_r:", SEPOL_FILE_TY...
constant SEPOL_LOG_TYPE (line 47) | pub const SEPOL_LOG_TYPE: &str = "magisk_log_file";
constant MAGISK_LOG_CON (line 48) | pub const MAGISK_LOG_CON: &str = concatcp!("u:object_r:", SEPOL_LOG_TYPE...
FILE: native/src/init/build.rs
function main (line 6) | fn main() {
FILE: native/src/init/getinfo.cpp
function string (line 18) | static string extract_quoted_str_until(chars<escapes...>, chars<breaks...>,
function kv_pairs (line 43) | static kv_pairs parse_impl(chars<padding...>, string_view str) {
function kv_pairs (line 62) | static kv_pairs parse_cmdline(string_view str) {
function kv_pairs (line 65) | static kv_pairs parse_bootconfig(string_view str) {
function kv_pairs (line 68) | static kv_pairs parse_partition_map(std::string_view str) {
function check_key_combo (line 74) | static bool check_key_combo() {
FILE: native/src/init/getinfo.rs
method print (line 6) | pub(crate) fn print(&self) {
method check_two_stage (line 43) | pub(crate) fn check_two_stage(&self) -> bool {
FILE: native/src/init/init.hpp
function Utf8CStr (line 24) | static inline Utf8CStr split_plat_cil() {
function Utf8CStr (line 28) | static inline Utf8CStr preload_lib() {
function Utf8CStr (line 32) | static inline Utf8CStr preload_policy() {
function Utf8CStr (line 36) | static inline Utf8CStr preload_ack() {
FILE: native/src/init/init.rs
method new (line 11) | fn new(argv: *mut *mut c_char) -> Self {
method first_stage (line 33) | fn first_stage(&self) {
method second_stage (line 47) | fn second_stage(&mut self) {
method legacy_system_as_root (line 73) | fn legacy_system_as_root(&mut self) {
method rootfs (line 84) | fn rootfs(&mut self) {
method recovery_or_charger (line 91) | fn recovery_or_charger(&self) {
method restore_ramdisk_init (line 97) | fn restore_ramdisk_init(&self) {
method start (line 114) | fn start(&mut self) -> LoggedResult<()> {
function main (line 174) | pub unsafe extern "C" fn main(
FILE: native/src/init/lib.rs
type KeyValue (line 22) | struct KeyValue {
type BootConfig (line 27) | struct BootConfig {
type MagiskInit (line 41) | struct MagiskInit {
type Utf8CStrRef (line 53) | type Utf8CStrRef<'a> = base::Utf8CStrRef<'a>;
function magisk_proxy_main (line 55) | unsafe fn magisk_proxy_main(argc: i32, argv: *mut *mut c_char) -> i32;
function backup_init (line 56) | fn backup_init() -> Utf8CStrRef<'static>;
function split_plat_cil (line 59) | fn split_plat_cil() -> Utf8CStrRef<'static>;
function preload_lib (line 60) | fn preload_lib() -> Utf8CStrRef<'static>;
function preload_policy (line 61) | fn preload_policy() -> Utf8CStrRef<'static>;
function preload_ack (line 62) | fn preload_ack() -> Utf8CStrRef<'static>;
function setup_klog (line 67) | fn setup_klog();
function inject_magisk_rc (line 68) | fn inject_magisk_rc(fd: i32, tmp_dir: Utf8CStrRef);
function switch_root (line 69) | fn switch_root(path: Utf8CStrRef);
function is_device_mounted (line 70) | fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool;
function print (line 75) | fn print(self: &BootConfig);
function init (line 78) | fn init(self: &mut BootConfig);
function set (line 80) | fn set(self: &mut BootConfig, config: &kv_pairs);
function parse_config_file (line 86) | fn parse_config_file(self: &mut MagiskInit);
function mount_overlay (line 87) | fn mount_overlay(self: &mut MagiskInit, dest: Utf8CStrRef);
function handle_sepolicy (line 88) | fn handle_sepolicy(self: &mut MagiskInit);
function restore_overlay_contexts (line 89) | fn restore_overlay_contexts(self: &MagiskInit);
function mount_system_root (line 93) | fn mount_system_root(self: &mut MagiskInit) -> bool;
function patch_rw_root (line 94) | fn patch_rw_root(self: &mut MagiskInit);
function patch_ro_root (line 95) | fn patch_ro_root(self: &mut MagiskInit);
function setup_tmp (line 98) | unsafe fn setup_tmp(self: &mut MagiskInit, path: *const c_char);
function collect_devices (line 99) | fn collect_devices(self: &MagiskInit);
function mount_preinit_dir (line 100) | fn mount_preinit_dir(self: &mut MagiskInit);
function find_block (line 101) | unsafe fn find_block(self: &MagiskInit, partname: *const c_char) -> u64;
function patch_fissiond (line 102) | unsafe fn patch_fissiond(self: &mut MagiskInit, tmp_path: *const c_char);
FILE: native/src/init/logging.rs
function setup_klog (line 15) | pub fn setup_klog() {
FILE: native/src/init/mount.cpp
type devinfo (line 13) | struct devinfo {
function parse_device (line 28) | static void parse_device(devinfo *dev, const char *uevent) {
FILE: native/src/init/mount.rs
function switch_root (line 19) | pub(crate) fn switch_root(path: &Utf8CStr) {
function is_device_mounted (line 56) | pub(crate) fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -...
constant RAMFS_MAGIC (line 66) | const RAMFS_MAGIC: u32 = 0x858458f6;
function is_rootfs (line 68) | pub(crate) fn is_rootfs() -> bool {
method prepare_data (line 77) | pub(crate) fn prepare_data(&self) {
method exec_init (line 95) | pub(crate) fn exec_init(&mut self) {
FILE: native/src/init/preload.c
function preload_init (line 7) | __attribute__((constructor))
function security_load_policy (line 14) | int security_load_policy(void *data, size_t len) {
FILE: native/src/init/rootdir.cpp
function unxz (line 18) | static bool unxz(int fd, rust::Slice<const uint8_t> bytes) {
function patch_rc_scripts (line 44) | static bool patch_rc_scripts(const char *src_path, const char *tmp_path,...
function load_overlay_rc (line 177) | static void load_overlay_rc(const char *overlay) {
function recreate_sbin (line 205) | static void recreate_sbin(const char *mirror, bool use_bind_mount) {
function extract_files (line 234) | static void extract_files(bool sbin) {
function magisk_proxy_main (line 377) | int magisk_proxy_main(int, char *argv[]) {
function unxz_init (line 403) | static void unxz_init(const char *init_xz, const char *init) {
function Utf8CStr (line 412) | Utf8CStr backup_init() {
FILE: native/src/init/rootdir.rs
function inject_magisk_rc (line 13) | pub fn inject_magisk_rc(fd: RawFd, tmp_dir: &Utf8CStr) {
type OverlayAttr (line 40) | pub struct OverlayAttr(Utf8CString, Utf8CString);
method parse_config_file (line 43) | pub(crate) fn parse_config_file(&mut self) {
method mount_impl (line 56) | fn mount_impl(
method mount_overlay (line 91) | pub(crate) fn mount_overlay(&mut self, dest: &Utf8CStr) {
method restore_overlay_contexts (line 100) | pub(crate) fn restore_overlay_contexts(&self) {
FILE: native/src/init/selinux.rs
constant MOCK_VERSION (line 15) | const MOCK_VERSION: &Utf8CStr = cstr!(concatcp!(SELINUXMOCK, "/version"));
constant MOCK_LOAD (line 16) | const MOCK_LOAD: &Utf8CStr = cstr!(concatcp!(SELINUXMOCK, "/load"));
constant MOCK_ENFORCE (line 17) | const MOCK_ENFORCE: &Utf8CStr = cstr!(concatcp!(SELINUXMOCK, "/enforce"));
constant MOCK_REQPROT (line 18) | const MOCK_REQPROT: &Utf8CStr = cstr!(concatcp!(SELINUXMOCK, "/checkreqp...
constant SELINUX_MNT (line 20) | const SELINUX_MNT: &str = "/sys/fs/selinux";
constant SELINUX_ENFORCE (line 21) | const SELINUX_ENFORCE: &Utf8CStr = cstr!(concatcp!(SELINUX_MNT, "/enforc...
constant SELINUX_LOAD (line 22) | const SELINUX_LOAD: &Utf8CStr = cstr!(concatcp!(SELINUX_MNT, "/load"));
constant SELINUX_REQPROT (line 23) | const SELINUX_REQPROT: &Utf8CStr = cstr!(concatcp!(SELINUX_MNT, "/checkr...
type SePatchStrategy (line 25) | enum SePatchStrategy {
function mock_fifo (line 50) | fn mock_fifo(target: &Utf8CStr, mock: &Utf8CStr) -> LoggedResult<()> {
function mock_file (line 56) | fn mock_file(target: &Utf8CStr, mock: &Utf8CStr) -> LoggedResult<()> {
method handle_sepolicy (line 63) | pub(crate) fn handle_sepolicy(&mut self) {
method cleanup_and_load (line 67) | fn cleanup_and_load(&self, rules: &str) {
method handle_sepolicy_impl (line 89) | fn handle_sepolicy_impl(&mut self) -> LoggedResult<()> {
FILE: native/src/init/twostage.rs
function hexpatch_init_for_second_stage (line 6) | pub(crate) fn hexpatch_init_for_second_stage(writable: bool) {
method hijack_init_with_switch_root (line 45) | pub(crate) fn hijack_init_with_switch_root(&self) {
FILE: native/src/sepolicy/api.cpp
function as_str (line 11) | std::string as_str(const Arg &arg) {
function print_rule (line 21) | static void print_rule(const char *action, Args ...args) {
function expand (line 32) | static inline void expand(F &&f, T &&...args) {
function expand (line 37) | static inline void expand(Str s, T &&...args) {
function expand (line 42) | static inline void expand(const StrVec &vec, T &&...args) {
function expand (line 53) | static inline void expand(const Xperms &vec, T &&...args) {
FILE: native/src/sepolicy/build.rs
function main (line 6) | fn main() {
FILE: native/src/sepolicy/cli.rs
type Cli (line 13) | struct Cli {
function print_usage (line 42) | fn print_usage(cmd: &str) {
function main (line 72) | pub unsafe extern "C" fn main(
FILE: native/src/sepolicy/lib.rs
type Xperm (line 16) | struct Xperm {
type SePolicy (line 22) | struct SePolicy {
method xperm_to_string (line 88) | fn xperm_to_string(perm: &ffi::Xperm) -> String {
type Utf8CStrRef (line 32) | type Utf8CStrRef<'a> = base::Utf8CStrRef<'a>;
function allow (line 36) | fn allow(self: &mut SePolicy, s: Vec<&str>, t: Vec<&str>, c: Vec<&str>, ...
function deny (line 37) | fn deny(self: &mut SePolicy, s: Vec<&str>, t: Vec<&str>, c: Vec<&str>, p...
function auditallow (line 38) | fn auditallow(self: &mut SePolicy, s: Vec<&str>, t: Vec<&str>, c: Vec<&s...
function dontaudit (line 39) | fn dontaudit(self: &mut SePolicy, s: Vec<&str>, t: Vec<&str>, c: Vec<&st...
function allowxperm (line 40) | fn allowxperm(self: &mut SePolicy, s: Vec<&str>, t: Vec<&str>, c: Vec<&s...
function auditallowxperm (line 41) | fn auditallowxperm(
function dontauditxperm (line 48) | fn dontauditxperm(
function permissive (line 55) | fn permissive(self: &mut SePolicy, t: Vec<&str>);
function enforce (line 56) | fn enforce(self: &mut SePolicy, t: Vec<&str>);
function typeattribute (line 57) | fn typeattribute(self: &mut SePolicy, t: Vec<&str>, a: Vec<&str>);
function type_ (line 59) | fn type_(self: &mut SePolicy, t: &str, a: Vec<&str>);
function attribute (line 60) | fn attribute(self: &mut SePolicy, t: &str);
function type_transition (line 61) | fn type_transition(self: &mut SePolicy, s: &str, t: &str, c: &str, d: &s...
function type_change (line 62) | fn type_change(self: &mut SePolicy, s: &str, t: &str, c: &str, d: &str);
function type_member (line 63) | fn type_member(self: &mut SePolicy, s: &str, t: &str, c: &str, d: &str);
function genfscon (line 64) | fn genfscon(self: &mut SePolicy, s: &str, t: &str, c: &str);
function strip_dontaudit (line 66) | fn strip_dontaudit(self: &mut SePolicy);
function print_rules (line 68) | fn print_rules(self: &SePolicy);
function to_file (line 69) | fn to_file(self: &SePolicy, file: Utf8CStrRef) -> bool;
function from_file (line 72) | fn from_file(file: Utf8CStrRef) -> SePolicy;
function from_split (line 74) | fn from_split() -> SePolicy;
function compile_split (line 76) | fn compile_split() -> SePolicy;
function from_data (line 78) | fn from_data(data: &[u8]) -> SePolicy;
function xperm_to_string (line 83) | fn xperm_to_string(perm: &Xperm) -> String;
FILE: native/src/sepolicy/policy.hpp
type Xperm (line 13) | struct Xperm
class sepol_impl (line 15) | class sepol_impl {
method sepol_impl (line 42) | sepol_impl(policydb *db) : db(db) {}
FILE: native/src/sepolicy/policydb.cpp
function cmp_sha256 (line 15) | static bool cmp_sha256(const char *a, const char *b) {
function check_precompiled (line 36) | static bool check_precompiled(const char *precompiled) {
function load_cil (line 76) | static void load_cil(struct cil_db *db, const char *file) {
function SePolicy (line 82) | SePolicy SePolicy::from_data(rust::Slice<const uint8_t> data) noexcept {
function SePolicy (line 101) | SePolicy SePolicy::from_file(::Utf8CStr file) noexcept {
function SePolicy (line 120) | SePolicy SePolicy::compile_split() noexcept {
function SePolicy (line 217) | SePolicy SePolicy::from_split() noexcept {
function vec_write (line 233) | static int vec_write(void *v, const char *buf, int len) {
type stat (line 261) | struct stat
FILE: native/src/sepolicy/rules.rs
method magisk_rules (line 51) | pub fn magisk_rules(&mut self) {
FILE: native/src/sepolicy/sepolicy.cpp
type avtab_key (line 13) | struct avtab_key
function auto_cast (line 37) | static auto_cast_wrapper<T> auto_cast(T *p) {
function copy_str (line 42) | static size_t copy_str(std::array<char, T> &dest, rust::Str src) {
function str_eq (line 58) | static bool str_eq(string_view a, rust::Str b) {
function hashtab_find (line 62) | static auto hashtab_find(hashtab_t h, Str key) {
function list_for_each (line 69) | static void list_for_each(Node *node_ptr, const Func &fn) {
function Node (line 79) | static Node *list_find(Node *node_ptr, const Func &fn) {
function hash_for_each (line 89) | static void hash_for_each(Node **node_ptr, int n_slot, const Func &fn) {
function hashtab_for_each (line 96) | static void hashtab_for_each(hashtab_t htab, const Func &fn) {
function avtab_for_each (line 101) | static void avtab_for_each(avtab_t *avtab, const Func &fn) {
function for_each_attr (line 106) | static void for_each_attr(hashtab_t htab, const Func &fn) {
function avtab_remove_node (line 114) | static int avtab_remove_node(avtab_t *h, avtab_ptr_t node) {
function is_redundant (line 142) | static bool is_redundant(avtab_ptr_t node) {
function avtab_ptr_t (line 153) | avtab_ptr_t sepol_impl::find_avtab_node(avtab_key_t *key, avtab_extended...
function avtab_ptr_t (line 176) | avtab_ptr_t sepol_impl::insert_avtab_node(avtab_key_t *key) {
function avtab_ptr_t (line 184) | avtab_ptr_t sepol_impl::get_avtab_node(avtab_key_t *key, avtab_extended_...
FILE: native/src/sepolicy/statement.rs
type Token (line 11) | pub enum Token<'a> {
type Tokens (line 38) | type Tokens<'a> = Peekable<IntoIter<Token<'a>>>;
type ParseResult (line 39) | type ParseResult<'a, T> = Result<T, ParseError<'a>>;
type ParseError (line 41) | enum ParseError<'a> {
function parse_id (line 62) | fn parse_id<'a>(tokens: &mut Tokens<'a>) -> ParseResult<'a, &'a str> {
function parse_term (line 73) | fn parse_term<'a>(tokens: &mut Tokens<'a>) -> ParseResult<'a, Vec<&'a st...
function parse_sterm (line 98) | fn parse_sterm<'a>(tokens: &mut Tokens<'a>) -> ParseResult<'a, Vec<&'a s...
function parse_xperm (line 124) | fn parse_xperm<'a>(tokens: &mut Tokens<'a>) -> ParseResult<'a, Xperm> {
function parse_xperms (line 153) | fn parse_xperms<'a>(tokens: &mut Tokens<'a>) -> ParseResult<'a, Vec<Xper...
function match_string (line 205) | fn match_string<'a>(tokens: &mut Tokens<'a>, pattern: &str) -> ParseResu...
function extract_token (line 214) | fn extract_token<'a>(s: &'a str, tokens: &mut Vec<Token<'a>>) {
function tokenize_statement (line 267) | fn tokenize_statement(statement: &str) -> Vec<Token<'_>> {
method load_rules (line 276) | pub fn load_rules(&mut self, rules: &str) {
method load_rule_file (line 281) | pub fn load_rule_file(&mut self, filename: &Utf8CStr) {
method load_rules_from_reader (line 291) | fn load_rules_from_reader<T: BufRead>(&mut self, reader: &mut T) {
method parse_statement (line 298) | fn parse_statement(&mut self, statement: &str) {
method exec_statement (line 329) | fn exec_statement<'a>(&mut self, tokens: &mut Tokens<'a>) -> ParseResult...
method fmt (line 494) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
method fmt (line 525) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
function format_statement_help (line 556) | pub(crate) fn format_statement_help(f: &mut dyn Write) -> std::fmt::Resu...
FILE: tools/elf-cleaner/src/main.rs
constant DT_AARCH64_BTI_PLT (line 8) | const DT_AARCH64_BTI_PLT: u32 = elf::DT_LOPROC + 1;
constant DT_AARCH64_PAC_PLT (line 9) | const DT_AARCH64_PAC_PLT: u32 = elf::DT_LOPROC + 3;
constant DT_AARCH64_VARIANT_PCS (line 10) | const DT_AARCH64_VARIANT_PCS: u32 = elf::DT_LOPROC + 5;
constant SUPPORTED_DT_FLAGS (line 12) | const SUPPORTED_DT_FLAGS: u32 = elf::DF_1_NOW | elf::DF_1_GLOBAL;
function print_remove_dynamic (line 14) | fn print_remove_dynamic(name: &str, path: &str) {
function process_elf (line 18) | fn process_elf(path: &str) -> anyhow::Result<()> {
function main (line 83) | fn main() -> anyhow::Result<()> {
FILE: tools/rustup-wrapper/src/main.rs
function main (line 20) | fn main() -> std::io::Result<()> {
Condensed preview — 740 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,806K chars).
[
{
"path": ".gitattributes",
"chars": 562,
"preview": "# Set the default behavior, in case people don't have core.autocrlf set.\n* text eol=lf\n\n# Explicitly declare text files "
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 1380,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"\"\nlabels: \"\"\nassignees: \"\"\n---\n\n<!--\n\n## READ BEF"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 182,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: XDA Community Support\n url: https://forum.xda-developers.com/f/m"
},
{
"path": ".github/actions/setup/action.yml",
"chars": 3218,
"preview": "name: Magisk Setup\ndescription: Set up the build environment for Magisk\ninputs:\n is-asset-build:\n required: false\n "
},
{
"path": ".github/actions/setup/sccache.sh",
"chars": 795,
"preview": "#!/usr/bin/env bash\n\n# Get latest sccache version\nget_sccache_ver() {\n curl -sL 'https://api.github.com/repos/mozilla/s"
},
{
"path": ".github/ci.prop",
"chars": 18,
"preview": "abiList=arm64-v8a\n"
},
{
"path": ".github/kvm.sh",
"chars": 199,
"preview": "#!/usr/bin/env bash\n\necho 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rul"
},
{
"path": ".github/workflows/build.yml",
"chars": 4934,
"preview": "name: Magisk Build\n\non:\n push:\n branches: [master]\n paths:\n - \"app/**\"\n - \"native/**\"\n - \"build.py"
},
{
"path": ".gitignore",
"chars": 170,
"preview": "out\n*.zip\n*.jks\n*.apk\n*.log\n/config.prop\n/notes.md\n\n# Built binaries\nnative/out\n\n# Android Studio\n*.iml\n.idea\n.cursor\nra"
},
{
"path": ".gitmodules",
"chars": 728,
"preview": "[submodule \"selinux\"]\n\tpath = native/src/external/selinux\n\turl = https://github.com/topjohnwu/selinux.git\n[submodule \"lz"
},
{
"path": "LICENSE",
"chars": 35141,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "README.MD",
"chars": 2546,
"preview": "\n\n[\n kotlin(\"plugin.parcelize\")\n alias(libs.plugins.legacy.kapt)\n alias"
},
{
"path": "app/apk/proguard-rules.pro",
"chars": 74,
"preview": "# Excessive obfuscation\n-flattenpackagehierarchy\n-allowaccessmodification\n"
},
{
"path": "app/apk/src/main/AndroidManifest.xml",
"chars": 1303,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:to"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/arch/AsyncLoadViewModel.kt",
"chars": 572,
"preview": "package com.topjohnwu.magisk.arch\n\nimport androidx.annotation.MainThread\nimport androidx.lifecycle.viewModelScope\nimport"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/arch/BaseFragment.kt",
"chars": 3036,
"preview": "package com.topjohnwu.magisk.arch\n\nimport android.os.Bundle\nimport android.view.KeyEvent\nimport android.view.LayoutInfla"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/arch/BaseViewModel.kt",
"chars": 2663,
"preview": "package com.topjohnwu.magisk.arch\n\nimport android.Manifest.permission.POST_NOTIFICATIONS\nimport android.Manifest.permiss"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/arch/NavigationActivity.kt",
"chars": 1634,
"preview": "package com.topjohnwu.magisk.arch\n\nimport android.content.ContentResolver\nimport android.view.KeyEvent\nimport androidx.d"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/arch/UIActivity.kt",
"chars": 5110,
"preview": "package com.topjohnwu.magisk.arch\n\nimport android.content.Context\nimport android.content.res.Resources\nimport android.gr"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/arch/ViewEvent.kt",
"chars": 540,
"preview": "package com.topjohnwu.magisk.arch\n\nimport android.content.Context\n\n/**\n * Class for passing events from ViewModels to Ac"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/arch/ViewModelHolder.kt",
"chars": 1918,
"preview": "package com.topjohnwu.magisk.arch\n\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.ViewModel\nimport a"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt",
"chars": 10465,
"preview": "package com.topjohnwu.magisk.databinding\n\nimport android.animation.ValueAnimator\nimport android.content.res.ColorStateLi"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/databinding/DiffObservableList.kt",
"chars": 4933,
"preview": "package com.topjohnwu.magisk.databinding\n\nimport androidx.annotation.MainThread\nimport androidx.annotation.WorkerThread\n"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/databinding/MergeObservableList.kt",
"chars": 4844,
"preview": "package com.topjohnwu.magisk.databinding\n\nimport androidx.databinding.ListChangeRegistry\nimport androidx.databinding.Obs"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/databinding/ObservableHost.kt",
"chars": 3099,
"preview": "package com.topjohnwu.magisk.databinding\n\nimport androidx.databinding.Observable\nimport androidx.databinding.PropertyCha"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/databinding/RecyclerViewItems.kt",
"chars": 898,
"preview": "package com.topjohnwu.magisk.databinding\n\nimport androidx.databinding.PropertyChangeRegistry\nimport androidx.databinding"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/databinding/RvItemAdapter.kt",
"chars": 4122,
"preview": "package com.topjohnwu.magisk.databinding\n\nimport android.annotation.SuppressLint\nimport android.util.SparseArray\nimport "
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/DarkThemeDialog.kt",
"chars": 1623,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport android.app.Activity\nimport androidx.appcompat.app.AppCompatDelegate\nimport "
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/EnvFixDialog.kt",
"chars": 2561,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport android.widget.Toast\nimport androidx.core.os.postDelayed\nimport androidx.lif"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/LocalModuleInstallDialog.kt",
"chars": 1143,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport android.net.Uri\nimport com.topjohnwu.magisk.MainDirections\nimport com.topjoh"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/ManagerInstallDialog.kt",
"chars": 1073,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport com.topjohnwu.magisk.core.AppContext\nimport com.topjohnwu.magisk.core.Info\ni"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/MarkDownDialog.kt",
"chars": 1336,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport android.view.LayoutInflater\nimport android.widget.TextView\nimport androidx.a"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt",
"chars": 2016,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport android.content.Context\nimport com.topjohnwu.magisk.core.R\nimport com.topjoh"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/SecondSlotWarningDialog.kt",
"chars": 569,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport com.topjohnwu.magisk.core.R\nimport com.topjohnwu.magisk.events.DialogBuilder"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/SuperuserRevokeDialog.kt",
"chars": 754,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport com.topjohnwu.magisk.core.R\nimport com.topjohnwu.magisk.events.DialogBuilder"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/dialog/UninstallDialog.kt",
"chars": 1937,
"preview": "package com.topjohnwu.magisk.dialog\n\nimport android.app.ProgressDialog\nimport android.widget.Toast\nimport androidx.lifec"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/events/ViewEvents.kt",
"chars": 3566,
"preview": "package com.topjohnwu.magisk.events\n\nimport android.content.Context\nimport android.view.View\nimport androidx.annotation."
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt",
"chars": 10364,
"preview": "package com.topjohnwu.magisk.ui\n\nimport android.Manifest\nimport android.Manifest.permission.REQUEST_INSTALL_PACKAGES\nimp"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/AppProcessInfo.kt",
"chars": 4334,
"preview": "package com.topjohnwu.magisk.ui.deny\n\nimport android.annotation.SuppressLint\nimport android.content.pm.ApplicationInfo\ni"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListFragment.kt",
"chars": 3513,
"preview": "package com.topjohnwu.magisk.ui.deny\n\nimport android.os.Bundle\nimport android.view.Menu\nimport android.view.MenuInflater"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListRvItem.kt",
"chars": 4243,
"preview": "package com.topjohnwu.magisk.ui.deny\n\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.databinding"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/deny/DenyListViewModel.kt",
"chars": 2945,
"preview": "package com.topjohnwu.magisk.ui.deny\n\nimport android.annotation.SuppressLint\nimport android.content.pm.PackageManager.MA"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/flash/ConsoleItem.kt",
"chars": 1240,
"preview": "package com.topjohnwu.magisk.ui.flash\n\nimport android.view.View\nimport android.widget.TextView\nimport androidx.core.view"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt",
"chars": 5153,
"preview": "package com.topjohnwu.magisk.ui.flash\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport andr"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt",
"chars": 4163,
"preview": "package com.topjohnwu.magisk.ui.flash\n\nimport android.view.MenuItem\nimport androidx.databinding.Bindable\nimport androidx"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/home/DeveloperItem.kt",
"chars": 3664,
"preview": "package com.topjohnwu.magisk.ui.home\n\nimport com.topjohnwu.magisk.R\nimport com.topjohnwu.magisk.core.Const\nimport com.to"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt",
"chars": 2933,
"preview": "package com.topjohnwu.magisk.ui.home\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.Me"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt",
"chars": 5765,
"preview": "package com.topjohnwu.magisk.ui.home\n\nimport android.content.ActivityNotFoundException\nimport android.content.Context\nim"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/home/RebootMenu.kt",
"chars": 2062,
"preview": "package com.topjohnwu.magisk.ui.home\n\nimport android.app.Activity\nimport android.os.Build\nimport android.os.PowerManager"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt",
"chars": 578,
"preview": "package com.topjohnwu.magisk.ui.install\n\nimport com.topjohnwu.magisk.R\nimport com.topjohnwu.magisk.arch.BaseFragment\nimp"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt",
"chars": 4749,
"preview": "package com.topjohnwu.magisk.ui.install\n\nimport android.net.Uri\nimport android.os.Bundle\nimport android.os.Parcelable\nim"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.kt",
"chars": 3375,
"preview": "package com.topjohnwu.magisk.ui.log\n\nimport android.os.Bundle\nimport android.view.Menu\nimport android.view.MenuInflater\n"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/log/LogRvItem.kt",
"chars": 1021,
"preview": "package com.topjohnwu.magisk.ui.log\n\nimport androidx.databinding.ViewDataBinding\nimport androidx.recyclerview.widget.Rec"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt",
"chars": 4278,
"preview": "package com.topjohnwu.magisk.ui.log\n\nimport android.system.Os\nimport androidx.databinding.Bindable\nimport androidx.lifec"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/log/SuLogRvItem.kt",
"chars": 1945,
"preview": "package com.topjohnwu.magisk.ui.log\n\nimport androidx.databinding.Bindable\nimport com.topjohnwu.magisk.BR\nimport com.topj"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ActionFragment.kt",
"chars": 3765,
"preview": "package com.topjohnwu.magisk.ui.module\n\nimport android.annotation.SuppressLint\nimport android.content.pm.ActivityInfo\nim"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ActionViewModel.kt",
"chars": 2841,
"preview": "package com.topjohnwu.magisk.ui.module\n\nimport android.view.MenuItem\nimport androidx.databinding.ObservableArrayList\nimp"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt",
"chars": 1636,
"preview": "package com.topjohnwu.magisk.ui.module\n\nimport android.os.Bundle\nimport android.view.View\nimport com.topjohnwu.magisk.R\n"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ModuleRvItem.kt",
"chars": 2501,
"preview": "package com.topjohnwu.magisk.ui.module\n\nimport androidx.databinding.Bindable\nimport com.topjohnwu.magisk.BR\nimport com.t"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt",
"chars": 3506,
"preview": "package com.topjohnwu.magisk.ui.module\n\nimport android.net.Uri\nimport androidx.databinding.Bindable\nimport androidx.life"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/BaseSettingsItem.kt",
"chars": 5135,
"preview": "package com.topjohnwu.magisk.ui.settings\n\nimport android.content.Context\nimport android.content.res.Resources\nimport and"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt",
"chars": 1274,
"preview": "package com.topjohnwu.magisk.ui.settings\n\nimport android.os.Bundle\nimport android.view.View\nimport com.topjohnwu.magisk."
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt",
"chars": 11740,
"preview": "package com.topjohnwu.magisk.ui.settings\n\nimport android.content.Context\nimport android.content.res.Resources\nimport and"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt",
"chars": 4932,
"preview": "package com.topjohnwu.magisk.ui.settings\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.net.U"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/PolicyRvItem.kt",
"chars": 2937,
"preview": "package com.topjohnwu.magisk.ui.superuser\n\nimport android.graphics.drawable.Drawable\nimport androidx.databinding.Bindabl"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.kt",
"chars": 1190,
"preview": "package com.topjohnwu.magisk.ui.superuser\n\nimport android.os.Bundle\nimport android.view.View\nimport com.topjohnwu.magisk"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt",
"chars": 6388,
"preview": "package com.topjohnwu.magisk.ui.superuser\n\nimport android.annotation.SuppressLint\nimport android.content.pm.PackageManag"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt",
"chars": 2419,
"preview": "package com.topjohnwu.magisk.ui.surequest\n\nimport android.content.Intent\nimport android.content.pm.ActivityInfo\nimport a"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestViewModel.kt",
"chars": 6973,
"preview": "package com.topjohnwu.magisk.ui.surequest\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport a"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/theme/Theme.kt",
"chars": 1205,
"preview": "package com.topjohnwu.magisk.ui.theme\n\nimport com.topjohnwu.magisk.R\nimport com.topjohnwu.magisk.core.Config\n\nenum class"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/theme/ThemeFragment.kt",
"chars": 2302,
"preview": "package com.topjohnwu.magisk.ui.theme\n\nimport android.os.Bundle\nimport android.view.ContextThemeWrapper\nimport android.v"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/ui/theme/ThemeViewModel.kt",
"chars": 733,
"preview": "package com.topjohnwu.magisk.ui.theme\n\nimport com.topjohnwu.magisk.arch.BaseViewModel\nimport com.topjohnwu.magisk.core.C"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/utils/AccessibilityUtils.kt",
"chars": 554,
"preview": "package com.topjohnwu.magisk.utils\n\nimport android.content.ContentResolver\nimport android.provider.Settings\n\nclass Acces"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/utils/MotionRevealHelper.kt",
"chars": 3209,
"preview": "package com.topjohnwu.magisk.utils\n\nimport android.animation.Animator\nimport android.animation.AnimatorSet\nimport androi"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/utils/TextHolder.kt",
"chars": 1320,
"preview": "package com.topjohnwu.magisk.utils\n\nimport android.content.res.Resources\n\nabstract class TextHolder {\n\n open val isEm"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/view/MagiskDialog.kt",
"chars": 8140,
"preview": "package com.topjohnwu.magisk.view\n\nimport android.app.Activity\nimport android.content.DialogInterface\nimport android.con"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/view/TappableHeadlineItem.kt",
"chars": 709,
"preview": "package com.topjohnwu.magisk.view\n\nimport com.topjohnwu.magisk.R\nimport com.topjohnwu.magisk.databinding.DiffItem\nimport"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/view/TextItem.kt",
"chars": 354,
"preview": "package com.topjohnwu.magisk.view\n\nimport com.topjohnwu.magisk.R\nimport com.topjohnwu.magisk.databinding.DiffItem\nimport"
},
{
"path": "app/apk/src/main/java/com/topjohnwu/magisk/widget/ConcealableBottomNavigationView.java",
"chars": 4282,
"preview": "package com.topjohnwu.magisk.widget;\n\nimport android.animation.Animator;\nimport android.animation.ObjectAnimator;\nimport"
},
{
"path": "app/apk/src/main/res/anim/fragment_enter.xml",
"chars": 510,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <alpha\n "
},
{
"path": "app/apk/src/main/res/anim/fragment_enter_pop.xml",
"chars": 510,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <alpha\n "
},
{
"path": "app/apk/src/main/res/anim/fragment_exit.xml",
"chars": 510,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <alpha\n "
},
{
"path": "app/apk/src/main/res/anim/fragment_exit_pop.xml",
"chars": 510,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <alpha\n "
},
{
"path": "app/apk/src/main/res/color/color_card_background_color_selector.xml",
"chars": 271,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/color/color_error_transient.xml",
"chars": 235,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/color/color_menu_tint.xml",
"chars": 327,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/color/color_on_primary_transient.xml",
"chars": 239,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/color/color_primary_error_transient.xml",
"chars": 308,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/color/color_primary_transient.xml",
"chars": 237,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/color/color_state_primary_transient.xml",
"chars": 391,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/color/color_text_transient.xml",
"chars": 239,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/apk/src/main/res/drawable/avd_bug_from_filled.xml",
"chars": 3490,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_bug_to_filled.xml",
"chars": 3800,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_circle_check_from_filled.xml",
"chars": 2272,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_circle_check_to_filled.xml",
"chars": 2474,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_home_from_filled.xml",
"chars": 1419,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_home_to_filled.xml",
"chars": 1480,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_module_from_filled.xml",
"chars": 5018,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_module_to_filled.xml",
"chars": 4912,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_settings_from_filled.xml",
"chars": 8520,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_settings_to_filled.xml",
"chars": 10609,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_superuser_from_filled.xml",
"chars": 1539,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/avd_superuser_to_filled.xml",
"chars": 1652,
"preview": "<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:aapt=\"http://schemas.android.com/a"
},
{
"path": "app/apk/src/main/res/drawable/bg_line_bottom_rounded.xml",
"chars": 351,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <item>"
},
{
"path": "app/apk/src/main/res/drawable/bg_line_top_rounded.xml",
"chars": 345,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <item>"
},
{
"path": "app/apk/src/main/res/drawable/bg_selection_circle_green.xml",
"chars": 243,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item>\n"
},
{
"path": "app/apk/src/main/res/drawable/ic_action_md2.xml",
"chars": 288,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#000000\" android:"
},
{
"path": "app/apk/src/main/res/drawable/ic_back_md2.xml",
"chars": 545,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_bug_filled_md2.xml",
"chars": 762,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_bug_md2.xml",
"chars": 690,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_bug_outlined_md2.xml",
"chars": 828,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_check_circle_checked_md2.xml",
"chars": 503,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_check_circle_md2.xml",
"chars": 805,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-selector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_check_circle_unchecked_md2.xml",
"chars": 495,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_check_md2.xml",
"chars": 452,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tool"
},
{
"path": "app/apk/src/main/res/drawable/ic_close_md2.xml",
"chars": 507,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tool"
},
{
"path": "app/apk/src/main/res/drawable/ic_day.xml",
"chars": 687,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_day_night.xml",
"chars": 971,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_delete_md2.xml",
"chars": 573,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_download_md2.xml",
"chars": 481,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tool"
},
{
"path": "app/apk/src/main/res/drawable/ic_folder_list.xml",
"chars": 446,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_forth_md2.xml",
"chars": 657,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_home_filled_md2.xml",
"chars": 425,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_home_md2.xml",
"chars": 693,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_home_outlined_md2.xml",
"chars": 484,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_install.xml",
"chars": 503,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_manager.xml",
"chars": 1408,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_module_filled_md2.xml",
"chars": 623,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_module_md2.xml",
"chars": 701,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_module_outlined_md2.xml",
"chars": 859,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_module_storage_md2.xml",
"chars": 943,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_night.xml",
"chars": 947,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_notifications_md2.xml",
"chars": 540,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_paint.xml",
"chars": 517,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_restart.xml",
"chars": 639,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_save_md2.xml",
"chars": 509,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_search_md2.xml",
"chars": 627,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:width=\"24dp\"\n android:height=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_settings_filled_md2.xml",
"chars": 1222,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_settings_md2.xml",
"chars": 709,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_settings_outlined_md2.xml",
"chars": 1548,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/drawable/ic_superuser_filled_md2.xml",
"chars": 349,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:height=\"24dp\"\n android:width=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_superuser_md2.xml",
"chars": 713,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_superuser_outlined_md2.xml",
"chars": 428,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:height=\"24dp\"\n android:width=\"24dp\"\n "
},
{
"path": "app/apk/src/main/res/drawable/ic_update_md2.xml",
"chars": 438,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "app/apk/src/main/res/layout/activity_main_md2.xml",
"chars": 2663,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/activity_request.xml",
"chars": 6729,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/dialog_magisk_base.xml",
"chars": 7882,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/dialog_settings_app_name.xml",
"chars": 2108,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/dialog_settings_download_path.xml",
"chars": 2185,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/dialog_settings_update_channel.xml",
"chars": 1792,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_action_md2.xml",
"chars": 2747,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_deny_md2.xml",
"chars": 2010,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_flash_md2.xml",
"chars": 2848,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_home_md2.xml",
"chars": 11666,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_install_md2.xml",
"chars": 11244,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_log_md2.xml",
"chars": 2274,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_module_md2.xml",
"chars": 2431,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_settings_md2.xml",
"chars": 1526,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_superuser_md2.xml",
"chars": 2020,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/fragment_theme_md2.xml",
"chars": 1407,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/include_home_magisk.xml",
"chars": 7725,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/include_home_manager.xml",
"chars": 8226,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/include_log_magisk.xml",
"chars": 2961,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/include_log_superuser.xml",
"chars": 2090,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_console_md2.xml",
"chars": 600,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tool"
},
{
"path": "app/apk/src/main/res/layout/item_developer.xml",
"chars": 1767,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_hide_md2.xml",
"chars": 5318,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_hide_process_md2.xml",
"chars": 2070,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_icon_link.xml",
"chars": 1191,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_list_single_line.xml",
"chars": 1079,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tool"
},
{
"path": "app/apk/src/main/res/layout/item_log_access_md2.xml",
"chars": 3205,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_log_textview.xml",
"chars": 543,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <data>\n\n"
},
{
"path": "app/apk/src/main/res/layout/item_log_track_md2.xml",
"chars": 2609,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_module_download.xml",
"chars": 917,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_module_md2.xml",
"chars": 11310,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_policy_md2.xml",
"chars": 9899,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_settings.xml",
"chars": 3519,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_settings_section.xml",
"chars": 1261,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tool"
},
{
"path": "app/apk/src/main/res/layout/item_spinner.xml",
"chars": 624,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:to"
},
{
"path": "app/apk/src/main/res/layout/item_tappable_headline.xml",
"chars": 2683,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_text.xml",
"chars": 628,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tool"
},
{
"path": "app/apk/src/main/res/layout/item_theme.xml",
"chars": 7550,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/apk/src/main/res/layout/item_theme_container.xml",
"chars": 345,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n styl"
},
{
"path": "app/apk/src/main/res/layout/markdown_window_md2.xml",
"chars": 705,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:"
},
{
"path": "app/apk/src/main/res/menu/menu_bottom_nav.xml",
"chars": 878,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools="
},
{
"path": "app/apk/src/main/res/menu/menu_deny_md2.xml",
"chars": 750,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app=\"h"
},
{
"path": "app/apk/src/main/res/menu/menu_flash.xml",
"chars": 342,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app=\"h"
},
{
"path": "app/apk/src/main/res/menu/menu_home_md2.xml",
"chars": 521,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app=\"h"
},
{
"path": "app/apk/src/main/res/menu/menu_log_md2.xml",
"chars": 523,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app=\"h"
},
{
"path": "app/apk/src/main/res/menu/menu_reboot.xml",
"chars": 943,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n <item\n "
},
{
"path": "app/apk/src/main/res/navigation/main.xml",
"chars": 6340,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<navigation xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:"
},
{
"path": "app/apk/src/main/res/values/attrs.xml",
"chars": 859,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!--region Deprecated-->\n <attr name=\"cardStyle\" format=\"refer"
},
{
"path": "app/apk/src/main/res/values/dimens.xml",
"chars": 447,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n <dimen name=\"margin_generic\">16dp</dimen>\n\n <dimen name=\"l_12"
},
{
"path": "app/apk/src/main/res/values/ids.xml",
"chars": 117,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <item name=\"recyclerScrollListener\" type=\"id\" />\n</resources>\n"
},
{
"path": "app/apk/src/main/res/values/styles_md2.xml",
"chars": 1041,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n <style name=\"Foundation\" parent=\"Theme.Foundation.Light\" />\n\n "
},
{
"path": "app/apk/src/main/res/values/styles_md2_appearance.xml",
"chars": 2180,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n <!--region Display-->\n <style name=\"AppearanceFoundation.Larg"
},
{
"path": "app/apk/src/main/res/values/styles_md2_impl.xml",
"chars": 5231,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n <style name=\"WidgetFoundation.Appbar\" parent=\"Widget.MaterialCom"
},
{
"path": "app/apk/src/main/res/values/styles_view_md2.xml",
"chars": 2124,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n <style name=\"W\" parent=\"android:Widget\" />\n\n <!--region Home-"
}
]
// ... and 540 more files (download for full content)
About this extraction
This page contains the full source code of the topjohnwu/Magisk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 740 files (3.4 MB), approximately 945.4k tokens, and a symbol index with 2130 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.