aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/moe/yuuta/sysuicontroller/core/root/ControllerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/moe/yuuta/sysuicontroller/core/root/ControllerService.java')
-rw-r--r--app/src/main/java/moe/yuuta/sysuicontroller/core/root/ControllerService.java215
1 files changed, 215 insertions, 0 deletions
diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/core/root/ControllerService.java b/app/src/main/java/moe/yuuta/sysuicontroller/core/root/ControllerService.java
new file mode 100644
index 0000000..63f6f08
--- /dev/null
+++ b/app/src/main/java/moe/yuuta/sysuicontroller/core/root/ControllerService.java
@@ -0,0 +1,215 @@
+package moe.yuuta.sysuicontroller.core.root;
+
+import android.annotation.SuppressLint;
+import android.app.ActivityThread;
+import android.app.StatusBarManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.statusbar.IStatusBarService;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import eu.chainfire.librootjava.IPCBroadcastHelper;
+import eu.chainfire.librootjava.RootIPC;
+import eu.chainfire.librootjava.RootJava;
+import eu.chainfire.librootjavadaemon.RootDaemon;
+import eu.chainfire.libsuperuser.Shell;
+import moe.yuuta.sysuicontroller.BuildConfig;
+import moe.yuuta.sysuicontroller.IStatusController;
+import moe.yuuta.sysuicontroller.core.CoreUtils;
+import moe.yuuta.sysuicontroller.core.DisableItem;
+import moe.yuuta.sysuicontroller.dump.StatusBarServiceDumpDeserializer;
+
+import static moe.yuuta.sysuicontroller.Main.GLOBAL_TAG;
+
+public class ControllerService extends IStatusController.Stub {
+ private static final String TAG = GLOBAL_TAG + ".ControllerService";
+
+ private int disableFlags = StatusBarManager.DISABLE_NONE;
+ private int disable2Flags = StatusBarManager.DISABLE2_NONE;
+
+ public static final int CODE_SERVICE = 0;
+ private StatusBarManager mManager;
+ private Context mContext;
+ private Intent mKeepWakeUpIntent;
+ private IStatusBarService mService;
+
+ public static void main (String... args) throws Throwable {
+ try {
+ new ControllerService().run(args);
+ } catch (Throwable throwable) {
+ Log.e(TAG, "FETAL EXCEPTION during init", throwable);
+ System.exit(throwable.hashCode());
+ }
+ }
+
+ @SuppressLint({"WrongConstant", "MissingPermission"})
+ private void run (String... args) throws Throwable {
+ Looper.prepare();
+ Log.i(TAG, "Version: " + BuildConfig.VERSION_CODE);
+ mContext = ActivityThread.systemMain().getSystemContext();
+ mManager = (StatusBarManager) mContext.getSystemService("statusbar");
+ @SuppressLint("PrivateApi") Method mGetService = StatusBarManager.class.getDeclaredMethod("getService");
+ mGetService.setAccessible(true);
+ mService = (IStatusBarService) mGetService.invoke(mManager);
+ RootDaemon.daemonize(BuildConfig.APPLICATION_ID, CODE_SERVICE, false, null);
+ RootJava.restoreOriginalLdLibraryPath();
+ RootDaemon.register(BuildConfig.APPLICATION_ID, this, CODE_SERVICE);
+ Log.i(TAG, "Started at " + new Date().toString());
+ RootIPC rootIPC;
+ try {
+ rootIPC = new RootIPC(BuildConfig.APPLICATION_ID, this, CODE_SERVICE,
+ 10 * 1000,
+ true);
+ } catch (RootIPC.TimeoutException e) {
+ Log.e(TAG, "Unable to establish a connection, exiting", e);
+ throw e;
+ }
+ mKeepWakeUpIntent = IPCBroadcastHelper.buildStickyBroadcastIntent(rootIPC);
+ mContext.sendStickyBroadcast(mKeepWakeUpIntent);
+ RootDaemon.run();
+ // Will be removed from exit() binder call, because this part may not be called.
+ Log.i(TAG, "Stopped at " + new Date().toString());
+ }
+
+ private void enforcePermission () throws SecurityException {
+ mContext.enforcePermission(BuildConfig.APPLICATION_ID + ".SERVICE",
+ Binder.getCallingPid(), Binder.getCallingUid(), "Permission denial");
+ }
+
+ @SuppressLint("MissingPermission")
+ @Override // Binder call
+ public void exit () throws RemoteException {
+ enforcePermission();
+ try {
+ if (mKeepWakeUpIntent != null) mContext.removeStickyBroadcast(mKeepWakeUpIntent);
+ } catch (Throwable e) {
+ Log.e(TAG, "Unable to remove sticky broadcast", e);
+ }
+ RootDaemon.exit();
+ }
+
+ @Override
+ public void disable(int flags) throws RemoteException {
+ enforcePermission();
+ disableFlags = flags;
+ mManager.disable(flags);
+ }
+
+ @Override
+ public void disable2(int flags) throws RemoteException {
+ enforcePermission();
+ disable2Flags = flags;
+ mManager.disable2(flags);
+ }
+
+ @Override
+ public void expandNotificationsPanel() throws RemoteException {
+ enforcePermission();
+ mManager.expandNotificationsPanel();
+ }
+
+ @Override
+ public void collapsePanels() throws RemoteException {
+ enforcePermission();
+ mManager.collapsePanels();
+ }
+
+ @Override
+ public void expandSettingsPanel(String subPanel) throws RemoteException {
+ enforcePermission();
+ mManager.expandSettingsPanel(subPanel);
+ }
+
+ @Override
+ public void setIcon(String slot, String packageName, int iconId, int iconLevel, String contentDescription) throws RemoteException {
+ enforcePermission();
+ mService.setIcon(slot, packageName, iconId, iconLevel, contentDescription);
+ }
+
+ @Override
+ public void removeIcon(String slot) throws RemoteException {
+ enforcePermission();
+ mManager.removeIcon(slot);
+ }
+
+ @Override
+ public void setIconVisibility(String slot, boolean visible) throws RemoteException {
+ enforcePermission();
+ mManager.setIconVisibility(slot, visible);
+ }
+
+ @Override
+ public int getDisableFlags() throws RemoteException {
+ enforcePermission();
+ // Deserialize at first
+ deserialize();
+ return disableFlags;
+ }
+
+ @Override
+ public int getDisable2Flags() throws RemoteException {
+ enforcePermission();
+ // Deserialize at first
+ deserialize();
+ return disable2Flags;
+ }
+
+ private void deserialize () {
+ try {
+ StringBuilder builder = new StringBuilder();
+ for (String res : Shell.SH.run(Collections.singletonList("dumpsys statusbar"))) {
+ builder.append(res);
+ builder.append("\n");
+ }
+ String result = builder.toString();
+ StatusBarServiceDumpDeserializer deserializer = CoreUtils.deserialize(result);
+ if (deserializer.getDisable1() != -1) disableFlags = deserializer.getDisable1();
+ if (deserializer.getDisable2() != -1) disable2Flags = deserializer.getDisable2();
+ } catch (Exception e) {
+ Log.e(TAG, "Error when dumping status bar service", e);
+ }
+ }
+
+ @Override
+ public List<DisableItem> getAvailableDisableItems() throws RemoteException {
+ Field[] fields = StatusBarManager.class.getDeclaredFields();
+ if (fields.length <= 0) return Collections.emptyList();
+ List<DisableItem> items = new ArrayList<>(fields.length);
+ for (Field field : fields) {
+ if (!Modifier.isStatic(field.getModifiers())) continue;
+ if (!Modifier.isFinal(field.getModifiers())) continue;
+ if (!Modifier.isPublic(field.getModifiers())) continue;
+ if (field.getName().equals("DISABLE_MASK") || field.getName().equals("DISABLE2_MASK")
+ || field.getName().equals("DISABLE_NONE") || field.getName().equals("DISABLE2_NONE")) continue;
+ try {
+ if (field.getName().startsWith("DISABLE_")) {
+ items.add(new DisableItem(field.getInt(null), field.getName(), false));
+ continue;
+ }
+ if (field.getName().startsWith("DISABLE2_")) {
+ items.add(new DisableItem(field.getInt(null), field.getName(), true));
+ }
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Unable to access value: " + field.getName(), e);
+ }
+ }
+ return items;
+ }
+
+ @Override
+ public int getDisableNoneFlag(boolean disable2) throws RemoteException {
+ return disable2 ? StatusBarManager.DISABLE2_NONE : StatusBarManager.DISABLE_NONE;
+ }
+}