diff options
Diffstat (limited to 'app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt')
-rw-r--r-- | app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt | 297 |
1 files changed, 130 insertions, 167 deletions
diff --git a/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt b/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt index 18f19d0..ac198d9 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt @@ -1,231 +1,194 @@ package moe.yuuta.workmode.access +import android.content.ComponentName import android.content.Context import android.os.Bundle -import android.os.Parcel import android.os.PersistableBundle +import android.service.quicksettings.TileService +import androidx.annotation.WorkerThread import com.elvishew.xlog.Logger import com.elvishew.xlog.XLog +import eu.chainfire.librootjava.RootIPCReceiver import eu.chainfire.librootjava.RootJava import eu.chainfire.libsuperuser.Shell import moe.yuuta.workmode.BuildConfig +import moe.yuuta.workmode.IAccessor +import moe.yuuta.workmode.R +import moe.yuuta.workmode.Setup.getLogsPath +import moe.yuuta.workmode.suspend.SuspendTile import moe.yuuta.workmode.suspend.data.ListMode import moe.yuuta.workmode.suspend.data.Status import moe.yuuta.workmode.suspend.data.SuspendedStorage -import moe.yuuta.workmode.utils.ByteArraySerializer +import moe.yuuta.workmode.suspend.data.TransferableSuspendedApp +import java.util.function.Function import java.util.stream.Collectors /** * The high-level API accessor, as known as the launcher (starter) of the accessor, wraps * the necessary start steps to launch it and deserialize the result. */ -open class AccessorStarter(private val mContext: Context, private val mLogPath: String) { - private val logger: Logger = XLog.tag("AccessorStarter").build() - +open class AccessorStarter(private val mContext: Context, private val mService: IAccessor, private val mListener: RootIPCReceiver<IAccessor>) { companion object { + private val logger: Logger = XLog.tag("AccessorStarter").build() + const val ACTION_UPDATE_UI_STATE = "moe.yuuta.workmode.access.ACTION_UPDATE_UI_STATE" const val ACTION_UPDATE_UI_PROGRESS = "moe.yuuta.workmode.access.ACTION_UPDATE_UI_PROGRESS" const val EXTRA_SHOW_PROGRESS = "moe.yuuta.workmode.access.EXTRA_SHOW_PROGRESS" - } - private fun launchRootProcess(root: Boolean, vararg args: String): MutableList<String> { - val command = RootJava.getLaunchScript(mContext, + // #Anti-Crack + internal const val EXTRA_ERROR_CODE = "moe.yuuta.workmode.access.EXTRA_ERROR_CODE" + internal const val EXTRA_ERROR_MSG = "moe.yuuta.workmode.access.EXTRA_ERROR_MSG" + internal const val EXTRA_ERROR_STATUS = "moe.yuuta.workmode.access.EXTRA_ERROR_STATUS" + internal const val EXTRA_DATA = "moe.yuuta.workmode.access.EXTRA_DATA" + internal const val EXTRA_DAT = "moe.yuuta.workmode.access.EXTRA_DAT" + + private fun launchRootProcess(context: Context, root: Boolean, vararg args: String): MutableList<String> { + val command = RootJava.getLaunchScript(context, WorkModeAccessor::class.java, null, null, args, BuildConfig.APPLICATION_ID + ":accessor") - return if (root) { - Shell.SU.run(command) - } else { - Shell.SH.run(command) + return if (root) { + Shell.SU.run(command) + } else { + Shell.SH.run(command) + } } - } - fun getSuspendedPackageAppExtras(packageName: String, root: Boolean): Bundle? { - val argumentParcel: Parcel = obtainArgumentParcel() - try { - argumentParcel.writeString(WorkModeAccessor.ACTION_GET_APP_EXTRAS) - argumentParcel.writeString(packageName) - val marshalledResult = launchRootProcess(root, - ByteArraySerializer.serialize(argumentParcel.marshall()))[0] - val result = deserialize(ByteArraySerializer.deserialize(marshalledResult)) - val bundle = result.readBundle() - result.recycle() - return bundle - } finally { - argumentParcel.recycle() - } - } + /** + * Create a connected Starter object. + */ + @WorkerThread + fun <T> start(context: Context, root: Boolean, thenRun: Function<AccessorStarter, T>): T { + var res: T? = null + var err: Throwable? = null + object : RootIPCReceiver<IAccessor>(context, 0x302) { + override fun onConnect(ipc: IAccessor?) { + logger.d("Connected to the system") + val starter = AccessorStarter(context, ipc!!, this) + try { + res = thenRun.apply(starter) + } catch (e: Throwable) { + logger.d("Cannot perform the action", e) + err = e + } + starter.release() + } - fun getSuspendedPackageLauncherExtras(packageName: String, root: Boolean): Bundle? { - val argumentParcel: Parcel = obtainArgumentParcel() - try { - - argumentParcel.writeString(WorkModeAccessor.ACTION_GET_LAUNCHER_EXTRAS) - argumentParcel.writeString(packageName) - val marshalledResult = launchRootProcess(root, - ByteArraySerializer.serialize(argumentParcel.marshall()))[0] - val result = deserialize(ByteArraySerializer.deserialize(marshalledResult)) - val bundle = result.readBundle() - result.recycle() - return bundle - } finally { - argumentParcel.recycle() + override fun onDisconnect(ipc: IAccessor?) { + logger.d("Disconnected from the system") + } + } + logger.d("Starting root process.....") + launchRootProcess(context, root, getLogsPath(context).absolutePath) + // Wait until it exits. + // We assume that the server must return a non-null result or an exception. + if (err != null) + throw err as Throwable + return res!! } } - fun isPackageSuspended(packageNames: Array<out String>, root: Boolean): Boolean { - val argumentParcel: Parcel = obtainArgumentParcel() - try { - - argumentParcel.writeString(WorkModeAccessor.ACTION_IS_SUSPENDED) - argumentParcel.writeStringArray(packageNames) - val marshalledResult = launchRootProcess(root, - WorkModeAccessor.ACTION_IS_SUSPENDED, - ByteArraySerializer.serialize(argumentParcel.marshall()))[0] - - val result = deserialize(ByteArraySerializer.deserialize(marshalledResult)) - val isSuspended = result.readByte() == 1.toByte() - result.recycle() - return isSuspended - } finally { - argumentParcel.recycle() - } - } + fun getSuspendedPackageAppExtras(packageInfo: TransferableSuspendedApp): Bundle? = + mService.getSuspendedPackageAppExtras(packageInfo) - fun dump(packageName: String, root: Boolean): DumpResult { - val argumentParcel: Parcel = obtainArgumentParcel() - try { - - argumentParcel.writeString(WorkModeAccessor.ACTION_DUMP) - argumentParcel.writeString(packageName) - val marshalledResult = launchRootProcess(root, - ByteArraySerializer.serialize(argumentParcel.marshall()))[0] - val result = deserialize(ByteArraySerializer.deserialize(marshalledResult)) - val data = DumpResult( - result.readByte() == 1.toByte(), - result.readBundle(), - result.readBundle() - ) - result.recycle() - return data - } finally { - argumentParcel.recycle() - } + fun getSuspendedPackageLauncherExtras(packageInfo: TransferableSuspendedApp): Bundle? = + mService.getSuspendedPackageLauncherExtras(packageInfo) + + fun isPackageSuspended(packages: List<TransferableSuspendedApp>): Boolean { + return mService.isSuspended(packages) } - fun setPackagesSuspended(packageNames: Array<String>, suspended: Boolean, + fun dump(packageInfo: TransferableSuspendedApp): DumpResult = + mService.dump(packageInfo) + + fun setPackagesSuspended(packages: List<TransferableSuspendedApp>, suspended: Boolean, appExtras: PersistableBundle, launcherExtras: PersistableBundle, - dialogMessage: String, root: Boolean): Array<String> { - val argumentParcel: Parcel = obtainArgumentParcel() - try { - - argumentParcel.writeString(WorkModeAccessor.ACTION_SET_SUSPENDED) - argumentParcel.writeStringArray(packageNames) - argumentParcel.writeByte(if (suspended) 1 else 0) - argumentParcel.writeBundle(Bundle(appExtras)) - argumentParcel.writeBundle(Bundle(launcherExtras)) - argumentParcel.writeString(dialogMessage) - val marshalledResult = launchRootProcess(root, - ByteArraySerializer.serialize(argumentParcel.marshall()))[0] - val result = deserialize(ByteArraySerializer.deserialize(marshalledResult)) - val rs = result.createStringArray() ?: arrayOf() - result.recycle() - return rs - } finally { - argumentParcel.recycle() - } + dialogMessage: String): Array<String> { + val result = mService.setPackagesSuspended(packages, suspended, appExtras, launcherExtras, dialogMessage) + processError(result) + return result.getStringArray(EXTRA_DATA) } - @Throws(Throwable::class) - private fun deserialize(byteArray: ByteArray): Parcel { - val result = Parcel.obtain() - result.unmarshall(byteArray, 0, byteArray.size) - // Thanks to https://github.com/jiaminghan/droidplanner-master/blob/743b5436df6311cbbbfdecd21f796e2b948cbac7/Android/src/com/o3dr/services/android/lib/util/ParcelableUtils.java#L35 - result.setDataPosition(0) - when (result.readByte()) { - 1.toByte() -> { - } - 0.toByte() -> { - val throwable = result.readSerializable() as Throwable? - if (throwable != null) { - throw throwable - } - throw RuntimeException("Unsuccessful result with unknown stacktrace") + // Read the Bundle which is returned from some methods. + // It contains the crack information and the normal information. + // If it has crack information, log it. + // #Anti-Crack + private fun processError(bundle: Bundle) { + when (bundle.getInt(EXTRA_ERROR_CODE)) { + 1 -> { } // If server returns this code, which means the task is successfully executed but // it had detected that the app was cracked. // #Anti-Crack - 2.toByte() -> { + 2 -> { // The ID is used to prevent from multiple reporting. - val id = result.readString() - val reason = result.readString() + val id = bundle.getString(EXTRA_ERROR_STATUS) + val reason = bundle.getString(EXTRA_ERROR_MSG) SuspendedStorage.get(mContext).reportCrack(id ?: "nd", reason ?: "nr") } } - return result - } - - fun getPackagesSuspendedByWorkMode(root: Boolean): List<String> { - val argumentParcel: Parcel = obtainArgumentParcel() - try { - - argumentParcel.writeString(WorkModeAccessor.ACTION_GET_ALL_PACKAGES_SUSPENDED_BY_WORK_MODE) - val marshalledResult = launchRootProcess(root, - ByteArraySerializer.serialize(argumentParcel.marshall()))[0] - val result = deserialize(ByteArraySerializer.deserialize(marshalledResult)) - val data = result.createStringArrayList() - result.recycle() - return data ?: listOf() - } finally { - argumentParcel.recycle() - } } - fun apply(suspendList: Array<String>, listMode: ListMode, status: Status, root: Boolean) { - val argumentParcel: Parcel = obtainArgumentParcel() - try { - - argumentParcel.writeString(WorkModeAccessor.ACTION_APPLY) - argumentParcel.writeStringArray(suspendList) - argumentParcel.writeInt(when (listMode) { - ListMode.BLACKLIST -> 1 - ListMode.WHITELIST -> 2 - }) - argumentParcel.writeInt(when (status) { - Status.ON -> 1 - Status.OFF -> 2 - }) - val marshalledResult = launchRootProcess(root, - ByteArraySerializer.serialize(argumentParcel.marshall()))[0] - val result = deserialize(ByteArraySerializer.deserialize(marshalledResult)) - result.recycle() - } finally { - argumentParcel.recycle() - } - } - - private fun obtainArgumentParcel(): Parcel { - val argumentParcel: Parcel = Parcel.obtain() - argumentParcel.writeString(mLogPath) + fun apply(suspendList: Array<TransferableSuspendedApp>, listMode: ListMode, status: Status) { // Tell the trigger times and times to the server, it will disable the app automatically // #Anti-Crack val sp = SuspendedStorage.get(mContext).getStorage() val keys = sp.all.keys.stream() - .filter { - return@filter it.startsWith("c_") - } - .collect(Collectors.toList()) - val map = mutableMapOf<String, Int>() + .filter { + return@filter it.startsWith("c_") + } + .collect(Collectors.toList()) + val map = hashMapOf<String, Int>() for (key in keys) { try { val times = sp.getInt(key, -1) map[key] = times } catch (e: Throwable) {} } - argumentParcel.writeMap(map) - return argumentParcel + val dat = Bundle() + dat.putSerializable(EXTRA_DAT, map) + val result = mService.apply(dat, suspendList, + when (listMode) { + ListMode.BLACKLIST -> 1 + ListMode.WHITELIST -> 2 + }, + when (status) { + Status.ON -> 1 + Status.OFF -> 2 + }) + processError(result) + } + + fun getInstalledApplicationsAcrossUser(flags: Int): List<TransferableSuspendedApp> = + mService.getInstalledApplicationsAcrossUser(flags) + + fun release() { + mListener.release() + } + + fun isConnected(): Boolean = mService.asBinder().isBinderAlive + + fun suspend(packages: List<TransferableSuspendedApp>, suspended: Boolean): Array<String> = + setPackagesSuspended(packages, + suspended, + PersistableBundle(), + PersistableBundle(), // Removed because there is an unknown bug which prevents from writing launcher extras from the owner (?) + mContext.getString(R.string.suspended_message)) + + fun apply() { + val storage = SuspendedStorage.get(mContext) + val status = storage.getStatus() + val listMode = storage.getListMode() + val list = storage.getList() + .stream() + .map { + return@map it.copyToSimpleTransferableInfo() + } + .collect(Collectors.toList()) + apply(list.toTypedArray(), listMode, status) + TileService.requestListeningState(mContext, ComponentName(mContext, SuspendTile::class.java)) } }
\ No newline at end of file |