diff --git a/api b/api
index 453e947..4a1f140 160000
--- a/api
+++ b/api
@@ -1 +1 @@
-Subproject commit 453e94721a902acfa406d0c46682a4b1954d1af1
+Subproject commit 4a1f140b2e84459e75135f79c695ae00c4500674
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 21cc360..146e13d 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -22,8 +22,8 @@ android {
applicationId = "com.rosan.dhizuku"
minSdk = 21
targetSdk = 33
- versionCode = 2
- versionName = "1.0.3"
+ versionCode = 3
+ versionName = "2.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@@ -128,8 +128,12 @@ dependencies {
implementation(libs.accompanist.drawablepainter)
implementation(libs.accompanist.systemuicontroller)
+ implementation(libs.lsposed.hiddenapibypass)
+
implementation(libs.xxpermissions)
implementation(libs.rikka.shizuku.api)
implementation(libs.rikka.shizuku.provider)
+
+ implementation(libs.commons.cli)
}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index fac7f23..b1f61ff 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -69,7 +69,7 @@
-keep public class com.rosan.dhizuku.data.process.model.impl.** {
public static void main(java.lang.String[]);
}
-#-keep public class com.rosan.installer.data.process.model.impl.** extends com.rosan.installer.data.process.repo.ProcessRepo {
+#-keep public class com.rosan.installer.data.process.model.impl.** extends com.rosan.dhizuku.data.process.repo.ProcessRepo {
#public static void main(java.lang.String[]);
#}
#-keep public class com.rosan.installer.** extends android.app.Service
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7a7c49a..a4b6b27 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -64,11 +64,12 @@
+ android:directBootAware="true"
+ android:exported="false"
+ tools:ignore="UnusedAttribute">
diff --git a/app/src/main/aidl/android/content/IIntentReceiver.aidl b/app/src/main/aidl/android/content/IIntentReceiver.aidl
deleted file mode 100644
index 5d9895e..0000000
--- a/app/src/main/aidl/android/content/IIntentReceiver.aidl
+++ /dev/null
@@ -1,9 +0,0 @@
-package android.content;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-oneway interface IIntentReceiver {
- void performReceive(in Intent intent, int resultCode, String data,
- in Bundle extras, boolean ordered, boolean sticky, int sendingUser);
-}
diff --git a/app/src/main/aidl/android/content/IIntentSender.aidl b/app/src/main/aidl/android/content/IIntentSender.aidl
deleted file mode 100644
index 2736b61..0000000
--- a/app/src/main/aidl/android/content/IIntentSender.aidl
+++ /dev/null
@@ -1,10 +0,0 @@
-package android.content;
-
-import android.content.IIntentReceiver;
-import android.content.Intent;
-import android.os.Bundle;
-
-oneway interface IIntentSender {
- void send(int code, in Intent intent, String resolvedType, in IBinder whitelistToken,
- IIntentReceiver finishedReceiver, String requiredPermission, in Bundle options);
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/IOnChecksumsReadyListener.aidl b/app/src/main/aidl/android/content/pm/IOnChecksumsReadyListener.aidl
deleted file mode 100644
index 9963a87..0000000
--- a/app/src/main/aidl/android/content/pm/IOnChecksumsReadyListener.aidl
+++ /dev/null
@@ -1,6 +0,0 @@
-package android.content.pm;
-import android.content.pm.ApkChecksum;
-
-oneway interface IOnChecksumsReadyListener {
- void onChecksumsReady(in List checksums);
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/IPackageDeleteObserver2.aidl b/app/src/main/aidl/android/content/pm/IPackageDeleteObserver2.aidl
deleted file mode 100644
index cc2406b..0000000
--- a/app/src/main/aidl/android/content/pm/IPackageDeleteObserver2.aidl
+++ /dev/null
@@ -1,7 +0,0 @@
-package android.content.pm;
-import android.content.Intent;
-
-oneway interface IPackageDeleteObserver2 {
- void onUserActionRequired(in Intent intent);
- void onPackageDeleted(String packageName, int returnCode, String msg);
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/IPackageInstallObserver2.aidl b/app/src/main/aidl/android/content/pm/IPackageInstallObserver2.aidl
deleted file mode 100644
index a1c9ec3..0000000
--- a/app/src/main/aidl/android/content/pm/IPackageInstallObserver2.aidl
+++ /dev/null
@@ -1,8 +0,0 @@
-package android.content.pm;
-import android.content.Intent;
-import android.os.Bundle;
-
-oneway interface IPackageInstallObserver2 {
- void onUserActionRequired(in Intent intent);
- void onPackageInstalled(String basePackageName, int returnCode, String msg, in Bundle extras);
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/IPackageInstaller.aidl b/app/src/main/aidl/android/content/pm/IPackageInstaller.aidl
deleted file mode 100644
index 14aab7c..0000000
--- a/app/src/main/aidl/android/content/pm/IPackageInstaller.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-package android.content.pm;
-
-import android.content.pm.IPackageDeleteObserver2;
-import android.content.pm.IPackageInstallerCallback;
-import android.content.pm.IPackageInstallerSession;
-import android.content.pm.PackageInstaller;
-import android.content.pm.VersionedPackage;
-import android.content.IntentSender;
-import android.graphics.Bitmap;
-
-interface IPackageInstaller {
- int createSession(in PackageInstaller.SessionParams params, String installerPackageName, String installerAttributionTag, int userId);
-// @RequiresApi(Build.VERSION_CODES.S)
-// int createSession(in PackageInstaller.SessionParams params, String installerPackageName, int userId);
- void updateSessionAppIcon(int sessionId, in Bitmap appIcon);
- void updateSessionAppLabel(int sessionId, String appLabel);
- void abandonSession(int sessionId);
- IPackageInstallerSession openSession(int sessionId);
- PackageInstaller.SessionInfo getSessionInfo(int sessionId);
- void registerCallback(IPackageInstallerCallback callback, int userId);
- void unregisterCallback(IPackageInstallerCallback callback);
- void uninstall(in VersionedPackage versionedPackage, String callerPackageName, int flags,
- in IntentSender statusReceiver, int userId);
- void uninstallExistingPackage(in VersionedPackage versionedPackage, String callerPackageName,
- in IntentSender statusReceiver, int userId);
- void installExistingPackage(String packageName, int installFlags, int installReason,
- in IntentSender statusReceiver, int userId, in List whiteListedPermissions);
- void setPermissionsResult(int sessionId, boolean accepted);
- void bypassNextStagedInstallerCheck(boolean value);
- void bypassNextAllowedApexUpdateCheck(boolean value);
- void setAllowUnlimitedSilentUpdates(String installerPackageName);
- void setSilentUpdatesThrottleTime(long throttleTimeInSeconds);
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/IPackageInstallerCallback.aidl b/app/src/main/aidl/android/content/pm/IPackageInstallerCallback.aidl
deleted file mode 100644
index 42e11bc..0000000
--- a/app/src/main/aidl/android/content/pm/IPackageInstallerCallback.aidl
+++ /dev/null
@@ -1,9 +0,0 @@
-package android.content.pm;
-
-oneway interface IPackageInstallerCallback {
- void onSessionCreated(int sessionId);
- void onSessionBadgingChanged(int sessionId);
- void onSessionActiveChanged(int sessionId, boolean active);
- void onSessionProgressChanged(int sessionId, float progress);
- void onSessionFinished(int sessionId, boolean success);
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/IPackageInstallerSession.aidl b/app/src/main/aidl/android/content/pm/IPackageInstallerSession.aidl
deleted file mode 100644
index 0204d42..0000000
--- a/app/src/main/aidl/android/content/pm/IPackageInstallerSession.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-package android.content.pm;
-
-import android.content.pm.Checksum;
-import android.content.pm.IOnChecksumsReadyListener;
-import android.content.pm.IPackageInstallObserver2;
-import android.content.IntentSender;
-import android.os.ParcelFileDescriptor;
-
-interface IPackageInstallerSession {
- void setClientProgress(float progress);
- void addClientProgress(float progress);
- String[] getNames();
- ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
- ParcelFileDescriptor openRead(String name);
- void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
- void stageViaHardLink(String target);
- void setChecksums(String name, in Checksum[] checksums, in byte[] signature);
- void requestChecksums(in String name, int optional, int required, in List trustedInstallers, in IOnChecksumsReadyListener onChecksumsReadyListener);
- void removeSplit(String splitName);
- void close();
- void commit(in IntentSender statusReceiver, boolean forTransferred);
- void transfer(in String packageName);
- void abandon();
- void addFile(int location, String name, long lengthBytes, in byte[] metadata, in byte[] signature);
- void removeFile(int location, String name);
- boolean isMultiPackage();
- int[] getChildSessionIds();
- void addChildSessionId(in int sessionId);
- void removeChildSessionId(in int sessionId);
- int getParentSessionId();
- boolean isStaged();
- int getInstallFlags();
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/IPackageManager.aidl b/app/src/main/aidl/android/content/pm/IPackageManager.aidl
deleted file mode 100644
index 86ce213..0000000
--- a/app/src/main/aidl/android/content/pm/IPackageManager.aidl
+++ /dev/null
@@ -1,231 +0,0 @@
-package android.content.pm;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ChangedPackages;
-import android.content.pm.InstantAppInfo;
-import android.content.pm.FeatureInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.IOnChecksumsReadyListener;
-import android.content.pm.IPackageInstaller;
-import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.ModuleInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.ComponentEnabledSetting;
-import android.content.pm.ProviderInfo;
-import android.content.pm.PermissionGroupInfo;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.pm.VersionedPackage;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
-import android.content.IntentSender;
-
-interface IPackageManager {
- void checkPackageStartable(String packageName, int userId);
- boolean isPackageAvailable(String packageName, int userId);
- PackageInfo getPackageInfo(String packageName, long flags, int userId);
- PackageInfo getPackageInfoVersioned(in VersionedPackage versionedPackage,
- long flags, int userId);
- int getPackageUid(String packageName, long flags, int userId);
- int[] getPackageGids(String packageName, long flags, int userId);
- String[] currentToCanonicalPackageNames(in String[] names);
- String[] canonicalToCurrentPackageNames(in String[] names);
- ApplicationInfo getApplicationInfo(String packageName, long flags, int userId);
- int getTargetSdkVersion(String packageName);
- ActivityInfo getActivityInfo(in ComponentName className, long flags, int userId);
- boolean activitySupportsIntent(in ComponentName className, in Intent intent,
- String resolvedType);
- ActivityInfo getReceiverInfo(in ComponentName className, long flags, int userId);
- ServiceInfo getServiceInfo(in ComponentName className, long flags, int userId);
- ProviderInfo getProviderInfo(in ComponentName className, long flags, int userId);
- boolean isProtectedBroadcast(String actionName);
- int checkSignatures(String pkg1, String pkg2);
- int checkUidSignatures(int uid1, int uid2);
- List getAllPackages();
- String[] getPackagesForUid(int uid);
- String getNameForUid(int uid);
- String[] getNamesForUids(in int[] uids);
- int getUidForSharedUser(String sharedUserName);
- int getFlagsForUid(int uid);
- int getPrivateFlagsForUid(int uid);
- boolean isUidPrivileged(int uid);
- ResolveInfo resolveIntent(in Intent intent, String resolvedType, long flags, int userId);
- ResolveInfo findPersistentPreferredActivity(in Intent intent, int userId);
- boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
- ResolveInfo resolveService(in Intent intent,
- String resolvedType, long flags, int userId);
- ProviderInfo resolveContentProvider(String name, long flags, int userId);
- void querySyncProviders(inout List outNames,
- inout List outInfo);
- InstrumentationInfo getInstrumentationInfo(
- in ComponentName className, int flags);
- void finishPackageInstall(int token, boolean didLaunch);
- void setInstallerPackageName(in String targetPackage, in String installerPackageName);
- void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName);
- String getInstallerPackageName(in String packageName);
- InstallSourceInfo getInstallSourceInfo(in String packageName);
- void resetApplicationPreferences(int userId);
- ResolveInfo getLastChosenActivity(in Intent intent,
- String resolvedType, int flags);
- void setLastChosenActivity(in Intent intent, String resolvedType, int flags,
- in IntentFilter filter, int match, in ComponentName activity);
- void addPreferredActivity(in IntentFilter filter, int match,
- in ComponentName[] set, in ComponentName activity, int userId, boolean removeExisting);
- void replacePreferredActivity(in IntentFilter filter, int match,
- in ComponentName[] set, in ComponentName activity, int userId);
- void clearPackagePreferredActivities(String packageName);
- int getPreferredActivities(out List outFilters,
- out List outActivities, String packageName);
- void addPersistentPreferredActivity(in IntentFilter filter, in ComponentName activity, int userId);
- void clearPackagePersistentPreferredActivities(String packageName, int userId);
- void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,
- int sourceUserId, int targetUserId, int flags);
- void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
- String[] setDistractingPackageRestrictionsAsUser(in String[] packageNames, int restrictionFlags,
- int userId);
- String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
- boolean isPackageSuspendedForUser(String packageName, int userId);
- Bundle getSuspendedPackageAppExtras(String packageName, int userId);
- byte[] getPreferredActivityBackup(int userId);
- void restorePreferredActivities(in byte[] backup, int userId);
- byte[] getDefaultAppsBackup(int userId);
- void restoreDefaultApps(in byte[] backup, int userId);
- byte[] getDomainVerificationBackup(int userId);
- void restoreDomainVerification(in byte[] backup, int userId);
-
- ComponentName getHomeActivities(out List outHomeCandidates);
- void setHomeActivity(in ComponentName className, int userId);
- void overrideLabelAndIcon(in ComponentName componentName, String nonLocalizedLabel,
- int icon, int userId);
- void restoreLabelAndIcon(in ComponentName componentName, int userId);
-
- void setComponentEnabledSetting(in ComponentName componentName,
- in int newState, in int flags, int userId);
- void setComponentEnabledSettings(in List settings, int userId);
-
- int getComponentEnabledSetting(in ComponentName componentName, int userId);
-
- void setApplicationEnabledSetting(in String packageName, in int newState, int flags,
- int userId, String callingPackage);
-
- int getApplicationEnabledSetting(in String packageName, int userId);
- void logAppProcessStartIfNeeded(String packageName, String processName, int uid, String seinfo, String apkFile, int pid);
- void flushPackageRestrictionsAsUser(in int userId);
-
- void setPackageStoppedState(String packageName, boolean stopped, int userId);
- void freeStorage(in String volumeUuid, in long freeStorageSize,
- int storageFlags, in IntentSender pi);
- void clearApplicationProfileData(in String packageName);
-
- String[] getSystemSharedLibraryNames();
- boolean hasSystemFeature(String name, int version);
- void enterSafeMode();
- boolean isSafeMode();
- boolean hasSystemUidErrors();
- oneway void notifyPackageUse(String packageName, int reason);
- oneway void notifyDexLoad(String loadingPackageName,
- in Map classLoaderContextMap, String loaderIsa);
- boolean performDexOptMode(String packageName, boolean checkProfiles,
- String targetCompilerFilter, boolean force, boolean bootComplete, String splitName);
- boolean performDexOptSecondary(String packageName,
- String targetCompilerFilter, boolean force);
- void dumpProfiles(String packageName, boolean dumpClassesAndMethods);
- void forceDexOpt(String packageName);
- void reconcileSecondaryDexFiles(String packageName);
- int getMoveStatus(int moveId);
- int movePackage(in String packageName, in String volumeUuid);
- int movePrimaryStorage(in String volumeUuid);
- boolean setInstallLocation(int loc);
- int getInstallLocation();
- int installExistingPackageAsUser(String packageName, int userId, int installFlags,
- int installReason, in List whiteListedPermissions);
- void verifyPendingInstall(int id, int verificationCode);
- void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
- void verifyIntentFilter(int id, int verificationCode, in List failedDomains);
- int getIntentVerificationStatus(String packageName, int userId);
- boolean updateIntentVerificationStatus(String packageName, int status, int userId);
- boolean isFirstBoot();
- boolean isOnlyCoreApps();
- boolean isDeviceUpgrading();
-
- boolean isStorageLow();
- boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId);
- boolean getApplicationHiddenSettingAsUser(String packageName, int userId);
- void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden);
- boolean setSystemAppInstallState(String packageName, boolean installed, int userId);
- IPackageInstaller getPackageInstaller();
- boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
- boolean getBlockUninstallForUser(String packageName, int userId);
- String getPermissionControllerPackageName();
- String getSdkSandboxPackageName();
- byte[] getInstantAppCookie(String packageName, int userId);
- boolean setInstantAppCookie(String packageName, in byte[] cookie, int userId);
- Bitmap getInstantAppIcon(String packageName, int userId);
- boolean isInstantApp(String packageName, int userId);
- boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
- void setUpdateAvailable(String packageName, boolean updateAvaialble);
- String getServicesSystemSharedLibraryPackageName();
- String getSharedSystemSharedLibraryPackageName();
- ChangedPackages getChangedPackages(int sequenceNumber, int userId);
- boolean isPackageDeviceAdminOnAnyUser(String packageName);
- int getInstallReason(String packageName, int userId);
- boolean canRequestPackageInstalls(String packageName, int userId);
- void deletePreloadsFileCache();
- ComponentName getInstantAppResolverComponent();
- ComponentName getInstantAppResolverSettingsComponent();
- ComponentName getInstantAppInstallerComponent();
- String getInstantAppAndroidId(String packageName, int userId);
- void setHarmfulAppWarning(String packageName, CharSequence warning, int userId);
- CharSequence getHarmfulAppWarning(String packageName, int userId);
- boolean hasSigningCertificate(String packageName, in byte[] signingCertificate, int flags);
- boolean hasUidSigningCertificate(int uid, in byte[] signingCertificate, int flags);
- String getDefaultTextClassifierPackageName();
- String getSystemTextClassifierPackageName();
- String getAttentionServicePackageName();
- String getRotationResolverPackageName();
- String getWellbeingPackageName();
- String getAppPredictionServicePackageName();
- String getSystemCaptionsServicePackageName();
- String getSetupWizardPackageName();
- String getIncidentReportApproverPackageName();
- String getContentCaptureServicePackageName();
- boolean isPackageStateProtected(String packageName, int userId);
- void sendDeviceCustomizationReadyBroadcast();
- List getInstalledModules(int flags);
- ModuleInfo getModuleInfo(String packageName, int flags);
- int getRuntimePermissionsVersion(int userId);
- void setRuntimePermissionsVersion(int version, int userId);
- void notifyPackagesReplacedReceived(in String[] packages);
- void requestPackageChecksums(in String packageName, boolean includeSplits, int optional, int required, in List trustedInstallers, in IOnChecksumsReadyListener onChecksumsReadyListener, int userId);
- IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
- String featureId, int userId);
- String[] getAppOpPermissionPackages(String permissionName);
- PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
- boolean addPermission(in PermissionInfo info);
- boolean addPermissionAsync(in PermissionInfo info);
- void removePermission(String name);
- int checkPermission(String permName, String pkgName, int userId);
- void grantRuntimePermission(String packageName, String permissionName, int userId);
- int checkUidPermission(String permName, int uid);
- void setMimeGroup(String packageName, String group, in List mimeTypes);
- String getSplashScreenTheme(String packageName, int userId);
- void setSplashScreenTheme(String packageName, String themeName, int userId);
- List getMimeGroup(String packageName, String group);
- boolean isAutoRevokeWhitelisted(String packageName);
- void makeProviderVisible(int recipientAppId, String visibleAuthority);
- void makeUidVisible(int recipientAppId, int visibleUid);
- IBinder getHoldLockToken();
- void holdLock(in IBinder token, in int durationMs);
- void setKeepUninstalledPackages(in List packageList);
- boolean canPackageQuery(String sourcePackageName, String targetPackageName, int userId);
-}
\ No newline at end of file
diff --git a/app/src/main/aidl/android/content/pm/PackageInstaller.aidl b/app/src/main/aidl/android/content/pm/PackageInstaller.aidl
deleted file mode 100644
index dfca396..0000000
--- a/app/src/main/aidl/android/content/pm/PackageInstaller.aidl
+++ /dev/null
@@ -1,4 +0,0 @@
-package android.content.pm;
-
-parcelable PackageInstaller.SessionParams;
-parcelable PackageInstaller.SessionInfo;
\ No newline at end of file
diff --git a/app/src/main/aidl/com/rosan/dhizuku/aidl/IDhizukuUserServiceManager.aidl b/app/src/main/aidl/com/rosan/dhizuku/aidl/IDhizukuUserServiceManager.aidl
new file mode 100644
index 0000000..0360cd9
--- /dev/null
+++ b/app/src/main/aidl/com/rosan/dhizuku/aidl/IDhizukuUserServiceManager.aidl
@@ -0,0 +1,5 @@
+package com.rosan.dhizuku.aidl;
+
+interface IDhizukuUserServiceManager {
+ void destroy();
+}
\ No newline at end of file
diff --git a/app/src/main/aidl/com/rosan/dhizuku/aidl/ITest.aidl b/app/src/main/aidl/com/rosan/dhizuku/aidl/ITest.aidl
new file mode 100644
index 0000000..87dd782
--- /dev/null
+++ b/app/src/main/aidl/com/rosan/dhizuku/aidl/ITest.aidl
@@ -0,0 +1,6 @@
+package com.rosan.dhizuku.aidl;
+
+interface ITest {
+ void onCreate() = 1;
+ void onDestroy() = 2;
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/data/process/model/impl/DhizukuUserServiceRepoImpl.kt b/app/src/main/java/com/rosan/dhizuku/data/process/model/impl/DhizukuUserServiceRepoImpl.kt
new file mode 100644
index 0000000..c5f664b
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/data/process/model/impl/DhizukuUserServiceRepoImpl.kt
@@ -0,0 +1,117 @@
+package com.rosan.dhizuku.data.process.model.impl
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.Binder
+import android.os.Bundle
+import android.os.IBinder
+import android.os.IInterface
+import android.os.Looper
+import android.os.Parcel
+import com.rosan.dhizuku.aidl.IDhizukuUserServiceManager
+import com.rosan.dhizuku.data.process.repo.ProcessRepo
+import com.rosan.dhizuku.data.reflect.repo.ReflectRepo
+import com.rosan.dhizuku.server.DhizukuProcessReceiver
+import com.rosan.dhizuku.shared.DhizukuVariables
+import org.apache.commons.cli.DefaultParser
+import org.apache.commons.cli.Option
+import org.apache.commons.cli.Options
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+import java.lang.reflect.Constructor
+import kotlin.system.exitProcess
+
+class DhizukuUserServiceRepoImpl {
+ companion object : ProcessRepo(), KoinComponent {
+ private val context by inject()
+
+ private val reflect by inject()
+
+ private val options = Options().addOption(
+ Option.builder("c").argName("component name (pName/cName)").required().hasArg()
+ .type(String::class.java).build()
+ )
+
+ @JvmStatic
+ override fun main(args: Array) = super.main(args)
+
+ override fun onCreate(args: Array) {
+ super.onCreate(args)
+ val cmdLine = DefaultParser().parse(options, args)
+ val componentName = ComponentName.unflattenFromString(cmdLine.getOptionValue("c"))
+ ?: throw Exception("need component name")
+ val service = createService(componentName).asBinder()
+ transactService(service, 1)
+ val manager = createManager(service)
+ val bundle = Bundle()
+ bundle.putBinder(DhizukuProcessReceiver.PARAM_MANAGER, manager.asBinder())
+ bundle.putBinder(DhizukuProcessReceiver.PARAM_USER_SERVICE, service)
+ bundle.putParcelable(DhizukuVariables.PARAM_COMPONENT, componentName)
+ val intent = Intent(DhizukuProcessReceiver.ACTION_USER_SERVICE).putExtras(bundle)
+ context.sendBroadcast(intent)
+ Looper.loop()
+ }
+
+ private fun createManager(service: IBinder): IDhizukuUserServiceManager {
+ return object : IDhizukuUserServiceManager.Stub() {
+ override fun destroy() {
+ transactService(service, 2)
+ exitProcess(0)
+ }
+ }
+ }
+
+ private fun createService(componentName: ComponentName): IInterface {
+// // compat for multi-user
+// val userHandle = UserHandleCompat.getUserHandleForUid(uid)
+// val packageContext = reflect.getDeclaredMethod(
+// Context::class.java,
+// "createPackageContextAsUser",
+// String::class.java,
+// Int::class.java,
+// UserHandle::class.java
+// )?.let {
+// it.isAccessible = true
+// it.invoke(
+// context,
+// componentName.packageName,
+// Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY,
+// userHandle
+// )
+// } as Context
+ val packageContext = context.createPackageContext(
+ componentName.packageName,
+ Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY
+ )
+ val serviceClazz = packageContext.classLoader.loadClass(componentName.className)
+ var constructorWithContext: Constructor<*>? = null
+ try {
+ constructorWithContext = serviceClazz.getConstructor(Context::class.java)
+ } catch (_: NoSuchMethodException) {
+ } catch (_: SecurityException) {
+ }
+ return (if (constructorWithContext != null) constructorWithContext.newInstance(context)
+ else serviceClazz.newInstance()).apply {
+ } as IInterface
+ }
+
+ private fun transactService(service: IBinder, code: Int) {
+ var dataParcel: Parcel? = null
+ var replyParcel: Parcel? = null
+ try {
+ val data = Parcel.obtain()
+ dataParcel = data
+ val reply = Parcel.obtain()
+ replyParcel = reply
+ data.writeInterfaceToken(service.interfaceDescriptor!!)
+ service.transact(
+ IBinder.FIRST_CALL_TRANSACTION + code, data, reply, Binder.FLAG_ONEWAY
+ )
+ } finally {
+ dataParcel?.recycle()
+ replyParcel?.recycle()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/rosan/dhizuku/data/process/repo/ProcessRepo.kt b/app/src/main/java/com/rosan/dhizuku/data/process/repo/ProcessRepo.kt
new file mode 100644
index 0000000..8630544
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/data/process/repo/ProcessRepo.kt
@@ -0,0 +1,49 @@
+package com.rosan.dhizuku.data.process.repo
+
+import com.rosan.dhizuku.di.init.processModules
+import org.koin.core.context.startKoin
+import java.io.FileDescriptor
+import java.io.FileOutputStream
+import java.io.OutputStream
+import java.io.PrintStream
+import kotlin.system.exitProcess
+
+abstract class ProcessRepo {
+ /*
+ * use @JvmStatic
+ * */
+ open fun main(args: Array) {
+ setIgnoreWarning(true)
+ val exception = kotlin.runCatching {
+ startKoin {
+ modules(processModules)
+ }
+ onCreate(args)
+ destroy()
+ }.exceptionOrNull()
+ setIgnoreWarning(false)
+ if (exception == null) return
+ exception.printStackTrace()
+ throw exception
+ }
+
+ protected open fun onCreate(args: Array) {
+ }
+
+ fun destroy(code: Int = 0) {
+ onDestroy()
+ exitProcess(code)
+ }
+
+ protected open fun onDestroy() {
+ }
+
+ private fun setIgnoreWarning(state: Boolean) {
+ System.setErr(PrintStream(if (state) NullOutputStream else FileOutputStream(FileDescriptor.err)))
+ }
+
+ object NullOutputStream : OutputStream() {
+ override fun write(b: Int) {
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/data/process/util/ProcessUtil.kt b/app/src/main/java/com/rosan/dhizuku/data/process/util/ProcessUtil.kt
new file mode 100644
index 0000000..4e47ece
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/data/process/util/ProcessUtil.kt
@@ -0,0 +1,48 @@
+package com.rosan.dhizuku.data.process.util
+
+import android.content.Context
+import android.os.Build
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import java.io.PrintWriter
+import java.util.concurrent.TimeUnit
+import kotlin.reflect.KClass
+
+object ProcessUtil : KoinComponent {
+ fun start(clazz: KClass, vararg params: Any?): Process {
+ val process = Runtime.getRuntime().exec("sh")
+ val writer = PrintWriter(process.outputStream, true)
+ val cmd = ArrayList()
+ cmd.add("/system/bin/app_process")
+ cmd.add(String.format("-Djava.class.path='%s'", get().packageCodePath))
+ cmd.add("/system/bin")
+ cmd.add(String.format("'%s'", clazz.qualifiedName))
+ cmd.addAll(params.map { it.toString() })
+ writer.println(cmd.joinToString(" "))
+ writer.println("exit $?")
+ return process
+ }
+
+ fun waitFor(process: Process, timeout: Long, unit: TimeUnit): Boolean {
+ return kotlin.runCatching {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) process.waitFor(timeout, unit)
+ else {
+ val startTime = System.nanoTime()
+ var rem = unit.toNanos(timeout)
+
+ do {
+ try {
+ process.exitValue()
+ return@runCatching true
+ } catch (ex: IllegalThreadStateException) {
+ if (rem > 0) Thread.sleep(
+ (TimeUnit.NANOSECONDS.toMillis(rem) + 1).coerceAtMost(100)
+ )
+ }
+ rem = unit.toNanos(timeout) - (System.nanoTime() - startTime)
+ } while (rem > 0)
+ return@runCatching false
+ }
+ }.getOrDefault(false)
+ }
+}
diff --git a/app/src/main/java/com/rosan/dhizuku/data/reflect/model/impl/ReflectRepoImpl.kt b/app/src/main/java/com/rosan/dhizuku/data/reflect/model/impl/ReflectRepoImpl.kt
new file mode 100644
index 0000000..1c9bcd1
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/data/reflect/model/impl/ReflectRepoImpl.kt
@@ -0,0 +1,93 @@
+package com.rosan.dhizuku.data.reflect.model.impl
+
+import com.rosan.dhizuku.data.reflect.repo.ReflectRepo
+import java.lang.reflect.Constructor
+import java.lang.reflect.Field
+import java.lang.reflect.Method
+
+class ReflectRepoImpl : ReflectRepo {
+ override fun getConstructors(clazz: Class<*>): Array> = clazz.constructors
+ override fun getDeclaredConstructors(clazz: Class<*>): Array> =
+ clazz.declaredConstructors
+
+ override fun getFields(clazz: Class<*>): Array = clazz.fields
+
+ override fun getDeclaredFields(clazz: Class<*>): Array = clazz.declaredFields
+
+ override fun getMethods(clazz: Class<*>): Array = clazz.methods
+
+ override fun getDeclaredMethods(clazz: Class<*>): Array = clazz.declaredMethods
+
+ override fun getConstructor(clazz: Class<*>, vararg parameterTypes: Class<*>): Constructor<*>? {
+ for (constructor in getConstructors(clazz)) {
+ val expectedTypes = constructor.parameterTypes
+ if (expectedTypes.size != parameterTypes.size) continue
+ for (i in expectedTypes.indices)
+ if (expectedTypes[i] != parameterTypes[i]) continue
+ return constructor
+ }
+ return null
+ }
+
+ override fun getDeclaredConstructor(
+ clazz: Class<*>,
+ vararg parameterTypes: Class<*>
+ ): Constructor<*>? {
+ for (constructor in getDeclaredConstructors(clazz)) {
+ val expectedTypes = constructor.parameterTypes
+ if (expectedTypes.size != parameterTypes.size) continue
+ for (i in expectedTypes.indices)
+ if (expectedTypes[i] != parameterTypes[i]) continue
+ return constructor
+ }
+ return null
+ }
+
+ override fun getField(clazz: Class<*>, name: String): Field? {
+ for (field in getFields(clazz)) {
+ if (field.name != name) continue
+ return field
+ }
+ return null
+ }
+
+ override fun getDeclaredField(clazz: Class<*>, name: String): Field? {
+ for (field in getDeclaredFields(clazz)) {
+ if (field.name != name) continue
+ return field
+ }
+ return null
+ }
+
+ override fun getMethod(
+ clazz: Class<*>,
+ name: String,
+ vararg parameterTypes: Class<*>
+ ): Method? {
+ for (method in getMethods(clazz)) {
+ if (method.name != name) continue
+ val expectedTypes = method.parameterTypes
+ if (expectedTypes.size != parameterTypes.size) continue
+ for (i in expectedTypes.indices)
+ if (expectedTypes[i] != parameterTypes[i]) continue
+ return method
+ }
+ return null
+ }
+
+ override fun getDeclaredMethod(
+ clazz: Class<*>,
+ name: String,
+ vararg parameterTypes: Class<*>
+ ): Method? {
+ for (method in getDeclaredMethods(clazz)) {
+ if (method.name != name) continue
+ val expectedTypes = method.parameterTypes
+ if (expectedTypes.size != parameterTypes.size) continue
+ for (i in expectedTypes.indices)
+ if (expectedTypes[i] != parameterTypes[i]) continue
+ return method
+ }
+ return null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/data/reflect/repo/ReflectRepo.kt b/app/src/main/java/com/rosan/dhizuku/data/reflect/repo/ReflectRepo.kt
new file mode 100644
index 0000000..84c3e84
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/data/reflect/repo/ReflectRepo.kt
@@ -0,0 +1,33 @@
+package com.rosan.dhizuku.data.reflect.repo
+
+import java.lang.reflect.Constructor
+import java.lang.reflect.Field
+import java.lang.reflect.Method
+
+interface ReflectRepo {
+ fun getConstructors(clazz: Class<*>): Array>
+
+ fun getDeclaredConstructors(clazz: Class<*>): Array>
+
+ fun getFields(clazz: Class<*>): Array
+
+ fun getDeclaredFields(clazz: Class<*>): Array
+
+ fun getMethods(clazz: Class<*>): Array
+
+ fun getDeclaredMethods(clazz: Class<*>): Array
+
+ fun getConstructor(clazz: Class<*>, vararg parameterTypes: Class<*>): Constructor<*>?
+
+ fun getDeclaredConstructor(
+ clazz: Class<*>, vararg parameterTypes: Class<*>
+ ): Constructor<*>?
+
+ fun getField(clazz: Class<*>, name: String): Field?
+
+ fun getDeclaredField(clazz: Class<*>, name: String): Field?
+
+ fun getMethod(clazz: Class<*>, name: String, vararg parameterTypes: Class<*>): Method?
+
+ fun getDeclaredMethod(clazz: Class<*>, name: String, vararg parameterTypes: Class<*>): Method?
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/di/init/process/context_module.kt b/app/src/main/java/com/rosan/dhizuku/di/init/process/context_module.kt
new file mode 100644
index 0000000..7e91dd4
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/di/init/process/context_module.kt
@@ -0,0 +1,56 @@
+package com.rosan.dhizuku.di.init.process
+
+import android.annotation.SuppressLint
+import android.app.ActivityThread
+import android.content.Context
+import android.os.Build
+import android.os.Looper
+import android.os.Process
+import com.rosan.dhizuku.data.reflect.repo.ReflectRepo
+import org.koin.dsl.module
+
+@SuppressLint("PrivateApi")
+val contextModule = module {
+ single {
+ // Normal app will have this.
+ var thread = ActivityThread.currentActivityThread()
+ if (thread == null) {
+ // If not normal app (launch by app_process or other).
+ if (Looper.getMainLooper() == null) Looper.prepareMainLooper()
+ thread = ActivityThread.systemMain()
+ }
+ // so get normal application or system context.
+ val context: Context = thread.application ?: thread.systemContext
+ val uid = Process.myUid()
+ val packageNames =
+ context.packageManager.getPackagesForUid(uid)
+ if (packageNames.isNullOrEmpty()) return@single context
+ // if current context isn't system context, return it.
+ if (
+ context.packageName in packageNames &&
+ (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q ||
+ context.opPackageName in packageNames)
+ ) return@single context
+ // create a context for packageName.
+ val packageName = packageNames.first()
+ val packageContext = context.createPackageContext(
+ packageName,
+ Context.CONTEXT_IGNORE_SECURITY or Context.CONTEXT_INCLUDE_CODE
+ )
+ val reflect: ReflectRepo = get()
+ val apk = reflect.getDeclaredField(packageContext::class.java, "mPackageInfo")?.let {
+ it.isAccessible = true
+ return@let it.get(packageContext)
+ }!!
+ val appContext = reflect.getDeclaredMethod(
+ packageContext::class.java,
+ "createAppContext",
+ ActivityThread::class.java,
+ apk::class.java
+ )?.let {
+ it.isAccessible = true
+ return@let it.invoke(null, thread, apk)
+ } as Context
+ appContext
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/di/init/process_modules.kt b/app/src/main/java/com/rosan/dhizuku/di/init/process_modules.kt
new file mode 100644
index 0000000..784d46b
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/di/init/process_modules.kt
@@ -0,0 +1,11 @@
+package com.rosan.dhizuku.di.init
+
+import com.rosan.dhizuku.di.init.process.contextModule
+import com.rosan.dhizuku.di.reflectModule
+
+val processModules = listOf(
+ contextModule,
+ reflectModule
+)
+
+
diff --git a/app/src/main/java/com/rosan/dhizuku/di/reflect_module.kt b/app/src/main/java/com/rosan/dhizuku/di/reflect_module.kt
new file mode 100644
index 0000000..715be6f
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/di/reflect_module.kt
@@ -0,0 +1,16 @@
+package com.rosan.dhizuku.di
+
+import android.os.Build
+import com.rosan.dhizuku.data.reflect.model.impl.ReflectRepoImpl
+import com.rosan.dhizuku.data.reflect.repo.ReflectRepo
+import org.koin.dsl.module
+import org.lsposed.hiddenapibypass.HiddenApiBypass
+
+val reflectModule = module {
+ single {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ HiddenApiBypass.setHiddenApiExemptions("")
+ }
+ ReflectRepoImpl()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/server/DhizukuConstants.kt b/app/src/main/java/com/rosan/dhizuku/server/DhizukuConstants.kt
index c051776..49b1a8d 100644
--- a/app/src/main/java/com/rosan/dhizuku/server/DhizukuConstants.kt
+++ b/app/src/main/java/com/rosan/dhizuku/server/DhizukuConstants.kt
@@ -1,5 +1,5 @@
package com.rosan.dhizuku.server
-val DHIZUKU_SERVRE_VERSION_CODE = 2
+val DHIZUKU_SERVRE_VERSION_CODE = 3
-val DHIZUKU_SERVER_VERSION_NAME = "1.1"
\ No newline at end of file
+val DHIZUKU_SERVER_VERSION_NAME = "1.2"
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/server/DhizukuProcessReceiver.kt b/app/src/main/java/com/rosan/dhizuku/server/DhizukuProcessReceiver.kt
new file mode 100644
index 0000000..a4cfbbe
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/server/DhizukuProcessReceiver.kt
@@ -0,0 +1,59 @@
+package com.rosan.dhizuku.server
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import com.rosan.dhizuku.aidl.IDhizukuUserServiceManager
+
+object DhizukuProcessReceiver : BroadcastReceiver() {
+ const val ACTION_USER_SERVICE = "com.rosan.dhizuku.process.user_service"
+
+ const val PARAM_MANAGER = "manager"
+
+ const val PARAM_USER_SERVICE = "service"
+
+ const val PARAM_TOKEN = "token"
+
+ private var listeners = listOf()
+
+ override fun onReceive(context: Context?, intent: Intent?) {
+ intent ?: return
+ when (intent.action) {
+ ACTION_USER_SERVICE -> onReceiveUserService(intent)
+ }
+ }
+
+ private fun onReceiveUserService(intent: Intent) {
+ val extras = intent.extras ?: return
+ val manager = IDhizukuUserServiceManager.Stub.asInterface(extras.getBinder(PARAM_MANAGER))
+ val service = extras.getBinder(PARAM_USER_SERVICE) ?: return
+ val args = DhizukuUserServiceArgs(extras)
+
+ listeners.forEach {
+ it.onReceive(args, DhizukuUserServiceConnections.UserService(manager, service))
+ }
+ }
+
+ fun addUserServiceListener(listener: OnUserServiceReceiverListener) {
+ listeners = ArrayList(listeners).apply {
+ add(listener)
+ }
+ }
+
+ fun removeUserServiceListener(listener: OnUserServiceReceiverListener) {
+ listeners = ArrayList(listeners).apply {
+ remove(listener)
+ }
+ }
+
+ fun clearUserServiceListeners() {
+ listeners = listOf()
+ }
+
+ interface OnUserServiceReceiverListener {
+ fun onReceive(
+ args: DhizukuUserServiceArgs,
+ service: DhizukuUserServiceConnections.UserService
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/server/DhizukuProvider.kt b/app/src/main/java/com/rosan/dhizuku/server/DhizukuProvider.kt
index e3021be..615300e 100644
--- a/app/src/main/java/com/rosan/dhizuku/server/DhizukuProvider.kt
+++ b/app/src/main/java/com/rosan/dhizuku/server/DhizukuProvider.kt
@@ -5,12 +5,10 @@ import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import android.os.Bundle
-import com.rosan.dhizuku.aidl.IDhizuku
import com.rosan.dhizuku.aidl.IDhizukuClient
+import com.rosan.dhizuku.server.impl.IDhizukuImpl
import com.rosan.dhizuku.shared.DhizukuVariables
import org.koin.core.component.KoinComponent
-import org.koin.core.component.get
-import org.koin.core.parameter.parametersOf
class DhizukuProvider : ContentProvider(), KoinComponent {
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
@@ -20,10 +18,7 @@ class DhizukuProvider : ContentProvider(), KoinComponent {
val client =
if (clientIBinder != null) IDhizukuClient.Stub.asInterface(clientIBinder)
else null
- val iDhizuku: IDhizuku = get(parameters = {
- parametersOf(client)
- })
- putBinder(DhizukuVariables.PARAM_DHIZUKU_BINDER, iDhizuku.asBinder())
+ putBinder(DhizukuVariables.PARAM_DHIZUKU_BINDER, IDhizukuImpl(client).asBinder())
}
else -> null;
diff --git a/app/src/main/java/com/rosan/dhizuku/server/DhizukuService.kt b/app/src/main/java/com/rosan/dhizuku/server/DhizukuService.kt
index 7bbcd9f..7b71d7a 100644
--- a/app/src/main/java/com/rosan/dhizuku/server/DhizukuService.kt
+++ b/app/src/main/java/com/rosan/dhizuku/server/DhizukuService.kt
@@ -50,11 +50,17 @@ class DhizukuService : Service(), KoinComponent {
override fun onDestroy() {
unregisterReceiver(packageReceiver)
+ unregisterReceiver(DhizukuProcessReceiver)
super.onDestroy()
}
private suspend fun run() {
runForeground()
+ registerPackageReceiver()
+ registerProcessReceiver()
+ }
+
+ private fun registerPackageReceiver() {
val filter = IntentFilter()
filter.addAction(Intent.ACTION_PACKAGE_ADDED)
filter.addAction(Intent.ACTION_PACKAGE_REMOVED)
@@ -62,6 +68,11 @@ class DhizukuService : Service(), KoinComponent {
registerReceiver(packageReceiver, filter)
}
+ private fun registerProcessReceiver() {
+ val filter = IntentFilter(DhizukuProcessReceiver.ACTION_USER_SERVICE)
+ registerReceiver(DhizukuProcessReceiver, filter)
+ }
+
private suspend fun runForeground() {
val manager = NotificationManagerCompat.from(this)
val channelName = "service_channel"
diff --git a/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceArgs.kt b/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceArgs.kt
new file mode 100644
index 0000000..25fbd19
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceArgs.kt
@@ -0,0 +1,30 @@
+package com.rosan.dhizuku.server
+
+import android.content.ComponentName
+import android.os.Build
+import android.os.Bundle
+import com.rosan.dhizuku.shared.DhizukuVariables
+
+class DhizukuUserServiceArgs {
+ private var bundle = Bundle();
+
+ var componentName: ComponentName
+ get() = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
+ bundle.getParcelable(DhizukuVariables.PARAM_COMPONENT, ComponentName::class.java)
+ else bundle.getParcelable(DhizukuVariables.PARAM_COMPONENT))!!
+ set(value) = bundle.putParcelable(DhizukuVariables.PARAM_COMPONENT, value)
+
+ constructor(bundle: Bundle) {
+ this.bundle = bundle
+ }
+
+ constructor(args: DhizukuUserServiceArgs) : this(args.bundle)
+
+ constructor(name: ComponentName) : this(Bundle().apply {
+ putParcelable(DhizukuVariables.PARAM_COMPONENT, name)
+ })
+
+ fun build(): Bundle {
+ return bundle;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceConnection.kt b/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceConnection.kt
new file mode 100644
index 0000000..d29b053
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceConnection.kt
@@ -0,0 +1,69 @@
+package com.rosan.dhizuku.server
+
+import android.os.IBinder
+import com.rosan.dhizuku.aidl.IDhizukuUserServiceConnection
+
+class DhizukuUserServiceConnection(
+ val uid: Int,
+ val pid: Int,
+ connection: IDhizukuUserServiceConnection
+) {
+ private var _connection = connection
+
+ var connection: IDhizukuUserServiceConnection
+ get() = _connection
+ set(value) {
+ kotlin.runCatching { _connection.asBinder().unlinkToDeath(recipient, 0) }
+ _connection = value
+ kotlin.runCatching {
+ _connection.asBinder().linkToDeath(recipient, 0)
+ }
+ }
+
+ private val recipient = IBinder.DeathRecipient {
+ DhizukuUserServiceConnections.unbind(uid, pid)
+ }
+
+ private val tokens = mutableListOf()
+
+ init {
+ kotlin.runCatching {
+ _connection.asBinder().linkToDeath(recipient, 0)
+ }
+ }
+
+ fun register(args: DhizukuUserServiceArgs) {
+ val name = args.componentName
+ val token = name.flattenToString()
+ tokens.remove(token)
+ tokens.add(token)
+ }
+
+ fun unregister(args: DhizukuUserServiceArgs) {
+ val name = args.componentName
+ val token = name.flattenToString()
+ tokens.remove(token)
+ }
+
+ fun isRegister(token: String) = tokens.contains(token)
+
+ fun connected(
+ args: DhizukuUserServiceArgs,
+ service: DhizukuUserServiceConnections.UserService
+ ) {
+ val name = args.componentName
+ val token = name.flattenToString()
+ if (token in tokens) kotlin.runCatching {
+ connection.connected(
+ args.build(),
+ service.service
+ )
+ }
+ }
+
+ fun died(args: DhizukuUserServiceArgs) {
+ val name = args.componentName
+ val token = name.flattenToString()
+ if (token in tokens) kotlin.runCatching { connection.died(args.build()) }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceConnections.kt b/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceConnections.kt
new file mode 100644
index 0000000..38334be
--- /dev/null
+++ b/app/src/main/java/com/rosan/dhizuku/server/DhizukuUserServiceConnections.kt
@@ -0,0 +1,159 @@
+package com.rosan.dhizuku.server
+
+import android.os.IBinder
+import com.rosan.dhizuku.aidl.IDhizukuUserServiceConnection
+import com.rosan.dhizuku.aidl.IDhizukuUserServiceManager
+import com.rosan.dhizuku.data.process.model.impl.DhizukuUserServiceRepoImpl
+import com.rosan.dhizuku.data.process.util.ProcessUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.channels.trySendBlocking
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.selects.select
+import rikka.shizuku.Shizuku
+import rikka.sui.Sui
+
+object DhizukuUserServiceConnections {
+ private fun onServiceConnected(args: DhizukuUserServiceArgs, service: UserService) {
+ connectionMap.values.forEach {
+ it.connected(args, service)
+ }
+ services[args.componentName.flattenToString()] = service
+ kotlin.runCatching {
+ service.service.linkToDeath({
+ onServiceDisconnected(args)
+ }, 0)
+ }
+ }
+
+ private fun onServiceDisconnected(args: DhizukuUserServiceArgs) {
+ connectionMap.values.forEach {
+ it.died(args)
+ }
+ services.remove(args.componentName.flattenToString())
+ }
+
+ private val connectionMap = mutableMapOf()
+
+ private val services = mutableMapOf()
+
+ fun start(args: DhizukuUserServiceArgs) {
+ val name = args.componentName
+ val token = name.flattenToString()
+ val service = services[token]
+ if (service != null) return
+ CoroutineScope(Dispatchers.IO).launch {
+ startInner(args)
+ }
+ }
+
+ private suspend fun startInner(args: DhizukuUserServiceArgs): UserService? {
+ val scope = CoroutineScope(Dispatchers.IO)
+ var process: Process? = null
+ val serviceResult = scope.async {
+ callbackFlow {
+ val listener = object : DhizukuProcessReceiver.OnUserServiceReceiverListener {
+ override fun onReceive(_args: DhizukuUserServiceArgs, service: UserService) {
+ if (args.componentName.flattenToString() != _args.componentName.flattenToString()) return
+ trySendBlocking(service)
+ close()
+ }
+ }
+ DhizukuProcessReceiver.addUserServiceListener(listener)
+ process = ProcessUtil.start(
+ DhizukuUserServiceRepoImpl::class,
+ "-c='${args.componentName.flattenToString()}'"
+ )
+ awaitClose {
+ DhizukuProcessReceiver.removeUserServiceListener(listener)
+ }
+ }.first()
+ }
+ val timeoutResult = scope.async {
+ delay(15 * 1000)
+ null
+ }
+ val service = select {
+ serviceResult.onAwait { it }
+ timeoutResult.onAwait { it }
+ }
+ scope.cancel()
+ if (service == null) {
+ kotlin.runCatching { process?.destroy() }
+ } else {
+ onServiceConnected(args, service)
+ }
+ return service
+ }
+
+ fun stop(args: DhizukuUserServiceArgs) {
+ val name = args.componentName
+ val token = name.flattenToString()
+ stop(token)
+ }
+
+ private fun stop(token: String) {
+ val service = services[token] ?: return
+ kotlin.runCatching { service.manager.destroy() }
+ }
+
+ fun bind(
+ uid: Int, pid: Int, args: DhizukuUserServiceArgs, iConnection: IDhizukuUserServiceConnection
+ ) {
+ val owner = "$uid:$pid"
+ val name = args.componentName
+ val token = name.flattenToString()
+ val connection =
+ connectionMap[owner] ?: DhizukuUserServiceConnection(uid, pid, iConnection).apply {
+ connectionMap[owner] = this
+ }
+ connection.connection = iConnection
+ connection.register(args)
+ val service = services[token]
+ if (service == null) {
+ start(args)
+ return
+ }
+ connection.connected(args, service)
+ }
+
+ fun unbind(uid: Int, pid: Int, args: DhizukuUserServiceArgs) {
+ val owner = "$uid:$pid"
+ val name = args.componentName
+ val token = name.flattenToString()
+ val connection = connectionMap[owner] ?: return
+ connection.unregister(args)
+ afterUnbind()
+ }
+
+ fun unbind(uid: Int, pid: Int) {
+ val owner = "$uid:$pid"
+ connectionMap.remove(owner)
+ afterUnbind()
+ }
+
+ private fun afterUnbind() {
+ val tokens = mutableListOf()
+ tokens.addAll(services.keys)
+ for (token in services.keys) {
+ for (connection in connectionMap.values) {
+ if (connection.isRegister(token)) {
+ tokens.remove(token)
+ break
+ }
+ }
+ }
+ for (token in tokens) {
+ stop(token)
+ }
+ Shizuku.checkSelfPermission()
+ }
+
+ data class UserService(val manager: IDhizukuUserServiceManager, val service: IBinder)
+}
diff --git a/app/src/main/java/com/rosan/dhizuku/server/impl/IDhizukuImpl.kt b/app/src/main/java/com/rosan/dhizuku/server/impl/IDhizukuImpl.kt
index df54c3e..ecc39b6 100644
--- a/app/src/main/java/com/rosan/dhizuku/server/impl/IDhizukuImpl.kt
+++ b/app/src/main/java/com/rosan/dhizuku/server/impl/IDhizukuImpl.kt
@@ -1,25 +1,24 @@
package com.rosan.dhizuku.server.impl
-import android.content.Context
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
-import android.os.IInterface
import android.os.Parcel
import com.rosan.dhizuku.aidl.IDhizuku
import com.rosan.dhizuku.aidl.IDhizukuClient
import com.rosan.dhizuku.aidl.IDhizukuRemoteProcess
+import com.rosan.dhizuku.aidl.IDhizukuUserServiceConnection
import com.rosan.dhizuku.data.settings.repo.AppRepo
import com.rosan.dhizuku.server.DHIZUKU_SERVER_VERSION_NAME
import com.rosan.dhizuku.server.DHIZUKU_SERVRE_VERSION_CODE
+import com.rosan.dhizuku.server.DhizukuUserServiceArgs
+import com.rosan.dhizuku.server.DhizukuUserServiceConnections
import com.rosan.dhizuku.shared.DhizukuVariables
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
class IDhizukuImpl(private val client: IDhizukuClient? = null) : IDhizuku.Stub(), KoinComponent {
- private val context by inject()
-
private val appRepo by inject()
override fun getVersionCode(): Int = DHIZUKU_SERVRE_VERSION_CODE
@@ -54,6 +53,26 @@ class IDhizukuImpl(private val client: IDhizukuClient? = null) : IDhizuku.Stub()
return IDhizukuRemoteProcessImpl(process, client?.asBinder() ?: this)
}
+ override fun bindUserService(
+ connection: IDhizukuUserServiceConnection?,
+ bundle: Bundle?
+ ) {
+ bundle ?: return
+ connection ?: return
+ val uid = Binder.getCallingUid()
+ val pid = Binder.getCallingPid()
+ val args = DhizukuUserServiceArgs(bundle)
+ DhizukuUserServiceConnections.bind(uid, pid, args, connection)
+ }
+
+ override fun unbindUserService(bundle: Bundle?) {
+ bundle ?: return
+ val uid = Binder.getCallingUid()
+ val pid = Binder.getCallingPid()
+ val args = DhizukuUserServiceArgs(bundle)
+ DhizukuUserServiceConnections.unbind(uid, pid, args)
+ }
+
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
if (code == DhizukuVariables.TRANSACT_CODE_REMOTE_BINDER) {
val targetData = Parcel.obtain()
diff --git a/app/src/main/java/com/rosan/dhizuku/ui/page/settings/home/HomePage.kt b/app/src/main/java/com/rosan/dhizuku/ui/page/settings/home/HomePage.kt
index 46535a2..161f09b 100644
--- a/app/src/main/java/com/rosan/dhizuku/ui/page/settings/home/HomePage.kt
+++ b/app/src/main/java/com/rosan/dhizuku/ui/page/settings/home/HomePage.kt
@@ -1,9 +1,9 @@
package com.rosan.dhizuku.ui.page.settings.home
+import android.annotation.SuppressLint
import android.app.admin.DevicePolicyManager
import android.content.*
import android.net.Uri
-import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.widget.TextView
import androidx.compose.animation.AnimatedContent
@@ -32,7 +32,6 @@ import com.rosan.dhizuku.data.console.repo.ConsoleRepo
import com.rosan.dhizuku.data.console.util.ConsoleRepoUtil
import com.rosan.dhizuku.data.console.util.ConsoleUtil
import com.rosan.dhizuku.server.DhizukuDAReceiver
-import com.rosan.dhizuku.ui.activity.RequestPermissionActivity
import com.rosan.dhizuku.ui.widget.dialog.PositionDialog
import com.rosan.dhizuku.util.toast
import kotlinx.coroutines.Dispatchers
@@ -72,6 +71,7 @@ fun HomePage(navController: NavController) {
}
}
+@SuppressLint("MissingPermission")
@Composable
fun StatusWidget() {
val context = LocalContext.current
@@ -96,7 +96,6 @@ fun StatusWidget() {
else if (isDeviceAdminer) R.string.device_admin_granted
else R.string.device_admin_denied
)
-
CardWidget(colors = CardDefaults.elevatedCardColors(
containerColor = containerColor, contentColor = onContainerColor
), content = {
@@ -109,16 +108,6 @@ fun StatusWidget() {
Spacer(modifier = Modifier.size(24.dp))
Text(text = text, style = MaterialTheme.typography.titleMedium)
}
- }, onClick = {
- context.startActivity(
- Intent(context, RequestPermissionActivity::class.java).putExtra(
- "bundle",
- Bundle().apply {
- putInt("uid", 10330)
- }).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK
- )
- )
})
}
@@ -184,6 +173,7 @@ fun ShizukuButton() {
exception is IllegalStateException && exception?.message == "binder haven't been received" -> stringResource(
R.string.shizuku_binder_not_received
)
+
else -> ByteArrayOutputStream().also {
exception?.printStackTrace(PrintStream(it))
}.toByteArray().decodeToString()
@@ -466,8 +456,7 @@ fun CardWidget(
}
if (buttons != null) {
FlowRow(
- modifier = Modifier
- .padding(horizontal = 12.dp),
+ modifier = Modifier.padding(horizontal = 12.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
buttons()
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 3d78786..a347be5 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -8,7 +8,7 @@
# https://mvnrepository.com/
[versions]
-agp = "8.0.0"
+agp = "8.0.1"
kotlin = "1.8.10"
compose = "1.4.0"
room = "2.5.1"
@@ -51,13 +51,19 @@ accompanist-flowlayout = { group = "com.google.accompanist", name = "accompanist
accompanist-drawablepainter = { group = "com.google.accompanist", name = "accompanist-drawablepainter", version.ref = "accompanist" }
accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanist" }
+# AndroidHiddenApiBypass
+# https://github.com/LSPosed/AndroidHiddenApiBypass
+lsposed-hiddenapibypass = { group = "org.lsposed.hiddenapibypass", name = "hiddenapibypass", version = "4.3" }
+
# XXPermissions
# https://github.com/getActivity/XXPermissions
xxpermissions = { group = "com.github.getActivity", name = "XXPermissions", version = "16.6" }
-# Shizuku
-# https://github.com/getActivity/XXPermissions
# Rikka Shizuku
# https://github.com/RikkaApps/Shizuku-API
rikka-shizuku-api = { group = "dev.rikka.shizuku", name = "api", version.ref = "rikka-shizuku" }
-rikka-shizuku-provider = { group = "dev.rikka.shizuku", name = "provider", version.ref = "rikka-shizuku" }
\ No newline at end of file
+rikka-shizuku-provider = { group = "dev.rikka.shizuku", name = "provider", version.ref = "rikka-shizuku" }
+
+# Commons CLI
+# https://search.maven.org/artifact/commons-cli/commons-cli
+commons-cli = { group = "commons-cli", name = "commons-cli", version = "1.5.0" }
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2871aa8..2a9f1c4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Tue Dec 13 22:04:53 CST 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/hidden-api/src/main/java/android/app/ActivityThread.java b/hidden-api/src/main/java/android/app/ActivityThread.java
new file mode 100644
index 0000000..924afd5
--- /dev/null
+++ b/hidden-api/src/main/java/android/app/ActivityThread.java
@@ -0,0 +1,22 @@
+package android.app;
+
+public final class ActivityThread {
+ public static void main(String[] args) {
+ }
+
+ public static ActivityThread systemMain() {
+ throw new RuntimeException("STUB");
+ }
+
+ public static ActivityThread currentActivityThread() {
+ throw new RuntimeException("STUB");
+ }
+
+ public ContextImpl getSystemContext() {
+ throw new RuntimeException("STUB");
+ }
+
+ public Application getApplication() {
+ throw new RuntimeException("STUB");
+ }
+}
diff --git a/hidden-api/src/main/java/android/app/ContextImpl.java b/hidden-api/src/main/java/android/app/ContextImpl.java
new file mode 100644
index 0000000..73cb972
--- /dev/null
+++ b/hidden-api/src/main/java/android/app/ContextImpl.java
@@ -0,0 +1,550 @@
+package android.app;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.view.Display;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ContextImpl extends Context {
+ @Override
+ public AssetManager getAssets() {
+ return null;
+ }
+
+ @Override
+ public Resources getResources() {
+ return null;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return null;
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return null;
+ }
+
+ @Override
+ public Looper getMainLooper() {
+ return null;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return null;
+ }
+
+ @Override
+ public void setTheme(int resid) {
+
+ }
+
+ @Override
+ public Resources.Theme getTheme() {
+ return null;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return null;
+ }
+
+ @Override
+ public String getPackageName() {
+ return null;
+ }
+
+ @Override
+ public ApplicationInfo getApplicationInfo() {
+ return null;
+ }
+
+ @Override
+ public String getPackageResourcePath() {
+ return null;
+ }
+
+ @Override
+ public String getPackageCodePath() {
+ return null;
+ }
+
+ @Override
+ public SharedPreferences getSharedPreferences(String name, int mode) {
+ return null;
+ }
+
+ @Override
+ public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
+ return false;
+ }
+
+ @Override
+ public boolean deleteSharedPreferences(String name) {
+ return false;
+ }
+
+ @Override
+ public FileInputStream openFileInput(String name) throws FileNotFoundException {
+ return null;
+ }
+
+ @Override
+ public FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException {
+ return null;
+ }
+
+ @Override
+ public boolean deleteFile(String name) {
+ return false;
+ }
+
+ @Override
+ public File getFileStreamPath(String name) {
+ return null;
+ }
+
+ @Override
+ public File getDataDir() {
+ return null;
+ }
+
+ @Override
+ public File getFilesDir() {
+ return null;
+ }
+
+ @Override
+ public File getNoBackupFilesDir() {
+ return null;
+ }
+
+ @Override
+ public File getExternalFilesDir(String type) {
+ return null;
+ }
+
+ @Override
+ public File[] getExternalFilesDirs(String type) {
+ return new File[0];
+ }
+
+ @Override
+ public File getObbDir() {
+ return null;
+ }
+
+ @Override
+ public File[] getObbDirs() {
+ return new File[0];
+ }
+
+ @Override
+ public File getCacheDir() {
+ return null;
+ }
+
+ @Override
+ public File getCodeCacheDir() {
+ return null;
+ }
+
+ @Override
+ public File getExternalCacheDir() {
+ return null;
+ }
+
+ @Override
+ public File[] getExternalCacheDirs() {
+ return new File[0];
+ }
+
+ @Override
+ public File[] getExternalMediaDirs() {
+ return new File[0];
+ }
+
+ @Override
+ public String[] fileList() {
+ return new String[0];
+ }
+
+ @Override
+ public File getDir(String name, int mode) {
+ return null;
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
+ return null;
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
+ return null;
+ }
+
+ @Override
+ public boolean moveDatabaseFrom(Context sourceContext, String name) {
+ return false;
+ }
+
+ @Override
+ public boolean deleteDatabase(String name) {
+ return false;
+ }
+
+ @Override
+ public File getDatabasePath(String name) {
+ return null;
+ }
+
+ @Override
+ public String[] databaseList() {
+ return new String[0];
+ }
+
+ @Override
+ public Drawable getWallpaper() {
+ return null;
+ }
+
+ @Override
+ public Drawable peekWallpaper() {
+ return null;
+ }
+
+ @Override
+ public int getWallpaperDesiredMinimumWidth() {
+ return 0;
+ }
+
+ @Override
+ public int getWallpaperDesiredMinimumHeight() {
+ return 0;
+ }
+
+ @Override
+ public void setWallpaper(Bitmap bitmap) throws IOException {
+
+ }
+
+ @Override
+ public void setWallpaper(InputStream data) throws IOException {
+
+ }
+
+ @Override
+ public void clearWallpaper() throws IOException {
+
+ }
+
+ @Override
+ public void startActivity(Intent intent) {
+
+ }
+
+ @Override
+ public void startActivity(Intent intent, Bundle options) {
+
+ }
+
+ @Override
+ public void startActivities(Intent[] intents) {
+
+ }
+
+ @Override
+ public void startActivities(Intent[] intents, Bundle options) {
+
+ }
+
+ @Override
+ public void startIntentSender(IntentSender intent, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) throws IntentSender.SendIntentException {
+
+ }
+
+ @Override
+ public void startIntentSender(IntentSender intent, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) throws IntentSender.SendIntentException {
+
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent) {
+
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent, String receiverPermission) {
+
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
+
+ }
+
+ @Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission) {
+
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+
+ }
+
+ @Override
+ public void sendStickyBroadcast(Intent intent) {
+
+ }
+
+ @Override
+ public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+
+ }
+
+ @Override
+ public void removeStickyBroadcast(Intent intent) {
+
+ }
+
+ @Override
+ public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
+
+ }
+
+ @Override
+ public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+
+ }
+
+ @Override
+ public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
+
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ return null;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+ return null;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
+ return null;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+ return null;
+ }
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+
+ }
+
+ @Override
+ public ComponentName startService(Intent service) {
+ return null;
+ }
+
+ @Override
+ public ComponentName startForegroundService(Intent service) {
+ return null;
+ }
+
+ @Override
+ public boolean stopService(Intent service) {
+ return false;
+ }
+
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+ return false;
+ }
+
+ @Override
+ public void unbindService(ServiceConnection conn) {
+
+ }
+
+ @Override
+ public boolean startInstrumentation(ComponentName className, String profileFile, Bundle arguments) {
+ return false;
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ return null;
+ }
+
+ @Override
+ public String getSystemServiceName(Class> serviceClass) {
+ return null;
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid) {
+ return 0;
+ }
+
+ @Override
+ public int checkCallingPermission(String permission) {
+ return 0;
+ }
+
+ @Override
+ public int checkCallingOrSelfPermission(String permission) {
+ return 0;
+ }
+
+ @Override
+ public int checkSelfPermission(String permission) {
+ return 0;
+ }
+
+ @Override
+ public void enforcePermission(String permission, int pid, int uid, String message) {
+
+ }
+
+ @Override
+ public void enforceCallingPermission(String permission, String message) {
+
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+
+ }
+
+ @Override
+ public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
+
+ }
+
+ @Override
+ public void revokeUriPermission(Uri uri, int modeFlags) {
+
+ }
+
+ @Override
+ public void revokeUriPermission(String toPackage, Uri uri, int modeFlags) {
+
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ return 0;
+ }
+
+ @Override
+ public int checkCallingUriPermission(Uri uri, int modeFlags) {
+ return 0;
+ }
+
+ @Override
+ public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
+ return 0;
+ }
+
+ @Override
+ public int checkUriPermission(Uri uri, String readPermission, String writePermission, int pid, int uid, int modeFlags) {
+ return 0;
+ }
+
+ @Override
+ public void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message) {
+
+ }
+
+ @Override
+ public void enforceCallingUriPermission(Uri uri, int modeFlags, String message) {
+
+ }
+
+ @Override
+ public void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message) {
+
+ }
+
+ @Override
+ public void enforceUriPermission(Uri uri, String readPermission, String writePermission, int pid, int uid, int modeFlags, String message) {
+
+ }
+
+ @Override
+ public Context createPackageContext(String packageName, int flags) throws PackageManager.NameNotFoundException {
+ return null;
+ }
+
+ @Override
+ public Context createContextForSplit(String splitName) throws PackageManager.NameNotFoundException {
+ return null;
+ }
+
+ @Override
+ public Context createConfigurationContext(Configuration overrideConfiguration) {
+ return null;
+ }
+
+ @Override
+ public Context createDisplayContext(Display display) {
+ return null;
+ }
+
+ @Override
+ public Context createDeviceProtectedStorageContext() {
+ return null;
+ }
+
+ @Override
+ public boolean isDeviceProtectedStorage() {
+ return false;
+ }
+}