241 lines
8.5 KiB
Diff
241 lines
8.5 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
|
Date: Sun, 31 Jul 2022 10:06:14 +0300
|
|
Subject: [PATCH] infrastructure for system_server extensions
|
|
|
|
---
|
|
.../server/ext/DelayedConditionalAction.java | 135 ++++++++++++++++++
|
|
.../android/server/ext/SystemServerExt.java | 58 ++++++++
|
|
.../java/com/android/server/SystemServer.java | 4 +-
|
|
3 files changed, 196 insertions(+), 1 deletion(-)
|
|
create mode 100644 services/core/java/com/android/server/ext/DelayedConditionalAction.java
|
|
create mode 100644 services/core/java/com/android/server/ext/SystemServerExt.java
|
|
|
|
diff --git a/services/core/java/com/android/server/ext/DelayedConditionalAction.java b/services/core/java/com/android/server/ext/DelayedConditionalAction.java
|
|
new file mode 100644
|
|
index 000000000000..d72f302e9d42
|
|
--- /dev/null
|
|
+++ b/services/core/java/com/android/server/ext/DelayedConditionalAction.java
|
|
@@ -0,0 +1,135 @@
|
|
+/*
|
|
+ * Copyright (C) 2022 GrapheneOS
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+package com.android.server.ext;
|
|
+
|
|
+import android.app.AlarmManager;
|
|
+import android.content.ContentResolver;
|
|
+import android.content.Context;
|
|
+import android.database.ContentObserver;
|
|
+import android.net.Uri;
|
|
+import android.os.Build;
|
|
+import android.os.Handler;
|
|
+import android.os.Looper;
|
|
+import android.os.SystemClock;
|
|
+import android.provider.Settings;
|
|
+import android.util.Slog;
|
|
+
|
|
+/**
|
|
+ * Infrastructure for actions that:
|
|
+ * - happen after a user-configurable device-wide (Settings.Global) delay
|
|
+ * - need to be taken even when the device is in deep sleep
|
|
+ * - need to be rescheduled based on some listenable event
|
|
+ */
|
|
+public abstract class DelayedConditionalAction {
|
|
+ private static final String TAG = "DelayedConditionalAction";
|
|
+
|
|
+ protected final SystemServerExt sse;
|
|
+ protected final Thread thread;
|
|
+ protected final Handler handler;
|
|
+
|
|
+ protected final ContentResolver contentResolver;
|
|
+ protected final AlarmManager alarmManager;
|
|
+ private final AlarmManager.OnAlarmListener alarmListener;
|
|
+
|
|
+ protected DelayedConditionalAction(SystemServerExt sse, Handler handler) {
|
|
+ this.sse = sse;
|
|
+
|
|
+ Looper looper = handler.getLooper();
|
|
+ thread = looper.getThread();
|
|
+ this.handler = handler;
|
|
+
|
|
+ if (Build.isDebuggable()) {
|
|
+ if (thread != Thread.currentThread()) {
|
|
+ throw new IllegalStateException("all calls should happen on the same thread");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ Context ctx = sse.context;
|
|
+ contentResolver = ctx.getContentResolver();
|
|
+ alarmManager = ctx.getSystemService(AlarmManager.class);
|
|
+
|
|
+ alarmListener = () -> {
|
|
+ if (delayDurationMillis() == 0) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ alarmTriggered();
|
|
+ };
|
|
+
|
|
+ registerStateListener();
|
|
+
|
|
+ Uri delaySettingUri = Settings.Global.getUriFor(getDelayGlobalSettingsKey());
|
|
+
|
|
+ ContentObserver delayChangeListener = new ContentObserver(handler) {
|
|
+ @Override
|
|
+ public void onChange(boolean selfChange) {
|
|
+ update();
|
|
+ }
|
|
+ };
|
|
+
|
|
+ contentResolver.registerContentObserver(delaySettingUri, false, delayChangeListener);
|
|
+ }
|
|
+
|
|
+ private boolean alarmScheduled;
|
|
+
|
|
+ protected final void update() {
|
|
+ final Thread curThread = Thread.currentThread();
|
|
+ if (curThread != thread) {
|
|
+ String msg = "update() called on an unknown thread " + curThread;
|
|
+ if (Build.isDebuggable()) {
|
|
+ throw new IllegalStateException(msg);
|
|
+ } else {
|
|
+ Slog.e(TAG, msg, new Throwable());
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (alarmScheduled) {
|
|
+ alarmManager.cancel(alarmListener);
|
|
+ alarmScheduled = false;
|
|
+ }
|
|
+
|
|
+ if (!shouldScheduleAlarm()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ long delayMillis = delayDurationMillis();
|
|
+
|
|
+ if (delayMillis == 0) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ final long triggerAt = SystemClock.elapsedRealtime() + delayMillis;
|
|
+ alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAt,
|
|
+ getClass().getName(), alarmListener, handler);
|
|
+ alarmScheduled = true;
|
|
+ }
|
|
+
|
|
+ private long delayDurationMillis() {
|
|
+ return Settings.Global.getLong(contentResolver, getDelayGlobalSettingsKey(), 0);
|
|
+ }
|
|
+
|
|
+ // Make sure to use the same Handler that is used for all other callbacks;
|
|
+ // call update() to reschedule / cancel the alarm
|
|
+ protected abstract void registerStateListener();
|
|
+
|
|
+ protected abstract boolean shouldScheduleAlarm();
|
|
+ protected abstract void alarmTriggered();
|
|
+
|
|
+ // android.provider.Settings.Global key
|
|
+ protected abstract String getDelayGlobalSettingsKey();
|
|
+}
|
|
diff --git a/services/core/java/com/android/server/ext/SystemServerExt.java b/services/core/java/com/android/server/ext/SystemServerExt.java
|
|
new file mode 100644
|
|
index 000000000000..83d895650473
|
|
--- /dev/null
|
|
+++ b/services/core/java/com/android/server/ext/SystemServerExt.java
|
|
@@ -0,0 +1,58 @@
|
|
+/*
|
|
+ * Copyright (C) 2022 GrapheneOS
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+package com.android.server.ext;
|
|
+
|
|
+import android.content.BroadcastReceiver;
|
|
+import android.content.Context;
|
|
+import android.content.IntentFilter;
|
|
+import android.os.Handler;
|
|
+
|
|
+import com.android.internal.os.BackgroundThread;
|
|
+import com.android.server.pm.PackageManagerService;
|
|
+
|
|
+public final class SystemServerExt {
|
|
+
|
|
+ public final Context context;
|
|
+ public final Handler bgHandler;
|
|
+ public final PackageManagerService packageManager;
|
|
+
|
|
+ private SystemServerExt(Context systemContext, PackageManagerService pm) {
|
|
+ context = systemContext;
|
|
+ bgHandler = BackgroundThread.getHandler();
|
|
+ packageManager = pm;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ Called after system server has completed its initialization,
|
|
+ but before any of the apps are started.
|
|
+
|
|
+ Call from com.android.server.SystemServer#startOtherServices(), at the end of lambda
|
|
+ that is passed into mActivityManagerService.systemReady()
|
|
+ */
|
|
+ public static void init(Context systemContext, PackageManagerService pm) {
|
|
+ SystemServerExt sse = new SystemServerExt(systemContext, pm);
|
|
+ sse.bgHandler.post(sse::initBgThread);
|
|
+ }
|
|
+
|
|
+ void initBgThread() {
|
|
+
|
|
+ }
|
|
+
|
|
+ public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, Handler handler) {
|
|
+ context.registerReceiver(receiver, filter, null, handler);
|
|
+ }
|
|
+}
|
|
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
|
|
index aa6918451fc1..960d7ae2eba9 100644
|
|
--- a/services/java/com/android/server/SystemServer.java
|
|
+++ b/services/java/com/android/server/SystemServer.java
|
|
@@ -2223,7 +2223,7 @@ public final class SystemServer implements Dumpable {
|
|
Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
|
|
}
|
|
t.traceEnd();
|
|
-
|
|
+
|
|
if (!isWatch) {
|
|
t.traceBegin("StartTwilightService");
|
|
mSystemServiceManager.startService(TwilightService.class);
|
|
@@ -3062,6 +3062,8 @@ public final class SystemServer implements Dumpable {
|
|
reportWtf("Triggering OdsignStatsLogger", e);
|
|
}
|
|
t.traceEnd();
|
|
+
|
|
+ com.android.server.ext.SystemServerExt.init(mSystemContext, mPackageManagerService);
|
|
}, t);
|
|
|
|
t.traceBegin("StartSystemUI");
|