From e78b9809ee95ee033ab016a9973942fa1bd72b8f Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Tue, 23 Apr 2024 13:44:22 +0800 Subject: [PATCH] use Shizuku API instead of rish #10 --- .gitignore | 16 +- app/build.gradle.kts | 3 + app/proguard-rules.pro | 3 +- app/src/main/AndroidManifest.xml | 8 + .../com/bintianqi/owndroid/IUserService.aidl | 7 + app/src/main/assets/rish.sh | 5 - app/src/main/assets/rish_shizuku.dex | Bin 6828 -> 0 bytes .../java/com/bintianqi/owndroid/dpm/DPM.kt | 1 - .../bintianqi/owndroid/dpm/ShizukuActivate.kt | 233 +++++++++--------- .../bintianqi/owndroid/dpm/ShizukuService.kt | 46 ++++ app/src/main/res/values-zh-rCN/strings.xml | 7 + app/src/main/res/values/strings.xml | 10 +- 12 files changed, 205 insertions(+), 134 deletions(-) create mode 100644 app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl delete mode 100644 app/src/main/assets/rish.sh delete mode 100644 app/src/main/assets/rish_shizuku.dex create mode 100644 app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt diff --git a/.gitignore b/.gitignore index b1a6202..38e98fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,13 @@ *.iml -/.gradle -/local.properties -/.idea +.gradle +local.properties +.idea .DS_Store -/build -/captures +build +captures .externalNativeBuild .cxx -local.properties -/app/build -/app/release +app/build +app/release +app/debug .androidide diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bc2fbdd..2345c53 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -34,6 +34,7 @@ android { } buildFeatures { compose = true + aidl = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.1" @@ -56,4 +57,6 @@ dependencies { implementation("com.google.accompanist:accompanist-drawablepainter:0.35.0-alpha") implementation("androidx.compose.material3:material3:1.2.0") implementation("androidx.navigation:navigation-compose:2.7.7") + implementation("dev.rikka.shizuku:provider:13.1.5") + implementation("dev.rikka.shizuku:api:13.1.5") } \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 3f41e6a..55542ee 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -12,6 +12,7 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} +-keep class com.bintianqi.owndroid.dpm.ShizukuService # Uncomment this to preserve the line number information for # debugging stack traces. @@ -19,4 +20,4 @@ # If you keep the line number information, uncomment this to # hide the original source file name. --renamesourcefileattribute SourceFile \ No newline at end of file +# -renamesourcefileattribute SourceFile diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 12cc4ac..292fa7a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,6 +19,7 @@ + + diff --git a/app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl b/app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl new file mode 100644 index 0000000..9cff5e0 --- /dev/null +++ b/app/src/main/aidl/com/bintianqi/owndroid/IUserService.aidl @@ -0,0 +1,7 @@ +package com.bintianqi.owndroid; + +interface IUserService { + void destroy() = 16777114; + String execute(String command) = 1; + String getUid() = 2; +} diff --git a/app/src/main/assets/rish.sh b/app/src/main/assets/rish.sh deleted file mode 100644 index 1aa980f..0000000 --- a/app/src/main/assets/rish.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/system/bin/sh -BASEDIR=$(dirname "$0") -DEX="$BASEDIR"/rish_shizuku.dex -[ -z "$RISH_APPLICATION_ID" ] && export RISH_APPLICATION_ID="com.bintianqi.owndroid" -/system/bin/app_process -Djava.class.path="$DEX" /system/bin --nice-name=rish rikka.shizuku.shell.ShizukuShellLoader "$@" diff --git a/app/src/main/assets/rish_shizuku.dex b/app/src/main/assets/rish_shizuku.dex deleted file mode 100644 index 964d7a5994b8285e347fcb049b20aed8221409f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6828 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.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)&& - !myDpm.isOrganizationOwnedDeviceWithManagedProfile + VERSION.SDK_INT>=30&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent) ){ Column { - Text(text = stringResource(R.string.org_owned_work_profile), style = typography.titleLarge, color = colorScheme.onPrimaryContainer) - Text(text = stringResource(R.string.input_userid_of_work_profile)) - var inputUserID by remember{mutableStateOf("")} - OutlinedTextField( - value = inputUserID, onValueChange = {inputUserID=it}, - label = {Text("UserID")}, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), - keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), - modifier = Modifier.focusable().fillMaxWidth().padding(vertical = 2.dp) - ) Button( onClick = { coScope.launch{ - focusMgr.clearFocus() - outputText = executeCommand( - myContext, "sh rish.sh", myContext.getString(R.string.activate_org_profile_command_with_user_id, inputUserID), - null, filesDir + val userID = Binder.getCallingUid() / 100000 + outputText = service!!.execute( + "dpm mark-profile-owner-on-organization-owned-device --user $userID com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver" ) - scrollState.animateScrollTo(scrollState.maxValue, scrollAnim()) outputTextScrollState.animateScrollTo(0, scrollAnim()) - if(myDpm.isOrganizationOwnedDeviceWithManagedProfile){ - Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show() - } } }, - modifier = Modifier.fillMaxWidth() + enabled = enabled ) { - Text(text = stringResource(R.string.activate)) + Text(text = stringResource(R.string.activate_org_profile)) } } } - SelectionContainer(modifier = Modifier.align(Alignment.Start).horizontalScroll(outputTextScrollState)){ + SelectionContainer(modifier = Modifier + .align(Alignment.Start) + .horizontalScroll(outputTextScrollState)){ Text(text = outputText, softWrap = false, modifier = Modifier.padding(4.dp)) } @@ -194,48 +190,53 @@ fun scrollAnim( visibilityThreshold: T? = null ): SpringSpec = SpringSpec(dampingRatio, stiffness, visibilityThreshold) -fun extractRish(myContext:Context){ - val assetsMgr = myContext.assets - myContext.deleteFile("rish.sh") - myContext.deleteFile("rish_shizuku.dex") - val shInput = assetsMgr.open("rish.sh") - val shOutput = myContext.openFileOutput("rish.sh",MODE_PRIVATE) - IOUtils.copy(shInput,shOutput) - shOutput.close() - val dexInput = assetsMgr.open("rish_shizuku.dex") - val dexOutput = myContext.openFileOutput("rish_shizuku.dex",MODE_PRIVATE) - IOUtils.copy(dexInput,dexOutput) - dexOutput.close() - if(VERSION.SDK_INT>=34){ Runtime.getRuntime().exec("chmod 400 rish_shizuku.dex",null,myContext.filesDir) } +private fun checkPermission(context: Context):String{ + if(checkShizukuStatus()==-1){return context.getString(R.string.shizuku_not_started)} + val getUid = if(service==null){return context.getString(R.string.shizuku_not_bind)}else{service!!.uid} + return when(getUid){ + "2000"->context.getString(R.string.shizuku_activated_shell) + "0"->context.getString(R.string.shizuku_activated_root) + else->context.getString(R.string.unknown_status)+"\nUID: $getUid" + } } -suspend fun executeCommand(myContext: Context, command: String, subCommand:String, env: Array?, dir:File?): String { - var result = "" - val tunnel:ByteArrayInputStream - val process:Process - val outputStream:OutputStream - try { - tunnel = ByteArrayInputStream(subCommand.toByteArray()) - process = withContext(Dispatchers.IO){Runtime.getRuntime().exec(command, env, dir)} - outputStream = process.outputStream - IOUtils.copy(tunnel,outputStream) - withContext(Dispatchers.IO){ outputStream.close() } - val exitCode = withContext(Dispatchers.IO){ process.waitFor() } - if(exitCode!=0){ result+="Error: $exitCode" } - }catch(e:Exception){ - e.printStackTrace() - return e.toString() - } - try { - val outputReader = BufferedReader(InputStreamReader(process.inputStream)) - var outputLine: String - while(withContext(Dispatchers.IO){ outputReader.readLine() }.also {outputLine = it}!=null) { result+="$outputLine\n" } - val errorReader = BufferedReader(InputStreamReader(process.errorStream)) - var errorLine: String - while(withContext(Dispatchers.IO){ errorReader.readLine() }.also {errorLine = it}!=null) { result+="$errorLine\n" } - } catch(e: NullPointerException) { - e.printStackTrace() - } - if(result==""){ return myContext.getString(R.string.try_again) } - return result +fun checkShizukuStatus():Int{ + val status = try { + if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) { 1 } + else if (Shizuku.shouldShowRequestPermissionRationale()) { 0 } + else { Shizuku.requestPermission(0); 0 } + }catch(e:Exception){ -1 } + Log.e("Shizuku",status.toString()) + return status +} + +fun userServiceControl(context:Context, status:Boolean){ + if(checkShizukuStatus()!=1){ return } + val userServiceConnection = object : ServiceConnection { + override fun onServiceConnected(componentName: ComponentName, binder: IBinder) { + if (binder.pingBinder()) { + service = IUserService.Stub.asInterface(binder) + } else { + Toast.makeText(context,context.getString(R.string.invalid_binder),Toast.LENGTH_SHORT).show() + } + } + override fun onServiceDisconnected(componentName: ComponentName) { + service = null + Toast.makeText(context,context.getString(R.string.shizuku_service_disconnected),Toast.LENGTH_SHORT).show() + } + } + val userServiceArgs = Shizuku.UserServiceArgs( + ComponentName( + context.packageName,ShizukuService::class.java.name + ) + ) + .daemon(false) + .processNameSuffix("service") + .debuggable(true) + .version(26) + if(status){ + Shizuku.bindUserService(userServiceArgs,userServiceConnection) + }else{ + Shizuku.unbindUserService(userServiceArgs,userServiceConnection,false) + } } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt new file mode 100644 index 0000000..d967578 --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/ShizukuService.kt @@ -0,0 +1,46 @@ +package com.bintianqi.owndroid.dpm + +import android.os.IBinder +import android.system.Os +import com.bintianqi.owndroid.IUserService +import java.io.BufferedReader +import java.io.InputStreamReader + +var service:IUserService? = null + +class ShizukuService: IUserService.Stub() { + override fun asBinder(): IBinder { + TODO("Not yet implemented") + } + + override fun destroy(){ } + + override fun execute(command: String?): String { + var result = "" + val process:Process + try { + process = Runtime.getRuntime().exec(command) + val exitCode = process.waitFor() + if(exitCode!=0){ result+="Error: $exitCode" } + }catch(e:Exception){ + e.printStackTrace() + return e.toString() + } + try { + val outputReader = BufferedReader(InputStreamReader(process.inputStream)) + var outputLine: String + while(outputReader.readLine().also {outputLine = it}!=null) { result+="$outputLine\n" } + val errorReader = BufferedReader(InputStreamReader(process.errorStream)) + var errorLine: String + while(errorReader.readLine().also {errorLine = it}!=null) { result+="$errorLine\n" } + } catch(e: NullPointerException) { + e.printStackTrace() + } + if(result==""){ return "No result" } + return result + } + + override fun getUid(): String { + return Os.getuid().toString() + } +} diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index cfa98ee..cb99ebf 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -41,6 +41,7 @@ 效果未知 选项 复制代码 + 未知状态 Device admin @@ -83,6 +84,12 @@ 已授权(Root) 激活Profile owner 激活Device owner + 激活由组织拥有的工作资料 + Shizuku服务断开连接 + Shizuku未连接 + 无效Binder + 连接Shizuku + 未授权 系统 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8d7d770..3174665 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,6 +44,7 @@ Copy Command Package name Not exist + Unknown status Device admin @@ -87,9 +88,6 @@ Enter UserID of work profile List owners Shizuku not started. - - dpm mark-profile-owner-on-organization-owned-device --user %1$s com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver - dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver dpm set-profile-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver @@ -97,6 +95,12 @@ Permission granted (Root) Activate profile owner Activate device owner + Activate organization-owned work profile + Shizuku service disconnected + Invalid binder + Connect Shizuku + Shizuku disconnected + Permission denied System manager