009: Closure wave 3 deblob, handoff, and optional wave4/malloc bacons.
Ship script gates wave 4 behind AXP_DEBLOB_WAVE4, documents secrets cert path, and adds deblob appliers plus tests; docs capture Swissquote fix and parity. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
deaaf42caa
commit
3f941e8451
64 files changed
+6270
-86
No files matched your search
@@ -38,8 +38,23 @@ def backup(path: Path) -> None:
|
||||
def patch_computer_engine() -> None:
|
||||
path = TREE / "frameworks/base/services/core/java/com/android/server/pm/ComputerEngine.java"
|
||||
text = path.read_text()
|
||||
# AXP/EXTENDROM spoofs on user images (GOLDEN ro.debuggable=0). LOS stock
|
||||
# isDebuggable() would disable that on lineage_sunfish-user.
|
||||
deb_gate = """ public static boolean isMicrogSigned(AndroidPackage p) {
|
||||
if (!isDebuggable()) {
|
||||
return false;
|
||||
}
|
||||
"""
|
||||
user_ok = """ public static boolean isMicrogSigned(AndroidPackage p) {
|
||||
// %s: no isDebuggable() gate (AXP user / GOLDEN).
|
||||
""" % MARKER
|
||||
if MARKER in text:
|
||||
print("ComputerEngine: already patched")
|
||||
if deb_gate not in text:
|
||||
print("ComputerEngine: already patched, user gate ok")
|
||||
return
|
||||
backup(path)
|
||||
path.write_text(text.replace(deb_gate, user_ok, 1))
|
||||
print("ComputerEngine: dropped isDebuggable gate")
|
||||
return
|
||||
backup(path)
|
||||
|
||||
@@ -78,9 +93,7 @@ def patch_computer_engine() -> None:
|
||||
}"""
|
||||
|
||||
new_is = """ public static boolean isMicrogSigned(AndroidPackage p) {
|
||||
if (!isDebuggable()) {
|
||||
return false;
|
||||
}
|
||||
// SUNFISH_A16_005_SIGSPOOF: no isDebuggable() gate (AXP user / GOLDEN).
|
||||
|
||||
// Allowlist the following apps:
|
||||
// * com.android.vending - microG Companion / patched Phonesky
|
||||
|
||||
Vendored
+153
@@ -0,0 +1,153 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: anupritaisno1 <www.anuprita804@gmail.com>
|
||||
Date: Mon, 18 Oct 2021 01:35:40 +0300
|
||||
Subject: [PATCH] automatically reboot device after timeout if set
|
||||
|
||||
Signed-off-by: anupritaisno1 <www.anuprita804@gmail.com>
|
||||
Change-Id: If891bfbcc144c9336ba013260bad2b7c7a59c054
|
||||
---
|
||||
core/java/android/provider/Settings.java | 7 ++++
|
||||
data/etc/com.android.systemui.xml | 1 +
|
||||
packages/SystemUI/AndroidManifest.xml | 3 ++
|
||||
.../keyguard/KeyguardViewMediator.java | 35 +++++++++++++++++++
|
||||
4 files changed, 46 insertions(+)
|
||||
|
||||
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
|
||||
index 783483d8e491..48913891ac52 100644
|
||||
--- a/core/java/android/provider/Settings.java
|
||||
+++ b/core/java/android/provider/Settings.java
|
||||
@@ -19027,6 +19027,13 @@ public final class Settings {
|
||||
public static final String REVIEW_PERMISSIONS_NOTIFICATION_STATE =
|
||||
"review_permissions_notification_state";
|
||||
|
||||
+ /**
|
||||
+ * Whether to automatically reboot the device after a user defined timeout
|
||||
+ *
|
||||
+ * @hide
|
||||
+ */
|
||||
+ public static final String SETTINGS_REBOOT_AFTER_TIMEOUT = "settings_reboot_after_timeout";
|
||||
+
|
||||
/**
|
||||
* Whether repair mode is active on the device.
|
||||
* <p>
|
||||
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
|
||||
index ce2543a47cf5..67108d16e099 100644
|
||||
--- a/data/etc/com.android.systemui.xml
|
||||
+++ b/data/etc/com.android.systemui.xml
|
||||
@@ -54,6 +54,7 @@
|
||||
<permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
|
||||
<permission name="android.permission.READ_WALLPAPER_INTERNAL"/>
|
||||
<permission name="android.permission.REAL_GET_TASKS"/>
|
||||
+ <permission name="android.permission.REBOOT"/>
|
||||
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
||||
<permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
|
||||
<permission name="android.permission.SATELLITE_COMMUNICATION"/>
|
||||
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
|
||||
index 351cce0929b7..00604a316019 100644
|
||||
--- a/packages/SystemUI/AndroidManifest.xml
|
||||
+++ b/packages/SystemUI/AndroidManifest.xml
|
||||
@@ -356,6 +356,9 @@
|
||||
|
||||
<uses-permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
|
||||
|
||||
+ <!-- Permission to allow rebooting the device after a user configurable amount of time -->
|
||||
+ <uses-permission android:name="android.permission.REBOOT" />
|
||||
+
|
||||
<uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" />
|
||||
|
||||
<uses-permission android:name="android.permission.MONITOR_STICKY_MODIFIER_STATE" />
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
|
||||
index 6034e92be873..67dd84e8ae8f 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
|
||||
@@ -240,6 +240,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
|
||||
private final static String TAG = "KeyguardViewMediator";
|
||||
|
||||
+ private static final String DELAYED_REBOOT_ACTION =
|
||||
+ "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_REBOOT";
|
||||
public static final String DELAYED_KEYGUARD_ACTION =
|
||||
"com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
|
||||
private static final String DELAYED_LOCK_PROFILE_ACTION =
|
||||
@@ -417,6 +419,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
*/
|
||||
private int mDelayedProfileShowingSequence;
|
||||
|
||||
+ /**
|
||||
+ * Same as {@link #mDelayedProfileShowingSequence}, but used for our reboot implementation
|
||||
+ */
|
||||
+ private int mDelayedRebootSequence;
|
||||
+
|
||||
private final DismissCallbackRegistry mDismissCallbackRegistry;
|
||||
|
||||
// the properties of the keyguard
|
||||
@@ -1503,6 +1510,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
final IntentFilter delayedActionFilter = new IntentFilter();
|
||||
delayedActionFilter.addAction(DELAYED_KEYGUARD_ACTION);
|
||||
delayedActionFilter.addAction(DELAYED_LOCK_PROFILE_ACTION);
|
||||
+ delayedActionFilter.addAction(DELAYED_REBOOT_ACTION);
|
||||
delayedActionFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
|
||||
mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
|
||||
SYSTEMUI_PERMISSION, null /* scheduler */,
|
||||
@@ -1866,6 +1874,18 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
}
|
||||
}
|
||||
|
||||
+ private void doRebootForOwnerAfterTimeoutIfEnabled(long rebootAfterTimeout) {
|
||||
+ long when = mSystemClock.elapsedRealtime() + rebootAfterTimeout;
|
||||
+ Intent rebootIntent = new Intent(DELAYED_REBOOT_ACTION);
|
||||
+ rebootIntent.putExtra("seq", mDelayedRebootSequence);
|
||||
+ rebootIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
+ PendingIntent sender = PendingIntent.getBroadcast(mContext,
|
||||
+ 0, rebootIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
+ mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
|
||||
+ if (DEBUG) Log.d(TAG, "setting alarm to reboot device, timeout = "
|
||||
+ + String.valueOf(rebootAfterTimeout));
|
||||
+ }
|
||||
+
|
||||
private void doKeyguardForChildProfilesLocked() {
|
||||
for (UserInfo profile : mUserTracker.getUserProfiles()) {
|
||||
if (!profile.isEnabled()) continue;
|
||||
@@ -1884,6 +1904,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
mDelayedProfileShowingSequence++;
|
||||
}
|
||||
|
||||
+ private void cancelDoRebootForOwnerAfterTimeoutIfEnabled() {
|
||||
+ mDelayedRebootSequence++;
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* It will let us know when the device is waking up.
|
||||
*/
|
||||
@@ -2298,6 +2322,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
|
||||
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
|
||||
showKeyguard(options);
|
||||
+ final long rebootAfterTimeout = Settings.Global.getLong(mContext.getContentResolver(), Settings.Global.SETTINGS_REBOOT_AFTER_TIMEOUT, 0);
|
||||
+ if (rebootAfterTimeout >= 1) {
|
||||
+ doRebootForOwnerAfterTimeoutIfEnabled(rebootAfterTimeout);
|
||||
+ }
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@@ -2478,6 +2506,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
}
|
||||
}
|
||||
}
|
||||
+ } else if (DELAYED_REBOOT_ACTION.equals(intent.getAction())) {
|
||||
+ final int sequence = intent.getIntExtra("seq", 0);
|
||||
+ if (sequence == mDelayedRebootSequence) {
|
||||
+ PowerManager pm = mContext.getSystemService(PowerManager.class);
|
||||
+ pm.reboot(null);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -3200,6 +3234,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
mHideAnimationRun = false;
|
||||
adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
+ cancelDoRebootForOwnerAfterTimeoutIfEnabled();
|
||||
}
|
||||
|
||||
private Configuration.Builder createInteractionJankMonitorConf(int cuj) {
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Tue, 6 Sep 2022 16:48:26 +0300
|
||||
Subject: [PATCH] bugfix: Bluetooth auto turn off ignored connected BLE devices
|
||||
|
||||
Previous attempt at fixing this didn't work properly, because getConnectionStateLeAware() didn't
|
||||
actually report BLE state.
|
||||
---
|
||||
.../android/server/ext/BluetoothAutoOff.java | 20 ++++++++++++++-----
|
||||
1 file changed, 15 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/ext/BluetoothAutoOff.java b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
index 4e7dbc042f37..a091b006214f 100644
|
||||
--- a/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
+++ b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
@@ -3,6 +3,7 @@ package com.android.server.ext;
|
||||
import android.annotation.Nullable;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
+import android.bluetooth.BluetoothProfile;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -12,12 +13,14 @@ import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
|
||||
class BluetoothAutoOff extends DelayedConditionalAction {
|
||||
+ private final BluetoothManager manager;
|
||||
@Nullable
|
||||
private final BluetoothAdapter adapter;
|
||||
|
||||
BluetoothAutoOff(SystemServerExt sse) {
|
||||
super(sse, sse.bgHandler);
|
||||
- adapter = sse.context.getSystemService(BluetoothManager.class).getAdapter();
|
||||
+ manager = sse.context.getSystemService(BluetoothManager.class);
|
||||
+ adapter = manager.getAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,11 +54,18 @@ class BluetoothAutoOff extends DelayedConditionalAction {
|
||||
|
||||
private boolean isAdapterOnAndDisconnected() {
|
||||
if (adapter != null) {
|
||||
- int state = adapter.getLeStateSysApi(); // getState() converts BLE states into STATE_OFF
|
||||
+ if (adapter.isLeEnabled()) {
|
||||
+ if (adapter.getConnectionState() == BluetoothAdapter.STATE_DISCONNECTED) {
|
||||
+ // Bluetooth GATT Profile (Bluetooth LE) connection state is ignored
|
||||
+ // by getConnectionState()
|
||||
+ return manager.getConnectedDevices(BluetoothProfile.GATT).size() == 0;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) {
|
||||
- // getConnectionState() converts BLE states into STATE_DISCONNECTED
|
||||
- return adapter.getConnectionStateLeAware() == BluetoothAdapter.STATE_DISCONNECTED;
|
||||
+ // isLeEnabled() currently implies isEnabled(), but check again anyway in case
|
||||
+ // this changes in the future
|
||||
+ if (adapter.isEnabled()) {
|
||||
+ return adapter.getConnectionState() == BluetoothAdapter.STATE_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Sun, 31 Jul 2022 11:19:33 +0300
|
||||
Subject: [PATCH] Bluetooth auto turn off
|
||||
|
||||
Co-authored-by: Pratyush <codelab@pratyush.dev>
|
||||
---
|
||||
core/java/android/provider/Settings.java | 6 ++
|
||||
.../android/server/ext/BluetoothAutoOff.java | 69 +++++++++++++++++++
|
||||
.../android/server/ext/SystemServerExt.java | 4 ++
|
||||
3 files changed, 79 insertions(+)
|
||||
create mode 100644 services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
|
||||
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
|
||||
index 49f59950b9e0..58f1077af988 100644
|
||||
--- a/core/java/android/provider/Settings.java
|
||||
+++ b/core/java/android/provider/Settings.java
|
||||
@@ -19549,6 +19549,12 @@ public final class Settings {
|
||||
*/
|
||||
public static final String WIFI_OFF_TIMEOUT = "wifi_off_timeout";
|
||||
|
||||
+ /**
|
||||
+ * The amount of time in milliseconds before a disconnected Bluetooth adapter is turned off
|
||||
+ * @hide
|
||||
+ */
|
||||
+ public static final String BLUETOOTH_OFF_TIMEOUT = "bluetooth_off_timeout";
|
||||
+
|
||||
/**
|
||||
* Whether repair mode is active on the device.
|
||||
* <p>
|
||||
diff --git a/services/core/java/com/android/server/ext/BluetoothAutoOff.java b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
new file mode 100644
|
||||
index 000000000000..4e7dbc042f37
|
||||
--- /dev/null
|
||||
+++ b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
@@ -0,0 +1,69 @@
|
||||
+package com.android.server.ext;
|
||||
+
|
||||
+import android.annotation.Nullable;
|
||||
+import android.bluetooth.BluetoothAdapter;
|
||||
+import android.bluetooth.BluetoothManager;
|
||||
+import android.content.BroadcastReceiver;
|
||||
+import android.content.Context;
|
||||
+import android.content.Intent;
|
||||
+import android.content.IntentFilter;
|
||||
+import android.os.Build;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Slog;
|
||||
+
|
||||
+class BluetoothAutoOff extends DelayedConditionalAction {
|
||||
+ @Nullable
|
||||
+ private final BluetoothAdapter adapter;
|
||||
+
|
||||
+ BluetoothAutoOff(SystemServerExt sse) {
|
||||
+ super(sse, sse.bgHandler);
|
||||
+ adapter = sse.context.getSystemService(BluetoothManager.class).getAdapter();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected boolean shouldScheduleAlarm() {
|
||||
+ return isAdapterOnAndDisconnected();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void alarmTriggered() {
|
||||
+ if (isAdapterOnAndDisconnected()) {
|
||||
+ adapter.disable();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void registerStateListener() {
|
||||
+ IntentFilter f = new IntentFilter();
|
||||
+ f.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
+ f.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
|
||||
+
|
||||
+ sse.registerReceiver(new BroadcastReceiver() {
|
||||
+ @Override
|
||||
+ public void onReceive(Context broadcastContext, Intent intent) {
|
||||
+ if (Build.isDebuggable()) {
|
||||
+ Slog.d("BtAutoOff", "" + intent + ", extras " + intent.getExtras().deepCopy());
|
||||
+ }
|
||||
+ update();
|
||||
+ }
|
||||
+ }, f, handler);
|
||||
+ }
|
||||
+
|
||||
+ private boolean isAdapterOnAndDisconnected() {
|
||||
+ if (adapter != null) {
|
||||
+ int state = adapter.getLeStateSysApi(); // getState() converts BLE states into STATE_OFF
|
||||
+
|
||||
+ if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) {
|
||||
+ // getConnectionState() converts BLE states into STATE_DISCONNECTED
|
||||
+ return adapter.getConnectionStateLeAware() == BluetoothAdapter.STATE_DISCONNECTED;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String getDelayGlobalSettingsKey() {
|
||||
+ return Settings.Global.BLUETOOTH_OFF_TIMEOUT;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/services/core/java/com/android/server/ext/SystemServerExt.java b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
index 66350e2b7f74..3c341ed25f4e 100644
|
||||
--- a/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
+++ b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
@@ -53,6 +53,10 @@ public final class SystemServerExt {
|
||||
if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI, 0)) {
|
||||
new WifiAutoOff(this);
|
||||
}
|
||||
+
|
||||
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH, 0)) {
|
||||
+ new BluetoothAutoOff(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, Handler handler) {
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
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 | 2 +
|
||||
3 files changed, 195 insertions(+)
|
||||
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 e92ba3ed7dc3..df60c628ccdb 100644
|
||||
--- a/services/java/com/android/server/SystemServer.java
|
||||
+++ b/services/java/com/android/server/SystemServer.java
|
||||
@@ -3454,6 +3454,8 @@ public final class SystemServer implements Dumpable {
|
||||
reportWtf("Triggering OdsignStatsLogger", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
+
|
||||
+ com.android.server.ext.SystemServerExt.init(mSystemContext, mPackageManagerService);
|
||||
}, t);
|
||||
|
||||
t.traceBegin("LockSettingsThirdPartyAppsStarted");
|
||||
Vendored
+128
@@ -0,0 +1,128 @@
|
||||
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] Wi-Fi auto turn off
|
||||
|
||||
Co-authored-by: Pratyush <codelab@pratyush.dev>
|
||||
---
|
||||
core/java/android/provider/Settings.java | 6 ++
|
||||
.../android/server/ext/SystemServerExt.java | 5 +-
|
||||
.../com/android/server/ext/WifiAutoOff.java | 69 +++++++++++++++++++
|
||||
3 files changed, 79 insertions(+), 1 deletion(-)
|
||||
create mode 100644 services/core/java/com/android/server/ext/WifiAutoOff.java
|
||||
|
||||
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
|
||||
index 10efaa78e435..49f59950b9e0 100644
|
||||
--- a/core/java/android/provider/Settings.java
|
||||
+++ b/core/java/android/provider/Settings.java
|
||||
@@ -19543,6 +19543,12 @@ public final class Settings {
|
||||
*/
|
||||
public static final String SETTINGS_REBOOT_AFTER_TIMEOUT = "settings_reboot_after_timeout";
|
||||
|
||||
+ /**
|
||||
+ * The amount of time in milliseconds before a disconnected Wi-Fi adapter is turned off
|
||||
+ * @hide
|
||||
+ */
|
||||
+ public static final String WIFI_OFF_TIMEOUT = "wifi_off_timeout";
|
||||
+
|
||||
/**
|
||||
* Whether repair mode is active on the device.
|
||||
* <p>
|
||||
diff --git a/services/core/java/com/android/server/ext/SystemServerExt.java b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
index 83d895650473..66350e2b7f74 100644
|
||||
--- a/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
+++ b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
@@ -19,6 +19,7 @@ package com.android.server.ext;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
+import android.content.pm.PackageManager;
|
||||
import android.os.Handler;
|
||||
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
@@ -49,7 +50,9 @@ public final class SystemServerExt {
|
||||
}
|
||||
|
||||
void initBgThread() {
|
||||
-
|
||||
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI, 0)) {
|
||||
+ new WifiAutoOff(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, Handler handler) {
|
||||
diff --git a/services/core/java/com/android/server/ext/WifiAutoOff.java b/services/core/java/com/android/server/ext/WifiAutoOff.java
|
||||
new file mode 100644
|
||||
index 000000000000..c7a3c05fe766
|
||||
--- /dev/null
|
||||
+++ b/services/core/java/com/android/server/ext/WifiAutoOff.java
|
||||
@@ -0,0 +1,69 @@
|
||||
+package com.android.server.ext;
|
||||
+
|
||||
+import android.content.BroadcastReceiver;
|
||||
+import android.content.Context;
|
||||
+import android.content.Intent;
|
||||
+import android.content.IntentFilter;
|
||||
+import android.net.wifi.WifiInfo;
|
||||
+import android.net.wifi.WifiManager;
|
||||
+import android.os.Build;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Slog;
|
||||
+
|
||||
+class WifiAutoOff extends DelayedConditionalAction {
|
||||
+ private final WifiManager wifiManager;
|
||||
+
|
||||
+ WifiAutoOff(SystemServerExt sse) {
|
||||
+ super(sse, sse.bgHandler);
|
||||
+ wifiManager = sse.context.getSystemService(WifiManager.class);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected boolean shouldScheduleAlarm() {
|
||||
+ return isWifiEnabledAndNotConnected();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void alarmTriggered() {
|
||||
+ if (isWifiEnabledAndNotConnected()) {
|
||||
+ wifiManager.setWifiEnabled(false);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private boolean isWifiEnabledAndNotConnected() {
|
||||
+ if (wifiManager.isWifiEnabled()) {
|
||||
+ WifiInfo i = wifiManager.getConnectionInfo();
|
||||
+ if (i == null) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ return i.getBSSID() == null;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void registerStateListener() {
|
||||
+ IntentFilter f = new IntentFilter();
|
||||
+ f.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||
+ f.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
+ // ConnectivityManager APIs seem unfit for listening to Wi-Fi state specifically, they look
|
||||
+ // to be higher level than that, eg VPN over Wi-Fi isn't considered to be a Wi-Fi connection
|
||||
+ // by ConnectivityManager
|
||||
+
|
||||
+ sse.registerReceiver(new BroadcastReceiver() {
|
||||
+ @Override
|
||||
+ public void onReceive(Context context, Intent intent) {
|
||||
+ if (Build.isDebuggable()) {
|
||||
+ Slog.d("WifiAutoOff", "" + intent + ", extras " + intent.getExtras().deepCopy());
|
||||
+ }
|
||||
+ update();
|
||||
+ }
|
||||
+ }, f, handler);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String getDelayGlobalSettingsKey() {
|
||||
+ return Settings.Global.WIFI_OFF_TIMEOUT;
|
||||
+ }
|
||||
+}
|
||||
Vendored
+141
@@ -0,0 +1,141 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Mon, 11 Mar 2024 19:40:18 +0200
|
||||
Subject: [PATCH] SystemUI: require unlocking to use QS tiles by default
|
||||
|
||||
---
|
||||
.../src/com/android/systemui/qs/QSHost.java | 1 +
|
||||
.../com/android/systemui/qs/QSHostAdapter.kt | 4 +++
|
||||
.../systemui/qs/tileimpl/QSTileImpl.java | 36 +++++++++++++++++--
|
||||
.../systemui/qs/QSHostAdapterKosmos.kt | 2 ++
|
||||
4 files changed, 40 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
|
||||
index 7c7f48e0d37b..87e87348d0f2 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
|
||||
@@ -51,6 +51,7 @@ public interface QSHost {
|
||||
Context getUserContext();
|
||||
int getUserId();
|
||||
Collection<QSTile> getTiles();
|
||||
+ com.android.systemui.statusbar.policy.KeyguardStateController getKeyguardStateController();
|
||||
void addCallback(Callback callback);
|
||||
void removeCallback(Callback callback);
|
||||
void removeTile(String tileSpec);
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
|
||||
index dc3b58247152..08f3fc9d7bdb 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
|
||||
@@ -31,6 +31,7 @@ import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
|
||||
import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
|
||||
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||
import com.android.systemui.shade.ShadeDisplayAware
|
||||
+import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -53,6 +54,7 @@ constructor(
|
||||
@ShadeDisplayAware private val context: Context,
|
||||
private val tileServiceRequestControllerBuilder: TileServiceRequestController.Builder,
|
||||
@Application private val scope: CoroutineScope,
|
||||
+ private val keyguardStateController_: KeyguardStateController,
|
||||
dumpManager: DumpManager,
|
||||
) : QSHost {
|
||||
|
||||
@@ -72,6 +74,8 @@ constructor(
|
||||
return interactor.currentQSTiles
|
||||
}
|
||||
|
||||
+ override fun getKeyguardStateController() = keyguardStateController_
|
||||
+
|
||||
override fun getSpecs(): List<String> {
|
||||
return interactor.currentTilesSpecs.map { it.spec }
|
||||
}
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
|
||||
index 1d1e9911884c..e9dc57e4c47d 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
|
||||
@@ -71,6 +71,7 @@ import com.android.systemui.qs.QsEventLogger;
|
||||
import com.android.systemui.qs.SideLabelTileLayout;
|
||||
import com.android.systemui.qs.flags.QsInCompose;
|
||||
import com.android.systemui.qs.logging.QSLogger;
|
||||
+import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Objects;
|
||||
@@ -272,6 +273,32 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
||||
return true;
|
||||
}
|
||||
|
||||
+ public enum Action {
|
||||
+ CLICK,
|
||||
+ SECONDARY_CLICK,
|
||||
+ LONG_CLICK,
|
||||
+ }
|
||||
+
|
||||
+ public boolean isAllowedWhenLocked(Action action) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ void handleAction(Action action, Runnable handler) {
|
||||
+ if (isAllowedWhenLocked(action)) {
|
||||
+ handler.run();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ KeyguardStateController ksc = mHost.getKeyguardStateController();
|
||||
+ boolean hasSecureKeyguard = ksc.isMethodSecure() && ksc.isShowing();
|
||||
+
|
||||
+ if (hasSecureKeyguard) {
|
||||
+ mActivityStarter.postQSRunnableDismissingKeyguard(handler);
|
||||
+ } else {
|
||||
+ handler.run();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
// safe to call from any thread
|
||||
|
||||
public void addCallback(Callback callback) {
|
||||
@@ -616,16 +643,19 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
||||
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
|
||||
} else {
|
||||
mQSLogger.logHandleClick(mTileSpec, msg.arg1);
|
||||
- handleClick((Expandable) msg.obj);
|
||||
+ Expandable view = (Expandable) msg.obj;
|
||||
+ handleAction(Action.CLICK, () -> handleClick(view));
|
||||
}
|
||||
} else if (msg.what == SECONDARY_CLICK) {
|
||||
name = "handleSecondaryClick";
|
||||
mQSLogger.logHandleSecondaryClick(mTileSpec, msg.arg1);
|
||||
- handleSecondaryClick((Expandable) msg.obj);
|
||||
+ Expandable view = (Expandable) msg.obj;
|
||||
+ handleAction(Action.SECONDARY_CLICK, () -> handleSecondaryClick(view));
|
||||
} else if (msg.what == LONG_CLICK) {
|
||||
name = "handleLongClick";
|
||||
mQSLogger.logHandleLongClick(mTileSpec, msg.arg1);
|
||||
- handleLongClick((Expandable) msg.obj);
|
||||
+ Expandable view = (Expandable) msg.obj;
|
||||
+ handleAction(Action.LONG_CLICK, () -> handleLongClick(view));
|
||||
} else if (msg.what == REFRESH_STATE) {
|
||||
name = "handleRefreshState";
|
||||
handleRefreshState(msg.obj);
|
||||
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt
|
||||
index 0bf801b35ad1..7cb93459077c 100644
|
||||
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt
|
||||
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt
|
||||
@@ -22,6 +22,7 @@ import com.android.systemui.kosmos.Kosmos
|
||||
import com.android.systemui.kosmos.applicationCoroutineScope
|
||||
import com.android.systemui.qs.external.tileServiceRequestControllerBuilder
|
||||
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
|
||||
+import com.android.systemui.statusbar.policy.keyguardStateController
|
||||
|
||||
val Kosmos.qsHostAdapter by
|
||||
Kosmos.Fixture {
|
||||
@@ -30,6 +31,7 @@ val Kosmos.qsHostAdapter by
|
||||
applicationContext,
|
||||
tileServiceRequestControllerBuilder,
|
||||
applicationCoroutineScope,
|
||||
+ keyguardStateController,
|
||||
dumpManager,
|
||||
)
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: pratyush <codelab@pratyush.dev>
|
||||
Date: Mon, 7 Jun 2021 22:15:59 +0100
|
||||
Subject: [PATCH] add auto-reboot setting
|
||||
|
||||
---
|
||||
res/values/arrays.xml | 31 +++++++
|
||||
res/values/strings.xml | 3 +
|
||||
res/xml/security_dashboard_settings.xml | 10 ++-
|
||||
.../AutoRebootPreferenceController.java | 82 +++++++++++++++++++
|
||||
.../settings/security/SecuritySettings.java | 1 +
|
||||
5 files changed, 126 insertions(+), 1 deletion(-)
|
||||
create mode 100644 src/com/android/settings/security/AutoRebootPreferenceController.java
|
||||
|
||||
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
|
||||
index febdb0412a4..c5df677975d 100644
|
||||
--- a/res/values/arrays.xml
|
||||
+++ b/res/values/arrays.xml
|
||||
@@ -105,6 +105,37 @@
|
||||
<item>1800000</item>
|
||||
</string-array>
|
||||
|
||||
+ <!-- Auto reboot settings -->
|
||||
+ <string-array name="auto_reboot_entries">
|
||||
+ <item>Off</item>
|
||||
+ <item>10 minutes</item>
|
||||
+ <item>30 minutes</item>
|
||||
+ <item>1 hour</item>
|
||||
+ <item>2 hours</item>
|
||||
+ <item>4 hours</item>
|
||||
+ <item>8 hours</item>
|
||||
+ <item>12 hours</item>
|
||||
+ <item>24 hours</item>
|
||||
+ <item>36 hours</item>
|
||||
+ <item>48 hours</item>
|
||||
+ <item>72 hours</item>
|
||||
+ </string-array>
|
||||
+
|
||||
+ <string-array name="auto_reboot_values" translatable="false">
|
||||
+ <item>0</item> <!-- Disabled -->
|
||||
+ <item>600000</item>
|
||||
+ <item>1800000</item>
|
||||
+ <item>3600000</item>
|
||||
+ <item>7200000</item>
|
||||
+ <item>14400000</item>
|
||||
+ <item>28800000</item>
|
||||
+ <item>43200000</item>
|
||||
+ <item>86400000</item>
|
||||
+ <item>129600000</item>
|
||||
+ <item>172800000</item>
|
||||
+ <item>259200000</item>
|
||||
+ </string-array>
|
||||
+
|
||||
<!-- Wi-Fi settings -->
|
||||
|
||||
<!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
|
||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
||||
index 2e44c013a96..b7105938345 100644
|
||||
--- a/res/values/strings.xml
|
||||
+++ b/res/values/strings.xml
|
||||
@@ -675,6 +675,9 @@
|
||||
<!-- Text shown for title of owner info setting [CHAR LIMIT=30]-->
|
||||
<string name="owner_info_settings_title">Add text on lock screen</string>
|
||||
|
||||
+ <string name="auto_reboot_title">Auto reboot</string>
|
||||
+ <string name="auto_reboot_summary">Automatically reboot the device, if the phone hasn\'t been unlocked within the selected number of hours.</string>
|
||||
+
|
||||
<!-- Text shown for summary of owner info setting (if none set) [CHAR LIMIT=40]-->
|
||||
<string name="owner_info_settings_summary">None</string>
|
||||
<!-- Hint text shown in owner info edit text [CHAR LIMIT=50] -->
|
||||
diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml
|
||||
index 0550441d3f2..d0aeb27fe53 100644
|
||||
--- a/res/xml/security_dashboard_settings.xml
|
||||
+++ b/res/xml/security_dashboard_settings.xml
|
||||
@@ -60,6 +60,14 @@
|
||||
android:title="@string/security_settings_biometric_preference_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:keywords="@string/keywords_biometric_settings" />
|
||||
+
|
||||
+ <ListPreference
|
||||
+ android:key="auto_reboot"
|
||||
+ android:title="@string/auto_reboot_title"
|
||||
+ android:summary="@string/auto_reboot_summary"
|
||||
+ android:persistent="false"
|
||||
+ android:entries="@array/auto_reboot_entries"
|
||||
+ android:entryValues="@array/auto_reboot_values" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<Preference
|
||||
@@ -71,4 +79,4 @@
|
||||
settings:controller="com.android.settings.security.SecurityAdvancedSettingsController"
|
||||
settings:keywords="@string/security_advanced_settings_keywords" />
|
||||
|
||||
-</PreferenceScreen>
|
||||
\ No newline at end of file
|
||||
+</PreferenceScreen>
|
||||
diff --git a/src/com/android/settings/security/AutoRebootPreferenceController.java b/src/com/android/settings/security/AutoRebootPreferenceController.java
|
||||
new file mode 100644
|
||||
index 00000000000..c7a75219a5e
|
||||
--- /dev/null
|
||||
+++ b/src/com/android/settings/security/AutoRebootPreferenceController.java
|
||||
@@ -0,0 +1,82 @@
|
||||
+package com.android.settings.security;
|
||||
+
|
||||
+import android.content.Context;
|
||||
+import android.os.UserManager;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Log;
|
||||
+
|
||||
+import androidx.preference.ListPreference;
|
||||
+import androidx.preference.Preference;
|
||||
+import androidx.preference.PreferenceCategory;
|
||||
+import androidx.preference.PreferenceScreen;
|
||||
+
|
||||
+import com.android.settings.core.PreferenceControllerMixin;
|
||||
+import com.android.settingslib.core.AbstractPreferenceController;
|
||||
+import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
+
|
||||
+public class AutoRebootPreferenceController extends AbstractPreferenceController
|
||||
+ implements PreferenceControllerMixin, OnResume,
|
||||
+ Preference.OnPreferenceChangeListener {
|
||||
+
|
||||
+ private static final String KEY_AUTO_REBOOT = "auto_reboot";
|
||||
+ private static final String PREF_KEY_SECURITY_CATEGORY = "security_category";
|
||||
+
|
||||
+ private PreferenceCategory mSecurityCategory;
|
||||
+ private boolean mIsAdmin;
|
||||
+ private final UserManager mUm;
|
||||
+
|
||||
+ public AutoRebootPreferenceController(Context context) {
|
||||
+ super(context);
|
||||
+ mUm = UserManager.get(context);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void displayPreference(PreferenceScreen screen) {
|
||||
+ super.displayPreference(screen);
|
||||
+ mSecurityCategory = screen.findPreference(PREF_KEY_SECURITY_CATEGORY);
|
||||
+ updatePreferenceState();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isAvailable() {
|
||||
+ mIsAdmin = mUm.isAdminUser();
|
||||
+ return mIsAdmin;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getPreferenceKey() {
|
||||
+ return KEY_AUTO_REBOOT;
|
||||
+ }
|
||||
+
|
||||
+ // TODO: should we use onCreatePreferences() instead?
|
||||
+ private void updatePreferenceState() {
|
||||
+ if (mSecurityCategory == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (mIsAdmin) {
|
||||
+ ListPreference autoReboot =
|
||||
+ (ListPreference) mSecurityCategory.findPreference(KEY_AUTO_REBOOT);
|
||||
+ autoReboot.setValue(Long.toString(Settings.Global.getLong(
|
||||
+ mContext.getContentResolver(), Settings.Global.SETTINGS_REBOOT_AFTER_TIMEOUT, 0)));
|
||||
+ } else {
|
||||
+ mSecurityCategory.removePreference(
|
||||
+ mSecurityCategory.findPreference(KEY_AUTO_REBOOT));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onResume() {
|
||||
+ updatePreferenceState();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean onPreferenceChange(Preference preference, Object value) {
|
||||
+ final String key = preference.getKey();
|
||||
+ if (KEY_AUTO_REBOOT.equals(key) && mIsAdmin) {
|
||||
+ long timeout = Long.parseLong((String) value);
|
||||
+ Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.SETTINGS_REBOOT_AFTER_TIMEOUT, timeout);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java
|
||||
index 797d3ec621e..3f0645f7dd8 100644
|
||||
--- a/src/com/android/settings/security/SecuritySettings.java
|
||||
+++ b/src/com/android/settings/security/SecuritySettings.java
|
||||
@@ -114,6 +114,7 @@ public class SecuritySettings extends DashboardFragment {
|
||||
securityPreferenceControllers.add(new CombinedBiometricStatusPreferenceController(
|
||||
context, lifecycle));
|
||||
securityPreferenceControllers.add(new ChangeScreenLockPreferenceController(context, host));
|
||||
+ securityPreferenceControllers.add(new AutoRebootPreferenceController(context));
|
||||
controllers.add(new PreferenceCategoryController(context, SECURITY_CATEGORY)
|
||||
.setChildren(securityPreferenceControllers));
|
||||
controllers.addAll(securityPreferenceControllers);
|
||||
Vendored
+238
@@ -0,0 +1,238 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Oliver Scott <olivercscott@gmail.com>
|
||||
Date: Fri, 2 Oct 2020 12:37:30 -0400
|
||||
Subject: [PATCH] add bluetooth auto-turn-off setting
|
||||
|
||||
---
|
||||
res/values/arrays.xml | 44 +++++++
|
||||
res/values/strings.xml | 19 +++
|
||||
res/xml/connected_devices.xml | 8 ++
|
||||
.../BluetoothTimeoutPreferenceController.java | 115 ++++++++++++++++++
|
||||
4 files changed, 186 insertions(+)
|
||||
create mode 100644 src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java
|
||||
|
||||
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
|
||||
index c5df677975d..1a2796ad276 100644
|
||||
--- a/res/values/arrays.xml
|
||||
+++ b/res/values/arrays.xml
|
||||
@@ -18,6 +18,50 @@
|
||||
*/
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
+ <!-- Bluetooth settings. The delay in inactivity before bluetooth is turned off. These are shown in a list dialog. -->
|
||||
+ <string-array name="bluetooth_timeout_entries">
|
||||
+ <item>@string/bluetooth_timeout_summary_never</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_15secs</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_30secs</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_1min</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_2mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_5mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_10mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_30mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_1hour</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_2hours</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_4hours</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_8hours</item>
|
||||
+ </string-array>
|
||||
+
|
||||
+ <!-- Do not translate. -->
|
||||
+ <string-array name="bluetooth_timeout_values" translatable="false">
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>0</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>15000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>30000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>60000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>120000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>300000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>1800000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>3600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>7200000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>14400000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>28800000</item>
|
||||
+ </string-array>
|
||||
+
|
||||
<!-- Display settings. The delay in inactivity before the screen is turned off. These are shown in a list dialog. -->
|
||||
<string-array name="screen_timeout_entries">
|
||||
<item>15 seconds</item>
|
||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
||||
index b7105938345..cf41793fd42 100644
|
||||
--- a/res/values/strings.xml
|
||||
+++ b/res/values/strings.xml
|
||||
@@ -27,6 +27,25 @@
|
||||
<!-- Used in confirmation dialogs as the action that the user will tap to turn on the feature. [CHAR LIMIT=40]-->
|
||||
<string name="confirmation_turn_on">Turn on</string>
|
||||
|
||||
+ <!-- Connected devices screen, setting option name to change bluetooth timeout -->
|
||||
+ <string name="bluetooth_timeout">Bluetooth timeout</string>
|
||||
+
|
||||
+ <!-- Connected devices screen, setting option summary to change bluetooth timeout -->
|
||||
+ <string name="bluetooth_timeout_summary">Bluetooth will turn off after <xliff:g id="timeout_description">%1$s</xliff:g> if no devices connected</string>
|
||||
+ <string name="bluetooth_timeout_summary2">Do not automatically turn off Bluetooth</string>
|
||||
+ <string name="bluetooth_timeout_summary_never">Never</string>
|
||||
+ <string name="bluetooth_timeout_summary_15secs">15 seconds</string>
|
||||
+ <string name="bluetooth_timeout_summary_30secs">30 seconds</string>
|
||||
+ <string name="bluetooth_timeout_summary_1min">1 minute</string>
|
||||
+ <string name="bluetooth_timeout_summary_2mins">2 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_5mins">5 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_10mins">10 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_30mins">30 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_1hour">1 hour</string>
|
||||
+ <string name="bluetooth_timeout_summary_2hours">2 hours</string>
|
||||
+ <string name="bluetooth_timeout_summary_4hours">4 hours</string>
|
||||
+ <string name="bluetooth_timeout_summary_8hours">8 hours</string>
|
||||
+
|
||||
<!-- Device Info screen. Used for a status item's value when the proper value is not known -->
|
||||
<string name="device_info_default">Unknown</string>
|
||||
<!-- String for removal of sensitive info on about, depending on tap -->
|
||||
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
|
||||
index 95aa8773c68..d66915369e4 100644
|
||||
--- a/res/xml/connected_devices.xml
|
||||
+++ b/res/xml/connected_devices.xml
|
||||
@@ -60,6 +60,14 @@
|
||||
settings:useAdminDisabledSummary="true"
|
||||
settings:userRestriction="no_config_bluetooth" />
|
||||
|
||||
+ <androidx.preference.ListPreference
|
||||
+ android:key="bluetooth_timeout"
|
||||
+ android:title="@string/bluetooth_timeout"
|
||||
+ android:summary="@string/summary_placeholder"
|
||||
+ android:entries="@array/bluetooth_timeout_entries"
|
||||
+ android:entryValues="@array/bluetooth_timeout_values"
|
||||
+ settings:controller="com.android.settings.bluetooth.BluetoothTimeoutPreferenceController"/>
|
||||
+
|
||||
<PreferenceCategory
|
||||
android:key="previously_connected_devices"
|
||||
android:title="@string/connected_device_saved_title"
|
||||
diff --git a/src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java
|
||||
new file mode 100644
|
||||
index 00000000000..244147948aa
|
||||
--- /dev/null
|
||||
+++ b/src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java
|
||||
@@ -0,0 +1,115 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2020 The Calyx Institute
|
||||
+ *
|
||||
+ * 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.settings.bluetooth;
|
||||
+
|
||||
+import android.bluetooth.BluetoothAdapter;
|
||||
+import android.content.Context;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Log;
|
||||
+
|
||||
+import androidx.preference.ListPreference;
|
||||
+import androidx.preference.Preference;
|
||||
+
|
||||
+import com.android.settings.R;
|
||||
+import com.android.settings.core.BasePreferenceController;
|
||||
+import com.android.settings.core.PreferenceControllerMixin;
|
||||
+
|
||||
+public class BluetoothTimeoutPreferenceController extends BasePreferenceController implements
|
||||
+ PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||
+ private static final String TAG = "BluetoothTimeoutPrefCtrl";
|
||||
+
|
||||
+ public static final int FALLBACK_BLUETOOTH_TIMEOUT_VALUE = 0;
|
||||
+
|
||||
+ private final String mBluetoothTimeoutKey;
|
||||
+
|
||||
+ protected BluetoothAdapter mBluetoothAdapter;
|
||||
+
|
||||
+ public BluetoothTimeoutPreferenceController(Context context, String key) {
|
||||
+ super(context, key);
|
||||
+ mBluetoothTimeoutKey = key;
|
||||
+
|
||||
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
+ if (mBluetoothAdapter == null) {
|
||||
+ Log.e(TAG, "Bluetooth is not supported on this device");
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getAvailabilityStatus() {
|
||||
+ return mBluetoothAdapter != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getPreferenceKey() {
|
||||
+ return mBluetoothTimeoutKey;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void updateState(Preference preference) {
|
||||
+ final ListPreference timeoutListPreference = (ListPreference) preference;
|
||||
+ final long currentTimeout = Settings.Global.getLong(mContext.getContentResolver(),
|
||||
+ Settings.Global.BLUETOOTH_OFF_TIMEOUT, FALLBACK_BLUETOOTH_TIMEOUT_VALUE);
|
||||
+ timeoutListPreference.setValue(String.valueOf(currentTimeout));
|
||||
+ updateTimeoutPreferenceDescription(timeoutListPreference,
|
||||
+ Long.parseLong(timeoutListPreference.getValue()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
+ try {
|
||||
+ long value = Long.parseLong((String) newValue);
|
||||
+ Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.BLUETOOTH_OFF_TIMEOUT, value);
|
||||
+ updateTimeoutPreferenceDescription((ListPreference) preference, value);
|
||||
+ } catch (NumberFormatException e) {
|
||||
+ Log.e(TAG, "could not persist bluetooth timeout setting", e);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public static CharSequence getTimeoutDescription(
|
||||
+ long currentTimeout, CharSequence[] entries, CharSequence[] values) {
|
||||
+ if (currentTimeout < 0 || entries == null || values == null
|
||||
+ || values.length != entries.length) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < values.length; i++) {
|
||||
+ long timeout = Long.parseLong(values[i].toString());
|
||||
+ if (currentTimeout == timeout) {
|
||||
+ return entries[i];
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private void updateTimeoutPreferenceDescription(ListPreference preference,
|
||||
+ long currentTimeout) {
|
||||
+ final CharSequence[] entries = preference.getEntries();
|
||||
+ final CharSequence[] values = preference.getEntryValues();
|
||||
+ final CharSequence timeoutDescription = getTimeoutDescription(
|
||||
+ currentTimeout, entries, values);
|
||||
+ String summary = "";
|
||||
+ if (timeoutDescription != null) {
|
||||
+ if (currentTimeout != 0)
|
||||
+ summary = mContext.getString(R.string.bluetooth_timeout_summary, timeoutDescription);
|
||||
+ else
|
||||
+ summary = mContext.getString(R.string.bluetooth_timeout_summary2);
|
||||
+ }
|
||||
+ preference.setSummary(summary);
|
||||
+ }
|
||||
+}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Oliver Scott <olivercscott@gmail.com>
|
||||
Date: Thu, 25 Feb 2021 11:31:14 -0500
|
||||
Subject: [PATCH] add Wi-Fi timeout feature
|
||||
|
||||
---
|
||||
res/values/arrays.xml | 44 +++++++
|
||||
res/values/strings.xml | 19 +++
|
||||
res/xml/wifi_configure_settings.xml | 8 ++
|
||||
.../wifi/WifiTimeoutPreferenceController.java | 115 ++++++++++++++++++
|
||||
4 files changed, 186 insertions(+)
|
||||
create mode 100644 src/com/android/settings/wifi/WifiTimeoutPreferenceController.java
|
||||
|
||||
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
|
||||
index 1a2796ad276..9344280a905 100644
|
||||
--- a/res/values/arrays.xml
|
||||
+++ b/res/values/arrays.xml
|
||||
@@ -62,6 +62,50 @@
|
||||
<item>28800000</item>
|
||||
</string-array>
|
||||
|
||||
+ <!-- Wifi settings. The delay in inactivity before wifi is turned off. These are shown in a list dialog. -->
|
||||
+ <string-array name="wifi_timeout_entries">
|
||||
+ <item>@string/wifi_timeout_summary_never</item>
|
||||
+ <item>@string/wifi_timeout_summary_15secs</item>
|
||||
+ <item>@string/wifi_timeout_summary_30secs</item>
|
||||
+ <item>@string/wifi_timeout_summary_1min</item>
|
||||
+ <item>@string/wifi_timeout_summary_2mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_5mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_10mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_30mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_1hour</item>
|
||||
+ <item>@string/wifi_timeout_summary_2hours</item>
|
||||
+ <item>@string/wifi_timeout_summary_4hours</item>
|
||||
+ <item>@string/wifi_timeout_summary_8hours</item>
|
||||
+ </string-array>
|
||||
+
|
||||
+ <!-- Do not translate. -->
|
||||
+ <string-array name="wifi_timeout_values" translatable="false">
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>0</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>15000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>30000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>60000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>120000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>300000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>1800000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>3600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>7200000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>14400000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>28800000</item>
|
||||
+ </string-array>
|
||||
+
|
||||
<!-- Display settings. The delay in inactivity before the screen is turned off. These are shown in a list dialog. -->
|
||||
<string-array name="screen_timeout_entries">
|
||||
<item>15 seconds</item>
|
||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
||||
index cf41793fd42..1c3f864c956 100644
|
||||
--- a/res/values/strings.xml
|
||||
+++ b/res/values/strings.xml
|
||||
@@ -46,6 +46,25 @@
|
||||
<string name="bluetooth_timeout_summary_4hours">4 hours</string>
|
||||
<string name="bluetooth_timeout_summary_8hours">8 hours</string>
|
||||
|
||||
+ <!-- screen, setting option name to change wifi timeout -->
|
||||
+ <string name="wifi_timeout">Turn off Wi-Fi automatically</string>
|
||||
+
|
||||
+ <!-- screen, setting option summary to change wifi timeout -->
|
||||
+ <string name="wifi_timeout_summary">Wi-Fi will turn off after <xliff:g id="timeout_description">%1$s</xliff:g> if no network connected</string>
|
||||
+ <string name="wifi_timeout_summary2">Disabled</string>
|
||||
+ <string name="wifi_timeout_summary_never">Never</string>
|
||||
+ <string name="wifi_timeout_summary_15secs">15 seconds</string>
|
||||
+ <string name="wifi_timeout_summary_30secs">30 seconds</string>
|
||||
+ <string name="wifi_timeout_summary_1min">1 minute</string>
|
||||
+ <string name="wifi_timeout_summary_2mins">2 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_5mins">5 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_10mins">10 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_30mins">30 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_1hour">1 hour</string>
|
||||
+ <string name="wifi_timeout_summary_2hours">2 hours</string>
|
||||
+ <string name="wifi_timeout_summary_4hours">4 hours</string>
|
||||
+ <string name="wifi_timeout_summary_8hours">8 hours</string>
|
||||
+
|
||||
<!-- Device Info screen. Used for a status item's value when the proper value is not known -->
|
||||
<string name="device_info_default">Unknown</string>
|
||||
<!-- String for removal of sensitive info on about, depending on tap -->
|
||||
diff --git a/res/xml/wifi_configure_settings.xml b/res/xml/wifi_configure_settings.xml
|
||||
index 5866c5898d9..663e3109d76 100644
|
||||
--- a/res/xml/wifi_configure_settings.xml
|
||||
+++ b/res/xml/wifi_configure_settings.xml
|
||||
@@ -26,6 +26,14 @@
|
||||
android:summary="@string/wifi_wakeup_summary"
|
||||
settings:controller="com.android.settings.wifi.WifiWakeupPreferenceController"/>
|
||||
|
||||
+ <ListPreference
|
||||
+ android:key="wifi_timeout"
|
||||
+ android:title="@string/wifi_timeout"
|
||||
+ android:summary="@string/wifi_timeout_summary"
|
||||
+ android:entries="@array/wifi_timeout_entries"
|
||||
+ android:entryValues="@array/wifi_timeout_values"
|
||||
+ settings:controller="com.android.settings.wifi.WifiTimeoutPreferenceController"/>
|
||||
+
|
||||
<SwitchPreferenceCompat
|
||||
android:key="notify_open_networks"
|
||||
android:title="@string/wifi_notify_open_networks"
|
||||
diff --git a/src/com/android/settings/wifi/WifiTimeoutPreferenceController.java b/src/com/android/settings/wifi/WifiTimeoutPreferenceController.java
|
||||
new file mode 100644
|
||||
index 00000000000..7116c905190
|
||||
--- /dev/null
|
||||
+++ b/src/com/android/settings/wifi/WifiTimeoutPreferenceController.java
|
||||
@@ -0,0 +1,115 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2020 The Calyx Institute
|
||||
+ *
|
||||
+ * 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.settings.wifi;
|
||||
+
|
||||
+import android.content.Context;
|
||||
+import android.net.wifi.WifiManager;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Log;
|
||||
+
|
||||
+import androidx.preference.ListPreference;
|
||||
+import androidx.preference.Preference;
|
||||
+
|
||||
+import com.android.settings.R;
|
||||
+import com.android.settings.core.BasePreferenceController;
|
||||
+import com.android.settings.core.PreferenceControllerMixin;
|
||||
+
|
||||
+public class WifiTimeoutPreferenceController extends BasePreferenceController implements
|
||||
+ PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||
+ private static final String TAG = "WifiTimeoutPrefCtrl";
|
||||
+
|
||||
+ public static final int FALLBACK_WIFI_TIMEOUT_VALUE = 0;
|
||||
+
|
||||
+ private final String mWifiTimeoutKey;
|
||||
+
|
||||
+ protected WifiManager mWifiManager;
|
||||
+
|
||||
+ public WifiTimeoutPreferenceController(Context context, String key) {
|
||||
+ super(context, key);
|
||||
+ mWifiTimeoutKey = key;
|
||||
+
|
||||
+ mWifiManager = context.getSystemService(WifiManager.class);
|
||||
+ if (mWifiManager == null) {
|
||||
+ Log.e(TAG, "Wifi is not supported on this device");
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getAvailabilityStatus() {
|
||||
+ return mWifiManager != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getPreferenceKey() {
|
||||
+ return mWifiTimeoutKey;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void updateState(Preference preference) {
|
||||
+ final ListPreference timeoutListPreference = (ListPreference) preference;
|
||||
+ final long currentTimeout = Settings.Global.getLong(mContext.getContentResolver(),
|
||||
+ Settings.Global.WIFI_OFF_TIMEOUT, FALLBACK_WIFI_TIMEOUT_VALUE);
|
||||
+ timeoutListPreference.setValue(String.valueOf(currentTimeout));
|
||||
+ updateTimeoutPreferenceDescription(timeoutListPreference,
|
||||
+ Long.parseLong(timeoutListPreference.getValue()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
+ try {
|
||||
+ long value = Long.parseLong((String) newValue);
|
||||
+ Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.WIFI_OFF_TIMEOUT, value);
|
||||
+ updateTimeoutPreferenceDescription((ListPreference) preference, value);
|
||||
+ } catch (NumberFormatException e) {
|
||||
+ Log.e(TAG, "could not persist wifi timeout setting", e);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public static CharSequence getTimeoutDescription(
|
||||
+ long currentTimeout, CharSequence[] entries, CharSequence[] values) {
|
||||
+ if (currentTimeout < 0 || entries == null || values == null
|
||||
+ || values.length != entries.length) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < values.length; i++) {
|
||||
+ long timeout = Long.parseLong(values[i].toString());
|
||||
+ if (currentTimeout == timeout) {
|
||||
+ return entries[i];
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private void updateTimeoutPreferenceDescription(ListPreference preference,
|
||||
+ long currentTimeout) {
|
||||
+ final CharSequence[] entries = preference.getEntries();
|
||||
+ final CharSequence[] values = preference.getEntryValues();
|
||||
+ final CharSequence timeoutDescription = getTimeoutDescription(
|
||||
+ currentTimeout, entries, values);
|
||||
+ String summary = "";
|
||||
+ if (timeoutDescription != null) {
|
||||
+ if (currentTimeout != 0)
|
||||
+ summary = mContext.getString(R.string.wifi_timeout_summary, timeoutDescription);
|
||||
+ else
|
||||
+ summary = mContext.getString(R.string.wifi_timeout_summary2);
|
||||
+ }
|
||||
+ preference.setSummary(summary);
|
||||
+ }
|
||||
+}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Port AXP auto-reboot, Wi-Fi/Bluetooth timeouts, and sensitive QS tiles.
|
||||
|
||||
AXP Patch.sh order @ 7b735844, applied with --fuzz=0:
|
||||
0014-Automatic_Reboot.patch
|
||||
0015-System_Server_Extensions.patch
|
||||
0015-WiFi_Timeout.patch
|
||||
0015-Bluetooth_Timeout.patch
|
||||
0015-Bluetooth_Timeout-Fix.patch
|
||||
0041-tile_restrictions.patch
|
||||
|
||||
A16 adaptations after the exact hunks:
|
||||
* privapp-permissions gained READ_SYSTEM_GRAMMATICAL_GENDER, so the REBOOT
|
||||
line is inserted between REAL_GET_TASKS and REQUEST_NETWORK_SCORES.
|
||||
* onKeyguardExitFinished() now dismisses the keyguard interactor before the
|
||||
closing brace. The AXP cancel stays immediately after sendUserPresentBroadcast().
|
||||
* QSTileImpl no longer imports QsInCompose, so KeyguardStateController is
|
||||
imported after QSLogger.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("SUNFISH_A16_TREE", "/srv/rom/src/lineage"))
|
||||
PATCH_DIR = pathlib.Path(__file__).resolve().parent / "a15-src" / "frameworks_base"
|
||||
BASE = TREE / "frameworks/base"
|
||||
|
||||
XML = BASE / "data/etc/com.android.systemui.xml"
|
||||
KEYGUARD = (
|
||||
BASE / "packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java"
|
||||
)
|
||||
QSTILE = BASE / "packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java"
|
||||
|
||||
XML_OLD = """ <permission name="android.permission.REAL_GET_TASKS"/>
|
||||
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
||||
"""
|
||||
XML_NEW = """ <permission name="android.permission.REAL_GET_TASKS"/>
|
||||
<permission name="android.permission.REBOOT"/>
|
||||
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
||||
"""
|
||||
|
||||
KEYGUARD_OLD = """ adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
|
||||
if (!KeyguardWmStateRefactor.isEnabled()) {
|
||||
mKeyguardInteractor.dismissKeyguard();
|
||||
}
|
||||
"""
|
||||
KEYGUARD_NEW = """ adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
cancelDoRebootForOwnerAfterTimeoutIfEnabled();
|
||||
|
||||
if (!KeyguardWmStateRefactor.isEnabled()) {
|
||||
mKeyguardInteractor.dismissKeyguard();
|
||||
}
|
||||
"""
|
||||
|
||||
IMPORT_OLD = "import com.android.systemui.qs.logging.QSLogger;\n"
|
||||
IMPORT_NEW = (
|
||||
"import com.android.systemui.qs.logging.QSLogger;\n"
|
||||
"import com.android.systemui.statusbar.policy.KeyguardStateController;\n"
|
||||
)
|
||||
|
||||
|
||||
def replace_once(path: pathlib.Path, old: str, new: str) -> None:
|
||||
text = path.read_text()
|
||||
if new in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def apply_patch(name: str) -> None:
|
||||
patch = PATCH_DIR / name
|
||||
if not patch.is_file():
|
||||
sys.exit(f"missing {patch}")
|
||||
result = subprocess.run(
|
||||
[
|
||||
"patch",
|
||||
"-p1",
|
||||
"--forward",
|
||||
"--fuzz=0",
|
||||
"--batch",
|
||||
"--no-backup-if-mismatch",
|
||||
"-d",
|
||||
str(BASE),
|
||||
"-i",
|
||||
str(patch),
|
||||
],
|
||||
check=False,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
)
|
||||
sys.stdout.write(result.stdout)
|
||||
sys.stdout.write(result.stderr)
|
||||
if result.returncode != 0 and "FAILED" in result.stderr + result.stdout:
|
||||
print(f"patch_incomplete: {name}")
|
||||
elif result.returncode != 0:
|
||||
print(f"patch_exit_{result.returncode}: {name}")
|
||||
|
||||
|
||||
def clean_rejects() -> None:
|
||||
for path in (XML, KEYGUARD, QSTILE):
|
||||
for suffix in (".rej", ".orig"):
|
||||
extra = path.with_name(path.name + suffix)
|
||||
if extra.exists():
|
||||
extra.unlink()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
apply_patch("0014-Automatic_Reboot.patch")
|
||||
replace_once(XML, XML_OLD, XML_NEW)
|
||||
replace_once(KEYGUARD, KEYGUARD_OLD, KEYGUARD_NEW)
|
||||
for name in (
|
||||
"0015-System_Server_Extensions.patch",
|
||||
"0015-WiFi_Timeout.patch",
|
||||
"0015-Bluetooth_Timeout.patch",
|
||||
"0015-Bluetooth_Timeout-Fix.patch",
|
||||
"0041-tile_restrictions.patch",
|
||||
):
|
||||
apply_patch(name)
|
||||
replace_once(QSTILE, IMPORT_OLD, IMPORT_NEW)
|
||||
clean_rejects()
|
||||
required = [
|
||||
"settings_reboot_after_timeout",
|
||||
"android.permission.REBOOT",
|
||||
"cancelDoRebootForOwnerAfterTimeoutIfEnabled();",
|
||||
"class SystemServerExt",
|
||||
"class WifiAutoOff",
|
||||
"class BluetoothAutoOff",
|
||||
"import android.bluetooth.BluetoothProfile;",
|
||||
"WIFI_OFF_TIMEOUT",
|
||||
"BLUETOOTH_OFF_TIMEOUT",
|
||||
"isAllowedWhenLocked",
|
||||
"KeyguardStateController",
|
||||
]
|
||||
blob = "\n".join(
|
||||
path.read_text()
|
||||
for path in (
|
||||
BASE / "core/java/android/provider/Settings.java",
|
||||
XML,
|
||||
KEYGUARD,
|
||||
BASE / "services/core/java/com/android/server/ext/SystemServerExt.java",
|
||||
BASE / "services/core/java/com/android/server/ext/WifiAutoOff.java",
|
||||
BASE / "services/core/java/com/android/server/ext/BluetoothAutoOff.java",
|
||||
QSTILE,
|
||||
)
|
||||
)
|
||||
missing = [item for item in required if item not in blob]
|
||||
if missing:
|
||||
sys.exit("missing after apply: " + ", ".join(missing))
|
||||
print("done: SUNFISH_A16_009_A15_REBOOT_TIMEOUTS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Settings UI for the AXP reboot and radio timeouts.
|
||||
|
||||
Apply after apply_009_a15_reboot_timeouts.py. Order matches AXP:
|
||||
bluetooth arrays land before the Wi-Fi arrays, which insert after them.
|
||||
|
||||
0006 needs fuzz 2. A16's strings.xml has an empty line where the A15
|
||||
patch has a single space, and connected_devices.xml shifted by a few
|
||||
lines. The preference still lands on the connected-devices screen.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("SUNFISH_A16_TREE", "/srv/rom/src/lineage"))
|
||||
PATCH_DIR = pathlib.Path(__file__).resolve().parent / "a15-src" / "settings"
|
||||
SETTINGS = TREE / "packages/apps/Settings"
|
||||
|
||||
|
||||
MARKERS = (
|
||||
"res/xml/security_dashboard_settings.xml",
|
||||
"res/xml/connected_devices.xml",
|
||||
"res/xml/wifi_configure_settings.xml",
|
||||
"res/values/arrays.xml",
|
||||
"res/values/strings.xml",
|
||||
)
|
||||
|
||||
|
||||
def already_applied() -> bool:
|
||||
try:
|
||||
blob = "\n".join((SETTINGS / name).read_text() for name in MARKERS)
|
||||
except OSError:
|
||||
return False
|
||||
needles = (
|
||||
'android:key="auto_reboot"',
|
||||
'android:key="bluetooth_timeout"',
|
||||
'android:key="wifi_timeout"',
|
||||
'name="auto_reboot_entries"',
|
||||
'name="bluetooth_timeout_entries"',
|
||||
'name="wifi_timeout_entries"',
|
||||
)
|
||||
return all(needle in blob for needle in needles)
|
||||
|
||||
|
||||
def apply_patch(name: str, fuzz: str) -> None:
|
||||
result = subprocess.run(
|
||||
[
|
||||
"patch",
|
||||
"-p1",
|
||||
"--forward",
|
||||
f"--fuzz={fuzz}",
|
||||
"--batch",
|
||||
"--no-backup-if-mismatch",
|
||||
"-d",
|
||||
str(SETTINGS),
|
||||
"-i",
|
||||
str(PATCH_DIR / name),
|
||||
],
|
||||
check=False,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
)
|
||||
sys.stdout.write(result.stdout)
|
||||
sys.stdout.write(result.stderr)
|
||||
for path in SETTINGS.rglob("*.rej"):
|
||||
path.unlink()
|
||||
if "FAILED" in result.stdout + result.stderr and not already_applied():
|
||||
sys.exit(f"failed: {name}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if already_applied():
|
||||
print("done: SUNFISH_A16_009_A15_SETTINGS_TIMEOUTS")
|
||||
return
|
||||
apply_patch("0005-Automatic_Reboot.patch", "0")
|
||||
apply_patch("0006-Bluetooth_Timeout.patch", "2")
|
||||
apply_patch("0007-WiFi_Timeout.patch", "0")
|
||||
if not already_applied():
|
||||
sys.exit("missing settings timeout markers")
|
||||
print("done: SUNFISH_A16_009_A15_SETTINGS_TIMEOUTS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Port four AXP LOS 22.2 userspace changes onto LOS 23 / Android 16.
|
||||
|
||||
Sources, Patch.sh @ 7b735844 (AXP A15):
|
||||
android_frameworks_base/0004-Fingerprint_Lockout.patch
|
||||
android_frameworks_base/0007-Always_Restict_Serial.patch
|
||||
android_frameworks_base/0042-minimal_screenshot_exif.patch
|
||||
android_bootable_recovery/0001-No_SerialNum_Restrictions.patch
|
||||
|
||||
Sunfish fingerprint HAL is HIDL 2.2, and HidlToAidlSensorAdapter still uses
|
||||
LockoutFrameworkImpl, so the AXP constant change is the live path.
|
||||
|
||||
A16 adaptations, behavior unchanged:
|
||||
* CheckPackageMetadata returns bool, so a serial constraint returns false.
|
||||
The A15 patch returned INSTALL_ERROR, which does not compile here.
|
||||
* Screenshot EXIF drops the now-unused Build and DateTimeFormatter imports.
|
||||
A16 ErrorProne treats unused imports as errors.
|
||||
|
||||
Already satisfied on this tree, so this script does not touch them:
|
||||
* 0028-Remove_Legacy_Package_Query: A16 already removed the
|
||||
MATCH_UNINSTALLED_PACKAGES / MATCH_ANY_USER branch.
|
||||
* system/core 0002-ptrace_scope: apply_009_yama_ptrace.py already writes
|
||||
persist.native_debug.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("SUNFISH_A16_TREE", "/srv/rom/src/lineage"))
|
||||
|
||||
LOCKOUT = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/biometrics"
|
||||
/ "sensors/fingerprint/hidl/LockoutFrameworkImpl.java"
|
||||
)
|
||||
AMS = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/am"
|
||||
/ "ActivityManagerService.java"
|
||||
)
|
||||
EXIF = (
|
||||
TREE
|
||||
/ "frameworks/base/packages/SystemUI/src/com/android/systemui"
|
||||
/ "screenshot/ImageExporter.java"
|
||||
)
|
||||
RECOVERY = TREE / "bootable/recovery/install/install.cpp"
|
||||
|
||||
LOCKOUT_OLD = "private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;"
|
||||
LOCKOUT_NEW = "private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 5;"
|
||||
|
||||
SERIAL_OLD = """ // We deprecated Build.SERIAL and it is not accessible to
|
||||
// Instant Apps and target APIs higher than O MR1. Since access to the serial
|
||||
// is now behind a permission we push down the value.
|
||||
final String buildSerial = (!appInfo.isInstantApp()
|
||||
&& appInfo.targetSdkVersion < Build.VERSION_CODES.P)
|
||||
? sTheRealBuildSerial : Build.UNKNOWN;
|
||||
"""
|
||||
SERIAL_NEW = """ // AXP/GrapheneOS 0007: deprecated Build.SERIAL stays UNKNOWN.
|
||||
// Callers use Build.getSerial(), which requires READ_PHONE_STATE.
|
||||
final String buildSerial = Build.UNKNOWN;
|
||||
"""
|
||||
|
||||
EXIF_OLD = """ exif.setAttribute(ExifInterface.TAG_IMAGE_UNIQUE_ID, uniqueId.toString());
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_SOFTWARE, "Android " + Build.DISPLAY);
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, Integer.toString(width));
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, Integer.toString(height));
|
||||
|
||||
String dateTime = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(captureTime);
|
||||
String subSec = DateTimeFormatter.ofPattern("SSS").format(captureTime);
|
||||
String timeZone = DateTimeFormatter.ofPattern("xxx").format(captureTime);
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTime);
|
||||
exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL, subSec);
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, timeZone);
|
||||
"""
|
||||
EXIF_NEW = """ // AXP/Calyx 0042: width and height only. No OS name, unique id, or time.
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, Integer.toString(width));
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, Integer.toString(height));
|
||||
"""
|
||||
|
||||
RECOVERY_OLD = """ // We allow the package to not have any serialno; and we also allow it to carry multiple serial
|
||||
// numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the
|
||||
// verification if the device's serialno doesn't match any of these carried numbers.
|
||||
|
||||
auto pkg_serial_no = get_value(metadata, "serialno");
|
||||
if (!pkg_serial_no.empty()) {
|
||||
auto device_serial_no = android::base::GetProperty("ro.serialno", "");
|
||||
bool serial_number_match = false;
|
||||
for (const auto& number : android::base::Split(pkg_serial_no, "|")) {
|
||||
if (device_serial_no == android::base::Trim(number)) {
|
||||
serial_number_match = true;
|
||||
}
|
||||
}
|
||||
if (!serial_number_match) {
|
||||
LOG(ERROR) << "Package is for serial " << pkg_serial_no;
|
||||
return false;
|
||||
}
|
||||
} else if (ota_type == OtaType::BRICK) {
|
||||
"""
|
||||
RECOVERY_NEW = """ // AXP/GrapheneOS 0001: any serialno constraint is rejected.
|
||||
// A16 CheckPackageMetadata returns bool; A15 returned INSTALL_ERROR.
|
||||
auto pkg_serial_no = get_value(metadata, "serialno");
|
||||
if (!pkg_serial_no.empty()) {
|
||||
LOG(ERROR) << "Serial number constraint not permitted: " << pkg_serial_no;
|
||||
return false;
|
||||
} else if (ota_type == OtaType::BRICK) {
|
||||
"""
|
||||
|
||||
|
||||
def replace_once(path: pathlib.Path, old: str, new: str) -> None:
|
||||
text = path.read_text()
|
||||
if new in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def drop_import(text: str, import_line: str, still_used: str) -> str:
|
||||
if import_line not in text:
|
||||
return text
|
||||
body = text.replace(import_line + "\n", "", 1)
|
||||
if still_used in body:
|
||||
return text
|
||||
return body
|
||||
|
||||
|
||||
def apply_exif() -> None:
|
||||
text = EXIF.read_text()
|
||||
if EXIF_NEW in text:
|
||||
updated = text
|
||||
elif EXIF_OLD not in text:
|
||||
sys.exit(f"anchor missing in {EXIF}")
|
||||
else:
|
||||
updated = text.replace(EXIF_OLD, EXIF_NEW, 1)
|
||||
updated = drop_import(updated, "import android.os.Build;", "Build.")
|
||||
updated = drop_import(
|
||||
updated, "import java.time.format.DateTimeFormatter;", "DateTimeFormatter"
|
||||
)
|
||||
EXIF.write_text(updated)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
replace_once(LOCKOUT, LOCKOUT_OLD, LOCKOUT_NEW)
|
||||
replace_once(AMS, SERIAL_OLD, SERIAL_NEW)
|
||||
apply_exif()
|
||||
replace_once(RECOVERY, RECOVERY_OLD, RECOVERY_NEW)
|
||||
print("done: SUNFISH_A16_009_A15_SMALL")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: AXP ship identity on LOS 23.2.
|
||||
|
||||
- AXP Patch.sh (LineageOS-22.2:405) replaces LINEAGE_BUILDTYPE := UNOFFICIAL
|
||||
with its own build type in vendor/lineage/config/*.mk. Same here, with PRO
|
||||
(GOLDEN ro.lineage.releasetype=PRO).
|
||||
- Drops the old TARGET_UNOFFICIAL_BUILD_ID insert from lineage_sunfish.mk.
|
||||
- Vendor SPL stays the LOS 23.2 2023-09-05 (AXP GOLDEN ships 2023-08-05).
|
||||
- build/make/core/config.mk only tags release-keys when the default cert is
|
||||
under vendor/lineage-priv/. Copies the project certs there (same keys, so
|
||||
an existing install updates without a wipe).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path("/srv/rom/src/lineage")
|
||||
SRC_CERTS = TREE / "vendor/sunfish-a16/certs"
|
||||
DST_CERTS = TREE / "vendor/lineage-priv/keys"
|
||||
OLD_ID = (
|
||||
"# sunfish-a16: must precede vendor/lineage version.mk (via inherit below)\n"
|
||||
"TARGET_UNOFFICIAL_BUILD_ID := AXP-Resurection-Pro\n\n"
|
||||
)
|
||||
# LOS 23.2 writes 2023-09-05. AXP GOLDEN uses 2023-08-05, but keymaster key
|
||||
# blobs on an existing install are bound to the vendor patch level and refuse
|
||||
# a rollback: vdc cryptfs init_user0 fails and recovery asks for a wipe
|
||||
# (LAB 2026-10-07 17:15 build). Never lower the vendor SPL on an upgrade.
|
||||
VENDOR_SPL_LOS = (
|
||||
"# Set Vendor SPL to match platform\n"
|
||||
"VENDOR_SECURITY_PATCH = 2023-09-05\n"
|
||||
)
|
||||
VENDOR_SPL_ROLLBACK = (
|
||||
"# Stock sunfish vendor SPL (TQ3A.230805), same as AXP GOLDEN.\n"
|
||||
"# System PLATFORM_SECURITY_PATCH stays the LOS 23.2 ASB.\n"
|
||||
"VENDOR_SECURITY_PATCH = 2023-08-05\n"
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
version = TREE / "vendor/lineage/config/version.mk"
|
||||
text = version.read_text()
|
||||
if "LINEAGE_BUILDTYPE := PRO\n" not in text:
|
||||
old = " LINEAGE_BUILDTYPE := UNOFFICIAL\n"
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {version}")
|
||||
version.write_text(text.replace(old, " LINEAGE_BUILDTYPE := PRO\n", 1))
|
||||
|
||||
device_mk = TREE / "device/google/sunfish/lineage_sunfish.mk"
|
||||
text = device_mk.read_text()
|
||||
if OLD_ID in text:
|
||||
device_mk.write_text(text.replace(OLD_ID, "", 1))
|
||||
if "TARGET_UNOFFICIAL_BUILD_ID" in device_mk.read_text():
|
||||
sys.exit(f"TARGET_UNOFFICIAL_BUILD_ID still set in {device_mk}")
|
||||
|
||||
common = TREE / "device/google/sunfish/device-common.mk"
|
||||
text = common.read_text()
|
||||
if VENDOR_SPL_ROLLBACK in text:
|
||||
text = text.replace(VENDOR_SPL_ROLLBACK, VENDOR_SPL_LOS, 1)
|
||||
common.write_text(text)
|
||||
if VENDOR_SPL_LOS not in text:
|
||||
sys.exit(f"vendor SPL is not 2023-09-05 in {common}")
|
||||
|
||||
if not (SRC_CERTS / "releasekey.pk8").is_file():
|
||||
sys.exit(f"missing {SRC_CERTS}/releasekey.pk8")
|
||||
DST_CERTS.mkdir(parents=True, exist_ok=True)
|
||||
for src in SRC_CERTS.iterdir():
|
||||
if src.name.startswith("avb"):
|
||||
continue
|
||||
dst = DST_CERTS / src.name
|
||||
if dst.is_symlink() or dst.exists():
|
||||
dst.unlink()
|
||||
if src.is_symlink():
|
||||
dst.symlink_to(src.readlink())
|
||||
else:
|
||||
shutil.copy2(src, dst)
|
||||
print("axp identity applied")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Hide /proc/cmdline from unprivileged processes.
|
||||
|
||||
AOSP and GOLDEN's init do this in first-stage init, immediately after
|
||||
mounting proc:
|
||||
|
||||
CHECKCALL(chmod("/proc/cmdline", 0440));
|
||||
|
||||
The failure text is exactly `chmod("/proc/cmdline", 0440) failed`, which
|
||||
is present in GOLDEN's /system/bin/init and absent from the LOS 23.2 init
|
||||
that left the file mode 0444. LOS 23.2 already chmod's /proc/bootconfig
|
||||
the same way. init.rc only chowns cmdline to root:radio.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("ANDROID_BUILD_TOP", "/srv/rom/src/lineage"))
|
||||
INIT = TREE / "system/core/init/first_stage_init.cpp"
|
||||
OLD = """#undef MAKE_STR
|
||||
std::string cmdline;
|
||||
android::base::ReadFileToString("/proc/cmdline", &cmdline);
|
||||
"""
|
||||
NEW = """#undef MAKE_STR
|
||||
// Don't expose the raw commandline to unprivileged processes.
|
||||
CHECKCALL(chmod("/proc/cmdline", 0440));
|
||||
std::string cmdline;
|
||||
android::base::ReadFileToString("/proc/cmdline", &cmdline);
|
||||
"""
|
||||
|
||||
|
||||
def main() -> None:
|
||||
text = INIT.read_text()
|
||||
if NEW in text:
|
||||
print(f"already applied: {INIT}")
|
||||
return
|
||||
if OLD not in text:
|
||||
sys.exit(f"cmdline chmod anchor missing in {INIT}")
|
||||
INIT.write_text(text.replace(OLD, NEW, 1))
|
||||
print(f"patched cmdline mode: {INIT}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop Google carrier apps and the AOSP IMS entitlement/RCS packages.
|
||||
|
||||
inherit-product merges PRODUCT_PACKAGES per makefile, so a filter-out never
|
||||
sees names added by sunfish-vendor.mk. Remove the package lines where they
|
||||
are added. CarrierSettings/*.pb copy rules stay: their tokens are paths, not
|
||||
the CarrierSettings module. Qualcomm radio packages stay (ims, atfwd,
|
||||
qcrilmsgtunnel, uceShimService, EuiccSupportPixel).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
TARGETS: tuple[tuple[str, tuple[str, ...], tuple[str, ...]], ...] = (
|
||||
(
|
||||
"vendor/google/sunfish/sunfish-vendor.mk",
|
||||
(
|
||||
"CarrierServices",
|
||||
"CarrierSettings",
|
||||
"CarrierWifi",
|
||||
"CarrierSetup",
|
||||
"RilConfigService",
|
||||
"grilservice",
|
||||
),
|
||||
(
|
||||
"EuiccSupportPixel",
|
||||
"EuiccSupportPixelPermissions",
|
||||
"ims",
|
||||
"QtiTelephonyService",
|
||||
"atfwd",
|
||||
"qcrilmsgtunnel",
|
||||
"uceShimService",
|
||||
),
|
||||
),
|
||||
(
|
||||
"device/google/sunfish/device-lineage.mk",
|
||||
("PresencePolling", "RcsService"),
|
||||
("GoogleParts",),
|
||||
),
|
||||
(
|
||||
"build/make/target/product/telephony_product.mk",
|
||||
("ImsServiceEntitlement",),
|
||||
("Dialer",),
|
||||
),
|
||||
)
|
||||
|
||||
_RCS_STUB = "# RCS\nPRODUCT_PACKAGES += \\\n\n"
|
||||
|
||||
|
||||
def _token(line: str) -> str:
|
||||
return line.strip().rstrip("\\").strip()
|
||||
|
||||
|
||||
def _has(text: str, name: str) -> bool:
|
||||
return any(_token(line) == name for line in text.splitlines())
|
||||
|
||||
|
||||
def apply_file(path: Path, packages: tuple[str, ...], keep: tuple[str, ...]) -> str:
|
||||
text = path.read_text()
|
||||
for name in keep:
|
||||
if not _has(text, name):
|
||||
raise SystemExit(f"FAIL: {path} lost {name}")
|
||||
removed = {name: 0 for name in packages}
|
||||
kept: list[str] = []
|
||||
for line in text.splitlines(keepends=True):
|
||||
token = _token(line)
|
||||
if token in removed:
|
||||
removed[token] += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
if all(count == 0 for count in removed.values()):
|
||||
return "already"
|
||||
if any(count != 1 for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: unexpected removals in {path}: {removed}")
|
||||
new = "".join(kept)
|
||||
if path.name == "device-lineage.mk":
|
||||
new = new.replace(_RCS_STUB, "", 1)
|
||||
for name in keep:
|
||||
if not _has(new, name):
|
||||
raise SystemExit(f"FAIL: edit would drop {name} from {path}")
|
||||
for name in packages:
|
||||
if _has(new, name):
|
||||
raise SystemExit(f"FAIL: {name} still listed in {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
results: list[str] = []
|
||||
for rel, packages, keep in TARGETS:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
state = apply_file(path, packages, keep)
|
||||
results.append(f"{state} {rel}")
|
||||
print("OK: " + "; ".join(results))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop the Google eUICC LPA from the sunfish vendor makefile.
|
||||
|
||||
inherit-product merges PRODUCT_PACKAGES per makefile, so a filter-out in
|
||||
apps.mk never sees the names added by sunfish-vendor.mk. A Soong phony
|
||||
does not set PACKAGES.*.OVERRIDES. The 20261009T073753Z and 20261009T090831Z
|
||||
zips still installed both APKs. Remove the two entries where they are added.
|
||||
EuiccSupportPixel and EuiccSupportPixelPermissions stay.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
PACKAGES = ("EuiccGoogle", "EuiccGoogleOverlay")
|
||||
KEEP = ("EuiccSupportPixel", "EuiccSupportPixelPermissions")
|
||||
|
||||
|
||||
def _package_line(line: str) -> str | None:
|
||||
stripped = line.strip().rstrip("\\").strip()
|
||||
if stripped in PACKAGES:
|
||||
return stripped
|
||||
return None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
mk = top / "vendor/google/sunfish/sunfish-vendor.mk"
|
||||
if not mk.is_file():
|
||||
print(f"FAIL: missing {mk}", file=sys.stderr)
|
||||
return 1
|
||||
text = mk.read_text()
|
||||
for name in KEEP:
|
||||
if name not in text:
|
||||
print(f"FAIL: {mk} lost {name}", file=sys.stderr)
|
||||
return 1
|
||||
removed = {name: 0 for name in PACKAGES}
|
||||
kept: list[str] = []
|
||||
for line in text.splitlines(keepends=True):
|
||||
hit = _package_line(line)
|
||||
if hit is None:
|
||||
kept.append(line)
|
||||
continue
|
||||
removed[hit] += 1
|
||||
if all(count == 0 for count in removed.values()):
|
||||
print(f"OK: already applied ({mk})")
|
||||
return 0
|
||||
if any(count != 1 for count in removed.values()):
|
||||
print(f"FAIL: unexpected removals {removed}", file=sys.stderr)
|
||||
return 1
|
||||
new = "".join(kept)
|
||||
for name in KEEP:
|
||||
if name not in new:
|
||||
print(f"FAIL: edit would drop {name}", file=sys.stderr)
|
||||
return 1
|
||||
for name in PACKAGES:
|
||||
if f" {name} \\" in new or f" {name}\n" in new:
|
||||
print(f"FAIL: {name} still listed", file=sys.stderr)
|
||||
return 1
|
||||
mk.write_text(new)
|
||||
print(f"OK: dropped {', '.join(PACKAGES)} from {mk}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop commands present on LAB and absent on GOLDEN.
|
||||
|
||||
Keeps the GPS binaries loc_launcher, lowi-server and xtra-daemon.
|
||||
bpftool, alloctop and apexd-lsof.sh are not product packages: bpfloader,
|
||||
dumpstate and apexd require them. Remove only those required entries.
|
||||
pbtombstone stays in PRODUCT_HOST_PACKAGES; only the system copy goes.
|
||||
Qualcomm diag binaries and imsrcsd go. imsdatadaemon and the other IMS
|
||||
call daemons stay.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MAKE_DROPS: tuple[tuple[str, tuple[str, ...], tuple[str, ...]], ...] = (
|
||||
(
|
||||
"vendor/google/sunfish/sunfish-vendor.mk",
|
||||
(
|
||||
"cnss_diag",
|
||||
"diag_klog",
|
||||
"diag_mdlog",
|
||||
"diag_socket_log",
|
||||
"diag_uart_log",
|
||||
"ssr_diag",
|
||||
"test_diag",
|
||||
"imsrcsd",
|
||||
),
|
||||
(
|
||||
"loc_launcher",
|
||||
"lowi-server",
|
||||
"xtra-daemon",
|
||||
"cnss-daemon",
|
||||
"imsdatadaemon",
|
||||
"imsqmidaemon",
|
||||
"ims_rtp_daemon",
|
||||
),
|
||||
),
|
||||
(
|
||||
"device/google/sunfish/device-lineage.mk",
|
||||
("disable_configstore",),
|
||||
("chre_daemon_msm",),
|
||||
),
|
||||
)
|
||||
|
||||
HOST_SAFE = {"pbtombstone"}
|
||||
|
||||
BP_LINES: tuple[tuple[str, str], ...] = (
|
||||
("system/bpf/loader/Android.bp", '"bpftool",'),
|
||||
("frameworks/native/cmds/dumpstate/Android.bp", '"alloctop",'),
|
||||
("system/apex/apexd/Android.bp", 'required: ["apexd-lsof.sh"],'),
|
||||
)
|
||||
|
||||
|
||||
def _token(line: str) -> str:
|
||||
return line.strip().rstrip("\\").strip()
|
||||
|
||||
|
||||
def _has(text: str, name: str) -> bool:
|
||||
return any(_token(line) == name for line in text.splitlines())
|
||||
|
||||
|
||||
def _assignment(line: str, current: str | None) -> str | None:
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("PRODUCT_HOST_PACKAGES") and "+=" in stripped:
|
||||
return "PRODUCT_HOST_PACKAGES"
|
||||
if stripped.startswith("PRODUCT_PACKAGES") and "+=" in stripped:
|
||||
return "PRODUCT_PACKAGES"
|
||||
return current
|
||||
|
||||
|
||||
def apply_make(path: Path, packages: tuple[str, ...], keep: tuple[str, ...]) -> str:
|
||||
text = path.read_text()
|
||||
for name in keep:
|
||||
if not _has(text, name):
|
||||
raise SystemExit(f"FAIL: {path} lost {name}")
|
||||
removed = {name: 0 for name in packages}
|
||||
rc_removed = 0
|
||||
kept: list[str] = []
|
||||
assignment: str | None = None
|
||||
for line in text.splitlines(keepends=True):
|
||||
assignment = _assignment(line, assignment)
|
||||
token = _token(line)
|
||||
if token in removed and not (token in HOST_SAFE and assignment == "PRODUCT_HOST_PACKAGES"):
|
||||
removed[token] += 1
|
||||
continue
|
||||
if "imsrcsd.rc:" in line:
|
||||
rc_removed += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
pending = [name for name, count in removed.items() if count == 0]
|
||||
if pending and any(count for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: partial removal in {path}: {removed}")
|
||||
if not any(count for count in removed.values()) and rc_removed == 0:
|
||||
return "already"
|
||||
if any(count != 1 for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: unexpected removals in {path}: {removed}")
|
||||
if "imsrcsd" in packages and rc_removed != 1:
|
||||
raise SystemExit(f"FAIL: imsrcsd.rc removals={rc_removed} in {path}")
|
||||
new = "".join(kept)
|
||||
for name in keep:
|
||||
if not _has(new, name):
|
||||
raise SystemExit(f"FAIL: edit would drop {name} from {path}")
|
||||
for name in packages:
|
||||
if _has(new, name):
|
||||
raise SystemExit(f"FAIL: {name} still listed in {path}")
|
||||
if "imsrcsd.rc:" in new:
|
||||
raise SystemExit(f"FAIL: imsrcsd.rc still copied from {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def apply_pbtombstone(path: Path) -> str:
|
||||
text = path.read_text()
|
||||
if not _has(text, "logcat") or not _has(text, "fastboot"):
|
||||
raise SystemExit(f"FAIL: {path} lost logcat or fastboot")
|
||||
removed = 0
|
||||
kept: list[str] = []
|
||||
assignment: str | None = None
|
||||
for line in text.splitlines(keepends=True):
|
||||
assignment = _assignment(line, assignment)
|
||||
token = _token(line)
|
||||
if token == "pbtombstone" and assignment == "PRODUCT_PACKAGES":
|
||||
removed += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
if removed == 0:
|
||||
if not any(
|
||||
_token(line) == "pbtombstone" and True
|
||||
for line in text.splitlines()
|
||||
):
|
||||
raise SystemExit(f"FAIL: {path} has no pbtombstone at all")
|
||||
return "already"
|
||||
if removed != 1:
|
||||
raise SystemExit(f"FAIL: pbtombstone system removals={removed}")
|
||||
new = "".join(kept)
|
||||
host_hits = 0
|
||||
assignment = None
|
||||
for line in new.splitlines():
|
||||
assignment = _assignment(line, assignment)
|
||||
if _token(line) == "pbtombstone" and assignment == "PRODUCT_HOST_PACKAGES":
|
||||
host_hits += 1
|
||||
if host_hits != 1:
|
||||
raise SystemExit(f"FAIL: host pbtombstone count={host_hits}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def apply_bp(path: Path, needle: str) -> str:
|
||||
text = path.read_text()
|
||||
hits = [line for line in text.splitlines() if line.strip() == needle]
|
||||
if not hits:
|
||||
return "already"
|
||||
if len(hits) != 1:
|
||||
raise SystemExit(f"FAIL: {needle} appears {len(hits)} times in {path}")
|
||||
new = "".join(
|
||||
line for line in text.splitlines(keepends=True) if line.strip() != needle
|
||||
)
|
||||
if needle in new:
|
||||
raise SystemExit(f"FAIL: {needle} still present in {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
results: list[str] = []
|
||||
for rel, packages, keep in MAKE_DROPS:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_make(path, packages, keep)} {rel}")
|
||||
pb = top / "build/make/target/product/base_system.mk"
|
||||
if not pb.is_file():
|
||||
print(f"FAIL: missing {pb}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_pbtombstone(pb)} {pb.relative_to(top)}")
|
||||
for rel, needle in BP_LINES:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_bp(path, needle)} {rel}")
|
||||
print("OK: " + "; ".join(results))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop Lineage tools that AXP.OS PRO sunfish does not ship.
|
||||
|
||||
GOLDEN has no /system_ext/bin/{bash,htop,nano,unrar} and no
|
||||
/system/addon.d/50-lineage.sh. It does ship curl and vim, so those tokens
|
||||
stay. Qualcomm diag binaries are a separate change.
|
||||
|
||||
inherit-product merges PRODUCT_PACKAGES per makefile, so filter-out cannot
|
||||
remove names added here. Delete the exact package-token lines.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
TARGETS: tuple[tuple[str, tuple[str, ...], tuple[str, ...]], ...] = (
|
||||
(
|
||||
"vendor/lineage/config/common.mk",
|
||||
("bash", "htop", "nano", "50-lineage.sh"),
|
||||
("curl", "getcap", "setcap", "vim", "nano_recovery"),
|
||||
),
|
||||
(
|
||||
"vendor/lineage/config/common_mobile_full.mk",
|
||||
("unrar",),
|
||||
("zstd",),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _token(line: str) -> str:
|
||||
return line.strip().rstrip("\\").strip()
|
||||
|
||||
|
||||
def _has(text: str, name: str) -> bool:
|
||||
return any(_token(line) == name for line in text.splitlines())
|
||||
|
||||
|
||||
def apply_file(path: Path, packages: tuple[str, ...], keep: tuple[str, ...]) -> str:
|
||||
text = path.read_text()
|
||||
for name in keep:
|
||||
if not _has(text, name):
|
||||
raise SystemExit(f"FAIL: {path} lost {name}")
|
||||
removed = {name: 0 for name in packages}
|
||||
kept: list[str] = []
|
||||
for line in text.splitlines(keepends=True):
|
||||
token = _token(line)
|
||||
if token in removed:
|
||||
removed[token] += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
if all(count == 0 for count in removed.values()):
|
||||
return "already"
|
||||
if any(count != 1 for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: unexpected removals in {path}: {removed}")
|
||||
new = "".join(kept)
|
||||
for name in keep:
|
||||
if not _has(new, name):
|
||||
raise SystemExit(f"FAIL: edit would drop {name} from {path}")
|
||||
for name in packages:
|
||||
if _has(new, name):
|
||||
raise SystemExit(f"FAIL: {name} still listed in {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
results: list[str] = []
|
||||
for rel, packages, keep in TARGETS:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_file(path, packages, keep)} {rel}")
|
||||
print("OK: " + "; ".join(results))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,576 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: SUPL privacy, plus an optional stop for LPP / XTRA / IZat.
|
||||
|
||||
- Never send IMSI or MSISDN to a SUPL server (AXP/Divest), including emergency.
|
||||
LOS 23 already skips that outside an emergency call.
|
||||
- Settings toggle "Force disable SUPL", default off. On forces SUPL_MODE=0.
|
||||
- GNSS NTP in sunfish gps.conf: 2.android.pool.ntp.org.
|
||||
- Settings toggle "Stop extra location assistance", default off.
|
||||
Off keeps Lineage LPP, XTRA and IZat. On sets LPP_PROFILE=0 (LPPE is
|
||||
carried by that LPP session), skips the framework XTRA download, and
|
||||
stops loc_launcher. The vendor binaries stay on the image.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
MARKER = "sunfish-a16-009-supl-privacy"
|
||||
TREE = pathlib.Path("/srv/rom/src/lineage")
|
||||
|
||||
|
||||
def must(path: pathlib.Path, old: str, new: str, already: str) -> None:
|
||||
text = path.read_text()
|
||||
if already in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
settings = TREE / "frameworks/base/core/java/android/provider/Settings.java"
|
||||
gnss_cfg = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/location/gnss/GnssConfiguration.java"
|
||||
)
|
||||
gnss_prov = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java"
|
||||
)
|
||||
loc_xml = TREE / "packages/apps/Settings/res/xml/location_settings.xml"
|
||||
strings = TREE / "packages/apps/Settings/res/values/strings.xml"
|
||||
gps = TREE / "device/google/sunfish/gps.conf"
|
||||
init_rc = TREE / "device/google/sunfish/init.hardware.rc"
|
||||
controller = (
|
||||
TREE
|
||||
/ "packages/apps/Settings/src/com/android/settings/location/ForceDisableSuplPrefController.java"
|
||||
)
|
||||
|
||||
must(
|
||||
settings,
|
||||
""" public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
|
||||
""",
|
||||
""" public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
|
||||
|
||||
/**
|
||||
* Force disable Secure User Plane Location (SUPL), 0 or 1.
|
||||
* Default 0 keeps carrier SUPL. AXP/Graphene toggle, """
|
||||
+ MARKER
|
||||
+ """.
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FORCE_DISABLE_SUPL = "force_disable_supl";
|
||||
|
||||
/** @hide */
|
||||
public static final int FORCE_DISABLE_SUPL_DEFAULT = 0;
|
||||
""",
|
||||
already="FORCE_DISABLE_SUPL",
|
||||
)
|
||||
|
||||
must(
|
||||
settings,
|
||||
""" /** @hide */
|
||||
public static final int FORCE_DISABLE_SUPL_DEFAULT = 0;
|
||||
""",
|
||||
""" /** @hide */
|
||||
public static final int FORCE_DISABLE_SUPL_DEFAULT = 0;
|
||||
|
||||
/**
|
||||
* Stop LPP, the framework XTRA download, and loc_launcher
|
||||
* (xtra-daemon, lowi, IZat). 0 or 1. Default 0 keeps Lineage
|
||||
* assistance. Binaries stay installed. """
|
||||
+ MARKER
|
||||
+ """.
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FORCE_DISABLE_LOCATION_ASSIST =
|
||||
"force_disable_location_assist";
|
||||
|
||||
/** @hide */
|
||||
public static final int FORCE_DISABLE_LOCATION_ASSIST_DEFAULT = 0;
|
||||
""",
|
||||
already="FORCE_DISABLE_LOCATION_ASSIST",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_cfg,
|
||||
"import android.os.SystemProperties;\n",
|
||||
"import android.os.SystemProperties;\nimport android.provider.Settings;\n",
|
||||
already="import android.provider.Settings;\n",
|
||||
)
|
||||
must(
|
||||
gnss_cfg,
|
||||
"import android.util.Log;\n",
|
||||
"import android.util.Log;\nimport android.util.Slog;\n",
|
||||
already="import android.util.Slog;\n",
|
||||
)
|
||||
must(
|
||||
gnss_cfg,
|
||||
""" loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_VENDOR_FILE);
|
||||
loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_SYSTEM_FILE);
|
||||
""",
|
||||
""" loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_VENDOR_FILE);
|
||||
loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_SYSTEM_FILE);
|
||||
applyConfigOverrides(mContext, mProperties); /* """
|
||||
+ MARKER
|
||||
+ """ */
|
||||
""",
|
||||
already="applyConfigOverrides(mContext, mProperties)",
|
||||
)
|
||||
if "void applyConfigOverrides(" not in gnss_cfg.read_text():
|
||||
text = gnss_cfg.read_text()
|
||||
needle = " private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);\n"
|
||||
insert = needle + """
|
||||
/** """ + MARKER + """: optional SUPL off. Default leaves carrier SUPL_MODE. */
|
||||
private static void applyConfigOverrides(Context ctx, Properties props) {
|
||||
String key = Settings.Global.FORCE_DISABLE_SUPL;
|
||||
int def = Settings.Global.FORCE_DISABLE_SUPL_DEFAULT;
|
||||
if (Settings.Global.getInt(ctx.getContentResolver(), key, def) == 1) {
|
||||
props.setProperty(CONFIG_SUPL_MODE, "0");
|
||||
Slog.d(TAG, "SUPL is force disabled");
|
||||
}
|
||||
}
|
||||
"""
|
||||
if needle not in text:
|
||||
sys.exit("native_set_es_extension_sec missing")
|
||||
gnss_cfg.write_text(text.replace(needle, insert, 1))
|
||||
|
||||
must(
|
||||
gnss_cfg,
|
||||
""" if (Settings.Global.getInt(ctx.getContentResolver(), key, def) == 1) {
|
||||
props.setProperty(CONFIG_SUPL_MODE, "0");
|
||||
Slog.d(TAG, "SUPL is force disabled");
|
||||
}
|
||||
}
|
||||
""",
|
||||
""" if (Settings.Global.getInt(ctx.getContentResolver(), key, def) == 1) {
|
||||
props.setProperty(CONFIG_SUPL_MODE, "0");
|
||||
Slog.d(TAG, "SUPL is force disabled");
|
||||
}
|
||||
String assist = Settings.Global.FORCE_DISABLE_LOCATION_ASSIST;
|
||||
int assistDef = Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT;
|
||||
if (Settings.Global.getInt(ctx.getContentResolver(), assist, assistDef) == 1) {
|
||||
// LPPE is carried by the LPP session. This HAL only has a setter
|
||||
// for LPP_PROFILE, and this override runs after carrier config.
|
||||
props.setProperty(CONFIG_LPP_PROFILE, "0");
|
||||
Slog.d(TAG, "LPP assistance stopped");
|
||||
}
|
||||
}
|
||||
""",
|
||||
already="LPP assistance stopped",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.ASSISTED_GPS_ENABLED),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
toggleXtraDaemon();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
""" mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.ASSISTED_GPS_ENABLED),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
toggleXtraDaemon();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
|
||||
/* """
|
||||
+ MARKER
|
||||
+ """ */
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_SUPL),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
already="Settings.Global.FORCE_DISABLE_SUPL",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_SUPL),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
""" Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_SUPL),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_LOCATION_ASSIST),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
already="Settings.Global.FORCE_DISABLE_LOCATION_ASSIST",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" toggleXtraDaemon();
|
||||
}
|
||||
|
||||
public GnssLocationProvider(Context context, GnssNative gnssNative,
|
||||
""",
|
||||
""" applyLocationAssistPrivacy();
|
||||
toggleXtraDaemon();
|
||||
}
|
||||
|
||||
public GnssLocationProvider(Context context, GnssNative gnssNative,
|
||||
""",
|
||||
already="applyLocationAssistPrivacy();",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" if (!isAssistedGpsEnabled()) {
|
||||
// PSDS download disabled by system setting, don't try
|
||||
Log.d(TAG, "handleDownloadPsdsData() called when PSDS disabled by system setting");
|
||||
return;
|
||||
}
|
||||
""",
|
||||
""" if (!isAssistedGpsEnabled()) {
|
||||
// PSDS download disabled by system setting, don't try
|
||||
Log.d(TAG, "handleDownloadPsdsData() called when PSDS disabled by system setting");
|
||||
return;
|
||||
}
|
||||
if (Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT) == 1) {
|
||||
Log.d(TAG, "handleDownloadPsdsData() skipped: location assistance stopped");
|
||||
return;
|
||||
}
|
||||
""",
|
||||
already="location assistance stopped",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" private void toggleXtraDaemon() {
|
||||
Log.i(TAG, "Toggling xtra-daemon via property");
|
||||
SystemProperties.set("persist.sys.xtra-daemon.enabled",
|
||||
Boolean.toString(isAssistedGpsEnabled()));
|
||||
}
|
||||
""",
|
||||
""" /** """
|
||||
+ MARKER
|
||||
+ """ Stop loc_launcher. Does not delete xtra-daemon, lowi or IZat. */
|
||||
private void applyLocationAssistPrivacy() {
|
||||
boolean stop = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT) == 1;
|
||||
SystemProperties.set("persist.sys.axp.loc_privacy", stop ? "1" : "0");
|
||||
}
|
||||
|
||||
private void toggleXtraDaemon() {
|
||||
Log.i(TAG, "Toggling xtra-daemon via property");
|
||||
SystemProperties.set("persist.sys.xtra-daemon.enabled",
|
||||
Boolean.toString(isAssistedGpsEnabled()));
|
||||
}
|
||||
""",
|
||||
already="persist.sys.axp.loc_privacy",
|
||||
)
|
||||
|
||||
old_setid = """ TelephonyManager phone = (TelephonyManager)
|
||||
mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
int type = AGPS_SETID_TYPE_NONE;
|
||||
String setId = null;
|
||||
final Boolean isEmergency = mNIHandler.getInEmergency();
|
||||
|
||||
// Unless we are in an emergency, do not provide sensitive subscriber information
|
||||
// to SUPL servers.
|
||||
if (!isEmergency) {
|
||||
mGnssNative.setAgpsSetId(type, "");
|
||||
return;
|
||||
}
|
||||
|
||||
int subId = SubscriptionManager.getDefaultDataSubscriptionId();
|
||||
if (mGnssConfiguration.isActiveSimEmergencySuplEnabled() && isEmergency
|
||||
&& mNetworkConnectivityHandler.getActiveSubId() >= 0) {
|
||||
subId = mNetworkConnectivityHandler.getActiveSubId();
|
||||
}
|
||||
if (SubscriptionManager.isValidSubscriptionId(subId)) {
|
||||
phone = phone.createForSubscriptionId(subId);
|
||||
}
|
||||
if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) {
|
||||
setId = phone.getSubscriberId();
|
||||
if (setId != null) {
|
||||
// This means the framework has the SIM card.
|
||||
type = AGPS_SETID_TYPE_IMSI;
|
||||
}
|
||||
} else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) {
|
||||
setId = phone.getLine1Number();
|
||||
if (setId != null) {
|
||||
// This means the framework has the SIM card.
|
||||
type = AGPS_SETID_TYPE_MSISDN;
|
||||
}
|
||||
}
|
||||
|
||||
mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId);
|
||||
"""
|
||||
new_setid = """ // """ + MARKER + """: AXP/Divest. Never send IMSI or the phone number
|
||||
// to a SUPL server, including during an emergency call. LOS 23 already
|
||||
// skips this outside emergency. Control-plane A-GNSS is unchanged.
|
||||
// flags is read so the unused-parameter check stays quiet.
|
||||
if (flags != 0 && Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "ignoring SUPL set-id request flags=" + flags);
|
||||
}
|
||||
mGnssNative.setAgpsSetId(AGPS_SETID_TYPE_NONE, "");
|
||||
"""
|
||||
prov = gnss_prov.read_text()
|
||||
if old_setid in prov:
|
||||
gnss_prov.write_text(prov.replace(old_setid, new_setid, 1))
|
||||
elif "ignoring SUPL set-id request flags" not in prov:
|
||||
short = """ // """ + MARKER + """: AXP/Divest. Never send IMSI or the phone number
|
||||
// to a SUPL server, including during an emergency call. LOS 23 already
|
||||
// skips this outside emergency. Control-plane A-GNSS is unchanged.
|
||||
mGnssNative.setAgpsSetId(AGPS_SETID_TYPE_NONE, "");
|
||||
"""
|
||||
if short not in prov:
|
||||
sys.exit("setAgpsSetId block missing")
|
||||
gnss_prov.write_text(prov.replace(short, new_setid, 1))
|
||||
|
||||
must(
|
||||
loc_xml,
|
||||
""" settings:controller="com.android.settings.location.LocationServicesPreferenceController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
""" settings:controller="com.android.settings.location.LocationServicesPreferenceController"/>
|
||||
|
||||
<!-- """
|
||||
+ MARKER
|
||||
+ """: default off, so carrier SUPL stays -->
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="force_disable_supl"
|
||||
android:title="@string/force_disable_supl_title"
|
||||
android:summary="@string/force_disable_supl_summary"
|
||||
settings:controller="com.android.settings.location.ForceDisableSuplPrefController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
already='android:key="force_disable_supl"',
|
||||
)
|
||||
|
||||
must(
|
||||
loc_xml,
|
||||
""" settings:controller="com.android.settings.location.ForceDisableSuplPrefController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
""" settings:controller="com.android.settings.location.ForceDisableSuplPrefController"/>
|
||||
|
||||
<!-- """
|
||||
+ MARKER
|
||||
+ """: default off. On stops LPP, XTRA and IZat. Binaries stay. -->
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="force_disable_location_assist"
|
||||
android:title="@string/force_disable_location_assist_title"
|
||||
android:summary="@string/force_disable_location_assist_summary"
|
||||
settings:controller="com.android.settings.location.ForceDisableLocationAssistPrefController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
already='android:key="force_disable_location_assist"',
|
||||
)
|
||||
|
||||
must(
|
||||
strings,
|
||||
""" <string name="location_services_preference_title">Location services</string>
|
||||
""",
|
||||
""" <string name="location_services_preference_title">Location services</string>
|
||||
<!-- """
|
||||
+ MARKER
|
||||
+ """ -->
|
||||
<string name="force_disable_supl_title">Force disable Secure User Plane Location (SUPL)</string>
|
||||
<string name="force_disable_supl_summary">Always disable SUPL assisted location support regardless of carrier configuration or emergency call status. Does not disable control-plane A-GNSS. IMSI and the phone number are never sent to a SUPL server.</string>
|
||||
""",
|
||||
already="force_disable_supl_title",
|
||||
)
|
||||
|
||||
must(
|
||||
strings,
|
||||
""" <string name="force_disable_supl_summary">Always disable SUPL assisted location support regardless of carrier configuration or emergency call status. Does not disable control-plane A-GNSS. IMSI and the phone number are never sent to a SUPL server.</string>
|
||||
""",
|
||||
""" <string name="force_disable_supl_summary">Always disable SUPL assisted location support regardless of carrier configuration or emergency call status. Does not disable control-plane A-GNSS. IMSI and the phone number are never sent to a SUPL server.</string>
|
||||
<string name="force_disable_location_assist_title">Stop extra location assistance</string>
|
||||
<string name="force_disable_location_assist_summary">Stops LTE positioning (LPP/LPPE), XTRA orbit downloads, and Qualcomm IZat. Satellite fixes keep working. The programs stay installed. SUPL has its own switch.</string>
|
||||
""",
|
||||
already="force_disable_location_assist_title",
|
||||
)
|
||||
|
||||
if not controller.exists():
|
||||
controller.write_text(
|
||||
"""package com.android.settings.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** """
|
||||
+ MARKER
|
||||
+ """ AXP/Graphene toggle. Default off. */
|
||||
public class ForceDisableSuplPrefController extends TogglePreferenceController {
|
||||
|
||||
public ForceDisableSuplPrefController(Context ctx, String key) {
|
||||
super(ctx, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (!Process.myUserHandle().isSystem()) {
|
||||
return DISABLED_FOR_USER;
|
||||
}
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.Global.getInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_SUPL,
|
||||
Settings.Global.FORCE_DISABLE_SUPL_DEFAULT) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
return Settings.Global.putInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_SUPL,
|
||||
isChecked ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return NO_RES;
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
assist_controller = (
|
||||
TREE
|
||||
/ "packages/apps/Settings/src/com/android/settings/location/ForceDisableLocationAssistPrefController.java"
|
||||
)
|
||||
if not assist_controller.exists():
|
||||
assist_controller.write_text(
|
||||
"""package com.android.settings.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** """
|
||||
+ MARKER
|
||||
+ """ Default off. Stops assistance; does not delete blobs. */
|
||||
public class ForceDisableLocationAssistPrefController extends TogglePreferenceController {
|
||||
|
||||
public ForceDisableLocationAssistPrefController(Context ctx, String key) {
|
||||
super(ctx, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (!Process.myUserHandle().isSystem()) {
|
||||
return DISABLED_FOR_USER;
|
||||
}
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.Global.getInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
return Settings.Global.putInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
isChecked ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return NO_RES;
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
must(
|
||||
init_rc,
|
||||
"""on property:persist.sys.xtra-daemon.enabled=*
|
||||
restart loc_launcher
|
||||
""",
|
||||
"""# """
|
||||
+ MARKER
|
||||
+ """
|
||||
# 1 stops loc_launcher (xtra-daemon, lowi, IZat). Binaries stay.
|
||||
# The xtra property must not restart the service while that stop is on.
|
||||
on property:persist.sys.axp.loc_privacy=1
|
||||
stop loc_launcher
|
||||
exec_background -- /system/bin/toybox killall xtra-daemon lowi-server
|
||||
|
||||
on property:persist.sys.axp.loc_privacy=0
|
||||
start loc_launcher
|
||||
|
||||
on property:sys.boot_completed=1 && property:persist.sys.axp.loc_privacy=1
|
||||
stop loc_launcher
|
||||
exec_background -- /system/bin/toybox killall xtra-daemon lowi-server
|
||||
|
||||
on property:persist.sys.xtra-daemon.enabled=* && property:persist.sys.axp.loc_privacy=0
|
||||
restart loc_launcher
|
||||
""",
|
||||
already="persist.sys.axp.loc_privacy",
|
||||
)
|
||||
|
||||
raw = gps.read_bytes()
|
||||
old_ntp = b"NTP_SERVER = time.google.com"
|
||||
new_ntp = b"NTP_SERVER = 2.android.pool.ntp.org"
|
||||
if new_ntp not in raw:
|
||||
if old_ntp not in raw:
|
||||
sys.exit("NTP_SERVER line missing")
|
||||
raw = raw.replace(old_ntp, new_ntp, 1)
|
||||
gps.write_bytes(raw)
|
||||
print("supl privacy applied")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: AXP Yama ptrace_scope, active at 2.
|
||||
|
||||
AXP LOS 22 init.rc sets /proc/sys/kernel/yama/ptrace_scope from
|
||||
persist.native_debug (true -> 0, false -> 2). GOLDEN's kernel has Yama
|
||||
off, so those lines do nothing there. This tree builds Yama, so init
|
||||
writes 2 at boot. persist.native_debug=true still opens ptrace.
|
||||
|
||||
Writing that sysctl needs CAP_SYS_PTRACE. AOSP neverallows it for init;
|
||||
the exception is the one in AXP's ptrace_scope sepolicy patch. The node
|
||||
is labeled proc_security, which init may already read and write.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path("/srv/rom/src/lineage")
|
||||
MARKER = "sunfish-a16-009-yama-ptrace"
|
||||
|
||||
RC_BOOT_OLD = " write /proc/sys/kernel/randomize_va_space 2\n"
|
||||
RC_BOOT_NEW = (
|
||||
" write /proc/sys/kernel/randomize_va_space 2\n"
|
||||
" # sunfish-a16-009-yama-ptrace: AXP scope 2 unless native debug is on.\n"
|
||||
" write /proc/sys/kernel/yama/ptrace_scope 2\n"
|
||||
)
|
||||
RC_PROP_OLD = (
|
||||
" write /proc/sys/net/ipv4/tcp_default_init_rwnd ${net.tcp_def_init_rwnd}\n"
|
||||
)
|
||||
RC_PROP_NEW = (
|
||||
" write /proc/sys/net/ipv4/tcp_default_init_rwnd ${net.tcp_def_init_rwnd}\n"
|
||||
"\n"
|
||||
"on property:persist.native_debug=true\n"
|
||||
" write /proc/sys/kernel/yama/ptrace_scope 0\n"
|
||||
"\n"
|
||||
"on property:persist.native_debug=false\n"
|
||||
" write /proc/sys/kernel/yama/ptrace_scope 2\n"
|
||||
)
|
||||
|
||||
GENFS_OLD = "genfscon proc /sys/kernel/usermodehelper u:object_r:usermodehelper:s0\n"
|
||||
GENFS_NEW = (
|
||||
"genfscon proc /sys/kernel/usermodehelper u:object_r:usermodehelper:s0\n"
|
||||
"genfscon proc /sys/kernel/yama/ptrace_scope u:object_r:proc_security:s0\n"
|
||||
)
|
||||
|
||||
PROP_OLD = "persist.debug. u:object_r:persist_debug_prop:s0\n"
|
||||
PROP_NEW = (
|
||||
"persist.debug. u:object_r:persist_debug_prop:s0\n"
|
||||
"persist.native_debug u:object_r:system_prop:s0\n"
|
||||
)
|
||||
|
||||
INIT_OLD = """allow init {
|
||||
proc_security
|
||||
}:file rw_file_perms;
|
||||
"""
|
||||
INIT_NEW = """allow init {
|
||||
proc_security
|
||||
}:file rw_file_perms;
|
||||
|
||||
# sunfish-a16-009-yama-ptrace: CAP_SYS_PTRACE to set ptrace_scope.
|
||||
allow init self:global_capability_class_set sys_ptrace;
|
||||
"""
|
||||
|
||||
NEVER_END = "} self:global_capability_class_set sys_ptrace;"
|
||||
|
||||
|
||||
def must(path: pathlib.Path, old: str, new: str, already: str) -> None:
|
||||
text = path.read_text()
|
||||
if already in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def loosen_sys_ptrace(path: pathlib.Path) -> None:
|
||||
text = path.read_text()
|
||||
idx = text.find(NEVER_END)
|
||||
if idx < 0:
|
||||
return
|
||||
start = text.rfind("neverallow {", 0, idx)
|
||||
if start < 0:
|
||||
sys.exit(f"neverallow block missing in {path}")
|
||||
block = text[start:idx]
|
||||
if "\n -init\n" in block:
|
||||
return
|
||||
if "\n domain\n" not in block:
|
||||
sys.exit(f"domain line missing in sys_ptrace neverallow {path}")
|
||||
new_block = block.replace("\n domain\n", "\n domain\n -init\n", 1)
|
||||
path.write_text(text[:start] + new_block + text[idx:])
|
||||
|
||||
|
||||
def main() -> None:
|
||||
rc = TREE / "system/core/rootdir/init.rc"
|
||||
must(rc, RC_BOOT_OLD, RC_BOOT_NEW, MARKER)
|
||||
must(rc, RC_PROP_OLD, RC_PROP_NEW, "on property:persist.native_debug=true")
|
||||
|
||||
se = TREE / "system/sepolicy"
|
||||
must(
|
||||
se / "private/init.te",
|
||||
INIT_OLD,
|
||||
INIT_NEW,
|
||||
"allow init self:global_capability_class_set sys_ptrace;",
|
||||
)
|
||||
loosen_sys_ptrace(se / "private/domain.te")
|
||||
must(se / "private/genfs_contexts", GENFS_OLD, GENFS_NEW, "yama/ptrace_scope")
|
||||
must(se / "private/property_contexts", PROP_OLD, PROP_NEW, "persist.native_debug")
|
||||
|
||||
api = se / "prebuilts/api"
|
||||
for domain in api.glob("*/private/domain.te"):
|
||||
loosen_sys_ptrace(domain)
|
||||
for genfs in api.glob("*/private/genfs_contexts"):
|
||||
text = genfs.read_text()
|
||||
if "yama/ptrace_scope" in text or GENFS_OLD not in text:
|
||||
continue
|
||||
genfs.write_text(text.replace(GENFS_OLD, GENFS_NEW, 1))
|
||||
for props in api.glob("*/private/property_contexts"):
|
||||
text = props.read_text()
|
||||
if "persist.native_debug" in text or PROP_OLD not in text:
|
||||
continue
|
||||
props.write_text(text.replace(PROP_OLD, PROP_NEW, 1))
|
||||
|
||||
# Current policy must still exclude init, or the write is neverallowed.
|
||||
live = (se / "private/domain.te").read_text()
|
||||
end = live.find(NEVER_END)
|
||||
start = live.rfind("neverallow {", 0, end)
|
||||
if "\n -init\n" not in live[start:end]:
|
||||
sys.exit("init still neverallowed from sys_ptrace")
|
||||
print("yama ptrace_scope applied")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -69,12 +69,12 @@ guarantee). Do not relock the bootloader on this Magisk track.
|
||||
|
||||
## Branding
|
||||
|
||||
`TARGET_UNOFFICIAL_BUILD_ID=AXP-Resurection-Pro` is set at the **top** of
|
||||
`device/google/sunfish/lineage_sunfish.mk` (before inheriting
|
||||
`vendor/lineage` → `version.mk`). Helper:
|
||||
`apply_009_unofficial_build_id.py`. **Pro** = full Magisk resurrection track
|
||||
(not a future slim/minimal variant). Mirrors GOLDEN’s `…-sunfish-pro` /
|
||||
releasetype `PRO` intent without patching `vendor/lineage/config/version.mk`.
|
||||
Ship identity follows AXP/GOLDEN, not Lineage's unofficial channel.
|
||||
GOLDEN (`22.2-2026.003-sunfish-pro`) reports `ro.lineage.releasetype=PRO`,
|
||||
`ro.build.tags=release-keys`, and a version ending in `sunfish-pro`.
|
||||
`TARGET_UNOFFICIAL_BUILD_ID` forces Lineage `UNOFFICIAL` and is not that
|
||||
scheme. The next bacon sets `PRO` + `release-keys` + `…-sunfish-pro`.
|
||||
**Pro** remains the full Magisk track (AXP PRO, not SLIM).
|
||||
|
||||
`branding.mk` adds `ro.axp.resurection.track=pro`. Ship scripts also publish
|
||||
`AXP-Resurection-Pro-<ver>-<date>-sunfish.zip` as a hardlink/copy of the
|
||||
|
||||
@@ -30,7 +30,9 @@ while IFS= read -r rel || [[ -n "$rel" ]]; do
|
||||
fail=$((fail + 1))
|
||||
continue
|
||||
fi
|
||||
args=(-p1 --batch -d "$KERNEL_DIR")
|
||||
# Never let GNU patch auto-answer "Assuming -R": the LOS base can already
|
||||
# contain a patch's intended result. Reversing it is a regression, not OK.
|
||||
args=(-p1 --batch --forward -d "$KERNEL_DIR")
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
args+=(--dry-run)
|
||||
fi
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
# off; CONFIG_LSM already lists yama but SECURITY_YAMA was unset so the LSM
|
||||
# never built.
|
||||
#
|
||||
# Does NOT apply high-offset CVE leftovers (nf_tables deliberately skipped) or
|
||||
# CVE-2022-49980 (denylist until lock-scope port).
|
||||
# Does NOT apply high-offset CVE leftovers (nf_tables deliberately skipped).
|
||||
# CVE-2022-49980's one-liner stays on the denylist. The bacon applies
|
||||
# ports/cve-2022-49980-lock-scope.patch after the CVE lists.
|
||||
#
|
||||
# USERFAULTFD: GOLDEN's running 4.14.355 config leaves it unset. LOS 23
|
||||
# sunfish_defconfig turns it on. This kernel has no UFFDIO_MOVE (that ioctl
|
||||
# is 6.1+), so ART only opens a fd and times out. Match GOLDEN.
|
||||
#
|
||||
# Usage: apply_uss5_1_defconfig.sh <kernel-tree>
|
||||
set -euo pipefail
|
||||
@@ -17,15 +22,14 @@ DEF="$K/arch/arm64/configs/sunfish_defconfig"
|
||||
test -f "$DEF"
|
||||
test -f "$K/security/yama/Kconfig"
|
||||
|
||||
for k in SECURITY_YAMA SLAB_FREELIST_RANDOM; do
|
||||
for k in SECURITY_YAMA SLAB_FREELIST_RANDOM USERFAULTFD HAVE_ARCH_USERFAULTFD_MINOR; do
|
||||
sed -i "/CONFIG_${k}/d" "$DEF"
|
||||
# drop "# CONFIG_FOO is not set" lines too (sed above only matches CONFIG_FOO=)
|
||||
sed -i "/# CONFIG_${k} is not set/d" "$DEF"
|
||||
done
|
||||
|
||||
{
|
||||
echo "CONFIG_SECURITY_YAMA=y"
|
||||
echo "CONFIG_SLAB_FREELIST_RANDOM=y"
|
||||
echo "# CONFIG_USERFAULTFD is not set"
|
||||
} >> "$DEF"
|
||||
|
||||
echo "OK: US-S5-1 defconfig (YAMA + SLAB_FREELIST_RANDOM) on $K"
|
||||
echo "OK: US-S5-1 defconfig (YAMA + SLAB_FREELIST_RANDOM, USERFAULTFD off) on $K"
|
||||
@@ -1,6 +1,7 @@
|
||||
# relative to AXP kernel_patches
|
||||
# LAB 2026-10-01: alone ⇒ Google-logo hang (udc_lock recursive deadlock on
|
||||
# msm-4.14; needs lock-scope companion, not one-liner). Do not re-apply.
|
||||
# msm-4.14). Companion is ports/cve-2022-49980-lock-scope.patch (UAF fix
|
||||
# plus uevents outside the lock). Do not apply the one-liner by itself.
|
||||
CVE-2022-49980/ANY/0001.patch
|
||||
CVE-2017-15832/qcacld-3.0/0001.patch
|
||||
CVE-2021-29648/^5.11/0001.patch
|
||||
|
||||
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
From: Daniel Micay <danielmicay@gmail.com>
|
||||
Subject: [PATCH] add vmalloc alloc_size attributes
|
||||
|
||||
Port of AXP/Graphene
|
||||
0008-Graphene-Kernel_Hardening-allocsize/4.14/0007.patch onto the
|
||||
Lineage msm-4.14 vmalloc.h. That header gained vmalloc_user_node_flags
|
||||
and dropped the pgprot argument of __vmalloc, so the upstream hunk no
|
||||
longer applies. The attribute is the same one AXP adds: alloc_size(1)
|
||||
on the size argument.
|
||||
|
||||
Signed-off-by: Daniel Micay <danielmicay@gmail.com>
|
||||
---
|
||||
include/linux/vmalloc.h | 22 +++++++++++-----------
|
||||
1 file changed, 11 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/include/linux/vmalloc.h
|
||||
+++ b/include/linux/vmalloc.h
|
||||
@@ -76,20 +76,20 @@
|
||||
static inline unsigned long vmalloc_nr_pages(void) { return 0; }
|
||||
#endif
|
||||
|
||||
-extern void *vmalloc(unsigned long size);
|
||||
-extern void *vzalloc(unsigned long size);
|
||||
-extern void *vmalloc_user(unsigned long size);
|
||||
-extern void *vmalloc_node(unsigned long size, int node);
|
||||
-extern void *vzalloc_node(unsigned long size, int node);
|
||||
-extern void *vmalloc_user_node_flags(unsigned long size, int node, gfp_t flags);
|
||||
-extern void *vmalloc_exec(unsigned long size);
|
||||
-extern void *vmalloc_32(unsigned long size);
|
||||
-extern void *vmalloc_32_user(unsigned long size);
|
||||
-extern void *__vmalloc(unsigned long size, gfp_t gfp_mask);
|
||||
+extern void *vmalloc(unsigned long size) __attribute__((alloc_size(1)));
|
||||
+extern void *vzalloc(unsigned long size) __attribute__((alloc_size(1)));
|
||||
+extern void *vmalloc_user(unsigned long size) __attribute__((alloc_size(1)));
|
||||
+extern void *vmalloc_node(unsigned long size, int node) __attribute__((alloc_size(1)));
|
||||
+extern void *vzalloc_node(unsigned long size, int node) __attribute__((alloc_size(1)));
|
||||
+extern void *vmalloc_user_node_flags(unsigned long size, int node, gfp_t flags) __attribute__((alloc_size(1)));
|
||||
+extern void *vmalloc_exec(unsigned long size) __attribute__((alloc_size(1)));
|
||||
+extern void *vmalloc_32(unsigned long size) __attribute__((alloc_size(1)));
|
||||
+extern void *vmalloc_32_user(unsigned long size) __attribute__((alloc_size(1)));
|
||||
+extern void *__vmalloc(unsigned long size, gfp_t gfp_mask) __attribute__((alloc_size(1)));
|
||||
extern void *__vmalloc_node_range(unsigned long size, unsigned long align,
|
||||
unsigned long start, unsigned long end, gfp_t gfp_mask,
|
||||
pgprot_t prot, unsigned long vm_flags, int node,
|
||||
- const void *caller);
|
||||
+ const void *caller) __attribute__((alloc_size(1)));
|
||||
#ifndef CONFIG_MMU
|
||||
extern void *__vmalloc_node_flags(unsigned long size, int node, gfp_t flags);
|
||||
static inline void *__vmalloc_node_flags_caller(unsigned long size, int node,
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
From: Alan Stern <stern@rowland.harvard.edu>
|
||||
Subject: [PATCH] USB: gadget: fix udc_lock scope around usb_udc_uevent
|
||||
|
||||
CVE-2022-49980 (2191c00855b0) takes udc_lock inside usb_udc_uevent().
|
||||
On msm-4.14 that callback still runs synchronously from device_add()
|
||||
and kobject_uevent() while the same thread already holds udc_lock, so
|
||||
the mutex deadlocks and the phone hangs on the Google logo.
|
||||
|
||||
Linux 6.1 usb_add_gadget() / gadget_bind_driver() only hold udc_lock
|
||||
around the list and the driver pointer. This keeps the 4.14 call
|
||||
shape and moves those uevents outside the lock, then applies the
|
||||
UAF fix. Do not apply 2191c00855b0 without this.
|
||||
|
||||
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
---
|
||||
|
||||
--- a/drivers/usb/gadget/udc/core.c
|
||||
+++ b/drivers/usb/gadget/udc/core.c
|
||||
@@ -1229,11 +1229,18 @@
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_add_tail(&udc->list, &udc_list);
|
||||
+ mutex_unlock(&udc_lock);
|
||||
|
||||
+ /*
|
||||
+ * device_add() emits a uevent that calls usb_udc_uevent(), which
|
||||
+ * takes udc_lock. Same for device_del() on the error path. v6.1
|
||||
+ * usb_add_gadget() only holds the mutex around the list update.
|
||||
+ */
|
||||
ret = device_add(&udc->dev);
|
||||
if (ret)
|
||||
goto err_unlist_udc;
|
||||
|
||||
+ mutex_lock(&udc_lock);
|
||||
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
|
||||
udc->vbus = true;
|
||||
|
||||
@@ -1247,9 +1254,11 @@
|
||||
return 0;
|
||||
|
||||
err_del_udc:
|
||||
+ mutex_unlock(&udc_lock);
|
||||
device_del(&udc->dev);
|
||||
|
||||
err_unlist_udc:
|
||||
+ mutex_lock(&udc_lock);
|
||||
list_del(&udc->list);
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
@@ -1313,7 +1322,14 @@
|
||||
dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
|
||||
udc->driver->function);
|
||||
|
||||
+ /*
|
||||
+ * Caller holds udc_lock. usb_udc_uevent() takes it too, so the
|
||||
+ * CHANGE uevent has to run outside the lock. Driver is still bound;
|
||||
+ * the callback re-locks to read it.
|
||||
+ */
|
||||
+ mutex_unlock(&udc_lock);
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
+ mutex_lock(&udc_lock);
|
||||
|
||||
usb_gadget_disconnect(udc->gadget);
|
||||
udc->driver->disconnect(udc->gadget);
|
||||
@@ -1383,7 +1399,10 @@
|
||||
}
|
||||
usb_udc_connect_control(udc);
|
||||
|
||||
+ /* Same deadlock as remove: uevent re-enters udc_lock. */
|
||||
+ mutex_unlock(&udc_lock);
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
+ mutex_lock(&udc_lock);
|
||||
return 0;
|
||||
err1:
|
||||
if (ret != -EISNAM)
|
||||
@@ -1611,13 +1630,14 @@
|
||||
return ret;
|
||||
}
|
||||
|
||||
- if (udc->driver) {
|
||||
+ mutex_lock(&udc_lock);
|
||||
+ if (udc->driver)
|
||||
ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
|
||||
udc->driver->function);
|
||||
- if (ret) {
|
||||
- dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
|
||||
- return ret;
|
||||
- }
|
||||
+ mutex_unlock(&udc_lock);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
+424
@@ -0,0 +1,424 @@
|
||||
From: Daniel Micay <danielmicay@gmail.com>
|
||||
Subject: [PATCH] make sysctl constants read-only
|
||||
|
||||
Port of AXP/Graphene ro/4.14/0007.patch and ro/4.14/0034.patch.
|
||||
Declarations still match; hunk context does not, and this tree has no
|
||||
net/decnet/sysctl_net_decnet.c. Same __read_only (__ro_after_init)
|
||||
annotations AXP applies, on the files that exist here.
|
||||
|
||||
Signed-off-by: Daniel Micay <danielmicay@gmail.com>
|
||||
---
|
||||
|
||||
--- a/fs/pipe.c
|
||||
+++ b/fs/pipe.c
|
||||
@@ -53,7 +53,7 @@
|
||||
/*
|
||||
* Minimum pipe size, as required by POSIX
|
||||
*/
|
||||
-unsigned int pipe_min_size = PAGE_SIZE;
|
||||
+unsigned int pipe_min_size __read_only = PAGE_SIZE;
|
||||
|
||||
/* Maximum allocatable pages per user. Hard limit is unset by default, soft
|
||||
* matches default values.
|
||||
--- a/kernel/sysctl.c
|
||||
+++ b/kernel/sysctl.c
|
||||
@@ -121,48 +121,48 @@
|
||||
|
||||
/* Constants used for minimum and maximum */
|
||||
#ifdef CONFIG_LOCKUP_DETECTOR
|
||||
-static int sixty = 60;
|
||||
+static int sixty __read_only = 60;
|
||||
#endif
|
||||
|
||||
-static int __maybe_unused neg_one = -1;
|
||||
-static int __maybe_unused neg_three = -3;
|
||||
+static int __maybe_unused neg_one __read_only = -1;
|
||||
+static int __maybe_unused neg_three __read_only = -3;
|
||||
|
||||
-static int zero;
|
||||
-static int __maybe_unused one = 1;
|
||||
-static int __maybe_unused two = 2;
|
||||
-static int __maybe_unused three = 3;
|
||||
-static int __maybe_unused four = 4;
|
||||
+static int zero __read_only;
|
||||
+static int __maybe_unused one __read_only = 1;
|
||||
+static int __maybe_unused two __read_only = 2;
|
||||
+static int __maybe_unused three __read_only = 3;
|
||||
+static int __maybe_unused four __read_only = 4;
|
||||
static int int_max = INT_MAX;
|
||||
-static unsigned long zero_ul;
|
||||
-static unsigned long one_ul = 1;
|
||||
-static unsigned long long_max = LONG_MAX;
|
||||
-static int one_hundred = 100;
|
||||
-static int one_thousand = 1000;
|
||||
+static unsigned long zero_ul __read_only;
|
||||
+static unsigned long one_ul __read_only = 1;
|
||||
+static unsigned long long_max __read_only = LONG_MAX;
|
||||
+static int one_hundred __read_only = 100;
|
||||
+static int one_thousand __read_only = 1000;
|
||||
#ifdef CONFIG_SCHED_WALT
|
||||
-static int two_million = 2000000;
|
||||
+static int two_million __read_only = 2000000;
|
||||
#endif
|
||||
#ifdef CONFIG_PRINTK
|
||||
-static int ten_thousand = 10000;
|
||||
+static int ten_thousand __read_only = 10000;
|
||||
#endif
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
-static int six_hundred_forty_kb = 640 * 1024;
|
||||
+static int six_hundred_forty_kb __read_only = 640 * 1024;
|
||||
#endif
|
||||
static int __maybe_unused two_hundred_million __read_only = 200000000;
|
||||
static int two_hundred_fifty_five __read_only = 255;
|
||||
|
||||
/* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */
|
||||
-static unsigned long dirty_bytes_min = 2 * PAGE_SIZE;
|
||||
+static unsigned long dirty_bytes_min __read_only = 2 * PAGE_SIZE;
|
||||
|
||||
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
|
||||
-static int maxolduid = 65535;
|
||||
-static int minolduid;
|
||||
+static int maxolduid __read_only = 65535;
|
||||
+static int minolduid __read_only;
|
||||
|
||||
-static int ngroups_max = NGROUPS_MAX;
|
||||
+static int ngroups_max __read_only = NGROUPS_MAX;
|
||||
static const int cap_last_cap = CAP_LAST_CAP;
|
||||
|
||||
/*this is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_secs */
|
||||
#ifdef CONFIG_DETECT_HUNG_TASK
|
||||
-static unsigned long hung_task_timeout_max = (LONG_MAX/HZ);
|
||||
+static unsigned long hung_task_timeout_max __read_only = (LONG_MAX/HZ);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INOTIFY_USER
|
||||
@@ -332,19 +332,19 @@
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SCHED_DEBUG
|
||||
-static int min_sched_granularity_ns = 100000; /* 100 usecs */
|
||||
-static int max_sched_granularity_ns = NSEC_PER_SEC; /* 1 second */
|
||||
-static int min_wakeup_granularity_ns; /* 0 usecs */
|
||||
-static int max_wakeup_granularity_ns = NSEC_PER_SEC; /* 1 second */
|
||||
+static int min_sched_granularity_ns __read_only = 100000; /* 100 usecs */
|
||||
+static int max_sched_granularity_ns __read_only = NSEC_PER_SEC; /* 1 second */
|
||||
+static int min_wakeup_granularity_ns __read_only; /* 0 usecs */
|
||||
+static int max_wakeup_granularity_ns __read_only = NSEC_PER_SEC; /* 1 second */
|
||||
#ifdef CONFIG_SMP
|
||||
-static int min_sched_tunable_scaling = SCHED_TUNABLESCALING_NONE;
|
||||
-static int max_sched_tunable_scaling = SCHED_TUNABLESCALING_END-1;
|
||||
+static int min_sched_tunable_scaling __read_only = SCHED_TUNABLESCALING_NONE;
|
||||
+static int max_sched_tunable_scaling __read_only = SCHED_TUNABLESCALING_END-1;
|
||||
#endif /* CONFIG_SMP */
|
||||
#endif /* CONFIG_SCHED_DEBUG */
|
||||
|
||||
#ifdef CONFIG_COMPACTION
|
||||
-static int min_extfrag_threshold;
|
||||
-static int max_extfrag_threshold = 1000;
|
||||
+static int min_extfrag_threshold __read_only;
|
||||
+static int max_extfrag_threshold __read_only = 1000;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
--- a/ipc/mq_sysctl.c
|
||||
+++ b/ipc/mq_sysctl.c
|
||||
@@ -47,11 +47,11 @@
|
||||
#define proc_mq_dointvec_minmax NULL
|
||||
#endif
|
||||
|
||||
-static int msg_max_limit_min = MIN_MSGMAX;
|
||||
-static int msg_max_limit_max = HARD_MSGMAX;
|
||||
+static int msg_max_limit_min __read_only = MIN_MSGMAX;
|
||||
+static int msg_max_limit_max __read_only = HARD_MSGMAX;
|
||||
|
||||
-static int msg_maxsize_limit_min = MIN_MSGSIZEMAX;
|
||||
-static int msg_maxsize_limit_max = HARD_MSGSIZEMAX;
|
||||
+static int msg_maxsize_limit_min __read_only = MIN_MSGSIZEMAX;
|
||||
+static int msg_maxsize_limit_max __read_only = HARD_MSGSIZEMAX;
|
||||
|
||||
static struct ctl_table mq_sysctls[] = {
|
||||
{
|
||||
--- a/lib/test_sysctl.c
|
||||
+++ b/lib/test_sysctl.c
|
||||
@@ -36,8 +36,8 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
-static int i_zero;
|
||||
-static int i_one_hundred = 100;
|
||||
+static int i_zero __read_only;
|
||||
+static int i_one_hundred __read_only = 100;
|
||||
|
||||
struct test_sysctl_data {
|
||||
int int_0001;
|
||||
--- a/net/ax25/sysctl_net_ax25.c
|
||||
+++ b/net/ax25/sysctl_net_ax25.c
|
||||
@@ -12,21 +12,21 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/ax25.h>
|
||||
|
||||
-static int min_ipdefmode[1], max_ipdefmode[] = {1};
|
||||
-static int min_axdefmode[1], max_axdefmode[] = {1};
|
||||
-static int min_backoff[1], max_backoff[] = {2};
|
||||
-static int min_conmode[1], max_conmode[] = {2};
|
||||
-static int min_window[] = {1}, max_window[] = {7};
|
||||
-static int min_ewindow[] = {1}, max_ewindow[] = {63};
|
||||
-static int min_t1[] = {1}, max_t1[] = {30000};
|
||||
-static int min_t2[] = {1}, max_t2[] = {20000};
|
||||
-static int min_t3[1], max_t3[] = {3600000};
|
||||
-static int min_idle[1], max_idle[] = {65535000};
|
||||
-static int min_n2[] = {1}, max_n2[] = {31};
|
||||
-static int min_paclen[] = {1}, max_paclen[] = {512};
|
||||
-static int min_proto[1], max_proto[] = { AX25_PROTO_MAX };
|
||||
+static int min_ipdefmode[1], max_ipdefmode[] __read_only = {1};
|
||||
+static int min_axdefmode[1], max_axdefmode[] __read_only = {1};
|
||||
+static int min_backoff[1], max_backoff[] __read_only = {2};
|
||||
+static int min_conmode[1], max_conmode[] __read_only = {2};
|
||||
+static int min_window[] __read_only = {1}, max_window[] __read_only = {7};
|
||||
+static int min_ewindow[] __read_only = {1}, max_ewindow[] __read_only = {63};
|
||||
+static int min_t1[] __read_only = {1}, max_t1[] __read_only = {30000};
|
||||
+static int min_t2[] __read_only = {1}, max_t2[] __read_only = {20000};
|
||||
+static int min_t3[1], max_t3[] __read_only = {3600000};
|
||||
+static int min_idle[1], max_idle[] __read_only = {65535000};
|
||||
+static int min_n2[] __read_only = {1}, max_n2[] __read_only = {31};
|
||||
+static int min_paclen[] __read_only = {1}, max_paclen[] __read_only = {512};
|
||||
+static int min_proto[1], max_proto[] __read_only = { AX25_PROTO_MAX };
|
||||
#ifdef CONFIG_AX25_DAMA_SLAVE
|
||||
-static int min_ds_timeout[1], max_ds_timeout[] = {65535000};
|
||||
+static int min_ds_timeout[1], max_ds_timeout[] __read_only = {65535000};
|
||||
#endif
|
||||
|
||||
static const struct ctl_table ax25_param_table[] = {
|
||||
--- a/net/core/sysctl_net_core.c
|
||||
+++ b/net/core/sysctl_net_core.c
|
||||
@@ -23,14 +23,14 @@
|
||||
#include <net/busy_poll.h>
|
||||
#include <net/pkt_sched.h>
|
||||
|
||||
-static int zero = 0;
|
||||
-static int one = 1;
|
||||
-static int two __maybe_unused = 2;
|
||||
-static int min_sndbuf = SOCK_MIN_SNDBUF;
|
||||
-static int min_rcvbuf = SOCK_MIN_RCVBUF;
|
||||
-static int max_skb_frags = MAX_SKB_FRAGS;
|
||||
-static long long_one __maybe_unused = 1;
|
||||
-static long long_max __maybe_unused = LONG_MAX;
|
||||
+static int zero __read_only = 0;
|
||||
+static int one __read_only = 1;
|
||||
+static int two __maybe_unused __read_only = 2;
|
||||
+static int min_sndbuf __read_only = SOCK_MIN_SNDBUF;
|
||||
+static int min_rcvbuf __read_only = SOCK_MIN_RCVBUF;
|
||||
+static int max_skb_frags __read_only = MAX_SKB_FRAGS;
|
||||
+static long long_one __maybe_unused __read_only = 1;
|
||||
+static long long_max __maybe_unused __read_only = LONG_MAX;
|
||||
|
||||
static int net_msg_warn; /* Unused, but still a sysctl */
|
||||
|
||||
--- a/net/ipv4/sysctl_net_ipv4.c
|
||||
+++ b/net/ipv4/sysctl_net_ipv4.c
|
||||
@@ -28,33 +28,33 @@
|
||||
#include <net/protocol.h>
|
||||
#include <net/netevent.h>
|
||||
|
||||
-static int zero;
|
||||
-static int one = 1;
|
||||
-static int three = 3;
|
||||
-static int four = 4;
|
||||
-static int hundred = 100;
|
||||
-static int thousand = 1000;
|
||||
-static int gso_max_segs = GSO_MAX_SEGS;
|
||||
-static int tcp_retr1_max = 255;
|
||||
-static int ip_local_port_range_min[] = { 1, 1 };
|
||||
-static int ip_local_port_range_max[] = { 65535, 65535 };
|
||||
-static int tcp_adv_win_scale_min = -31;
|
||||
-static int tcp_adv_win_scale_max = 31;
|
||||
-static int tcp_min_snd_mss_min = TCP_MIN_SND_MSS;
|
||||
-static int tcp_min_snd_mss_max = 65535;
|
||||
+static int zero __read_only;
|
||||
+static int one __read_only = 1;
|
||||
+static int three __read_only = 3;
|
||||
+static int four __read_only = 4;
|
||||
+static int hundred __read_only = 100;
|
||||
+static int thousand __read_only = 1000;
|
||||
+static int gso_max_segs __read_only = GSO_MAX_SEGS;
|
||||
+static int tcp_retr1_max __read_only = 255;
|
||||
+static int ip_local_port_range_min[] __read_only = { 1, 1 };
|
||||
+static int ip_local_port_range_max[] __read_only = { 65535, 65535 };
|
||||
+static int tcp_adv_win_scale_min __read_only = -31;
|
||||
+static int tcp_adv_win_scale_max __read_only = 31;
|
||||
+static int tcp_min_snd_mss_min __read_only = TCP_MIN_SND_MSS;
|
||||
+static int tcp_min_snd_mss_max __read_only = 65535;
|
||||
static int ip_privileged_port_min;
|
||||
-static int ip_privileged_port_max = 65535;
|
||||
-static int ip_ttl_min = 1;
|
||||
-static int ip_ttl_max = 255;
|
||||
-static int tcp_syn_retries_min = 1;
|
||||
-static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
|
||||
-static int ip_ping_group_range_min[] = { 0, 0 };
|
||||
-static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
|
||||
-static int one_day_secs = 24 * 3600;
|
||||
-static int tcp_delack_seg_min = TCP_DELACK_MIN;
|
||||
-static int tcp_delack_seg_max = 60;
|
||||
+static int ip_privileged_port_max __read_only = 65535;
|
||||
+static int ip_ttl_min __read_only = 1;
|
||||
+static int ip_ttl_max __read_only = 255;
|
||||
+static int tcp_syn_retries_min __read_only = 1;
|
||||
+static int tcp_syn_retries_max __read_only = MAX_TCP_SYNCNT;
|
||||
+static int ip_ping_group_range_min[] __read_only = { 0, 0 };
|
||||
+static int ip_ping_group_range_max[] __read_only = { GID_T_MAX, GID_T_MAX };
|
||||
+static int one_day_secs __read_only = 24 * 3600;
|
||||
+static int tcp_delack_seg_min __read_only = TCP_DELACK_MIN;
|
||||
+static int tcp_delack_seg_max __read_only = 60;
|
||||
static int tcp_use_userconfig_min;
|
||||
-static int tcp_use_userconfig_max = 1;
|
||||
+static int tcp_use_userconfig_max __read_only = 1;
|
||||
|
||||
/* obsolete */
|
||||
static int sysctl_tcp_low_latency __read_mostly;
|
||||
--- a/net/ipv6/sysctl_net_ipv6.c
|
||||
+++ b/net/ipv6/sysctl_net_ipv6.c
|
||||
@@ -22,9 +22,9 @@
|
||||
#endif
|
||||
|
||||
static int zero;
|
||||
-static int one = 1;
|
||||
-static int auto_flowlabels_min;
|
||||
-static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
|
||||
+static int one __read_only = 1;
|
||||
+static int auto_flowlabels_min __read_only;
|
||||
+static int auto_flowlabels_max __read_only = IP6_AUTO_FLOW_LABEL_MAX;
|
||||
|
||||
static int proc_rt6_multipath_hash_policy(struct ctl_table *table, int write,
|
||||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
--- a/net/netrom/sysctl_net_netrom.c
|
||||
+++ b/net/netrom/sysctl_net_netrom.c
|
||||
@@ -15,22 +15,22 @@
|
||||
/*
|
||||
* Values taken from NET/ROM documentation.
|
||||
*/
|
||||
-static int min_quality[] = {0}, max_quality[] = {255};
|
||||
-static int min_obs[] = {0}, max_obs[] = {255};
|
||||
-static int min_ttl[] = {0}, max_ttl[] = {255};
|
||||
-static int min_t1[] = {5 * HZ};
|
||||
-static int max_t1[] = {600 * HZ};
|
||||
-static int min_n2[] = {2}, max_n2[] = {127};
|
||||
-static int min_t2[] = {1 * HZ};
|
||||
-static int max_t2[] = {60 * HZ};
|
||||
-static int min_t4[] = {1 * HZ};
|
||||
-static int max_t4[] = {1000 * HZ};
|
||||
-static int min_window[] = {1}, max_window[] = {127};
|
||||
-static int min_idle[] = {0 * HZ};
|
||||
-static int max_idle[] = {65535 * HZ};
|
||||
-static int min_route[] = {0}, max_route[] = {1};
|
||||
-static int min_fails[] = {1}, max_fails[] = {10};
|
||||
-static int min_reset[] = {0}, max_reset[] = {1};
|
||||
+static int min_quality[] __read_only = {0}, max_quality[] __read_only = {255};
|
||||
+static int min_obs[] __read_only = {0}, max_obs[] __read_only = {255};
|
||||
+static int min_ttl[] __read_only = {0}, max_ttl[] __read_only = {255};
|
||||
+static int min_t1[] __read_only = {5 * HZ};
|
||||
+static int max_t1[] __read_only = {600 * HZ};
|
||||
+static int min_n2[] __read_only = {2}, max_n2[] __read_only = {127};
|
||||
+static int min_t2[] __read_only = {1 * HZ};
|
||||
+static int max_t2[] __read_only = {60 * HZ};
|
||||
+static int min_t4[] __read_only = {1 * HZ};
|
||||
+static int max_t4[] __read_only = {1000 * HZ};
|
||||
+static int min_window[] __read_only = {1}, max_window[] __read_only = {127};
|
||||
+static int min_idle[] __read_only = {0 * HZ};
|
||||
+static int max_idle[] __read_only = {65535 * HZ};
|
||||
+static int min_route[] __read_only = {0}, max_route[] __read_only = {1};
|
||||
+static int min_fails[] __read_only = {1}, max_fails[] __read_only = {10};
|
||||
+static int min_reset[] __read_only = {0}, max_reset[] __read_only = {1};
|
||||
|
||||
static struct ctl_table_header *nr_table_header;
|
||||
|
||||
--- a/net/phonet/sysctl.c
|
||||
+++ b/net/phonet/sysctl.c
|
||||
@@ -35,8 +35,8 @@
|
||||
#define DYNAMIC_PORT_MAX 0x7f
|
||||
|
||||
static DEFINE_SEQLOCK(local_port_range_lock);
|
||||
-static int local_port_range_min[2] = {0, 0};
|
||||
-static int local_port_range_max[2] = {1023, 1023};
|
||||
+static int local_port_range_min[2] __read_only = {0, 0};
|
||||
+static int local_port_range_max[2] __read_only = {1023, 1023};
|
||||
static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
|
||||
static struct ctl_table_header *phonet_table_hrd;
|
||||
|
||||
--- a/net/rose/sysctl_net_rose.c
|
||||
+++ b/net/rose/sysctl_net_rose.c
|
||||
@@ -12,15 +12,15 @@
|
||||
#include <net/ax25.h>
|
||||
#include <net/rose.h>
|
||||
|
||||
-static int min_timer[] = {1 * HZ};
|
||||
-static int max_timer[] = {300 * HZ};
|
||||
-static int min_idle[] = {0 * HZ};
|
||||
-static int max_idle[] = {65535 * HZ};
|
||||
-static int min_route[1], max_route[] = {1};
|
||||
-static int min_ftimer[] = {60 * HZ};
|
||||
-static int max_ftimer[] = {600 * HZ};
|
||||
-static int min_maxvcs[] = {1}, max_maxvcs[] = {254};
|
||||
-static int min_window[] = {1}, max_window[] = {7};
|
||||
+static int min_timer[] __read_only = {1 * HZ};
|
||||
+static int max_timer[] __read_only = {300 * HZ};
|
||||
+static int min_idle[] __read_only = {0 * HZ};
|
||||
+static int max_idle[] __read_only = {65535 * HZ};
|
||||
+static int min_route[1], max_route[] __read_only = {1};
|
||||
+static int min_ftimer[] __read_only = {60 * HZ};
|
||||
+static int max_ftimer[] __read_only = {600 * HZ};
|
||||
+static int min_maxvcs[] __read_only = {1}, max_maxvcs[] = {254};
|
||||
+static int min_window[] __read_only = {1}, max_window[] = {7};
|
||||
|
||||
static struct ctl_table_header *rose_table_header;
|
||||
|
||||
--- a/net/sctp/sysctl.c
|
||||
+++ b/net/sctp/sysctl.c
|
||||
@@ -40,21 +40,21 @@
|
||||
#include <net/sctp/sctp.h>
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
-static int zero = 0;
|
||||
-static int one = 1;
|
||||
-static int timer_max = 86400000; /* ms in one day */
|
||||
-static int int_max = INT_MAX;
|
||||
-static int sack_timer_min = 1;
|
||||
-static int sack_timer_max = 500;
|
||||
-static int addr_scope_max = SCTP_SCOPE_POLICY_MAX;
|
||||
-static int rwnd_scale_max = 16;
|
||||
-static int rto_alpha_min = 0;
|
||||
-static int rto_beta_min = 0;
|
||||
-static int rto_alpha_max = 1000;
|
||||
-static int rto_beta_max = 1000;
|
||||
+static int zero __read_only = 0;
|
||||
+static int one __read_only = 1;
|
||||
+static int timer_max __read_only = 86400000; /* ms in one day */
|
||||
+static int int_max __read_only = INT_MAX;
|
||||
+static int sack_timer_min __read_only = 1;
|
||||
+static int sack_timer_max __read_only = 500;
|
||||
+static int addr_scope_max __read_only = SCTP_SCOPE_POLICY_MAX;
|
||||
+static int rwnd_scale_max __read_only = 16;
|
||||
+static int rto_alpha_min __read_only = 0;
|
||||
+static int rto_beta_min __read_only = 0;
|
||||
+static int rto_alpha_max __read_only = 1000;
|
||||
+static int rto_beta_max __read_only = 1000;
|
||||
|
||||
-static unsigned long max_autoclose_min = 0;
|
||||
-static unsigned long max_autoclose_max =
|
||||
+static unsigned long max_autoclose_min __read_only = 0;
|
||||
+static unsigned long max_autoclose_max __read_only =
|
||||
(MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX)
|
||||
? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ;
|
||||
|
||||
--- a/net/x25/sysctl_net_x25.c
|
||||
+++ b/net/x25/sysctl_net_x25.c
|
||||
@@ -13,8 +13,8 @@
|
||||
#include <linux/init.h>
|
||||
#include <net/x25.h>
|
||||
|
||||
-static int min_timer[] = { 1 * HZ };
|
||||
-static int max_timer[] = { 300 * HZ };
|
||||
+static int min_timer[] __read_only = { 1 * HZ };
|
||||
+static int max_timer[] __read_only = { 300 * HZ };
|
||||
|
||||
static struct ctl_table_header *x25_table_header;
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
0008-Graphene-Kernel_Hardening-misc/4.14/0005.patch
|
||||
0008-Graphene-Kernel_Hardening-misc/4.14/0010.patch
|
||||
0008-Graphene-Kernel_Hardening-misc/4.14/0018.patch
|
||||
# misc/0021 is already present in LOS @ 28f9290ae067 (KSYM_NAME_LEN=192).
|
||||
# Applying it with GNU patch's reverse detection silently shrinks it to 128
|
||||
# under CONFIG_CFI_CLANG, so it must remain omitted.
|
||||
0008-Graphene-Kernel_Hardening-random/4.14/0002.patch
|
||||
0008-Graphene-Kernel_Hardening-random/4.14/0007.patch
|
||||
0008-Graphene-Kernel_Hardening-random/4.14/0012.patch
|
||||
|
||||
@@ -30,13 +30,19 @@ Stage1+combo4+CVE apply.
|
||||
```text
|
||||
zcat /proc/config.gz | grep CONFIG_SECURITY_YAMA=y
|
||||
zcat /proc/config.gz | grep CONFIG_SLAB_FREELIST_RANDOM=y
|
||||
cat /proc/sys/kernel/yama/ptrace_scope # expect 1 (default)
|
||||
cat /proc/sys/kernel/yama/ptrace_scope # expect 2 (ship policy)
|
||||
pidof magiskd # still up
|
||||
```
|
||||
|
||||
The ship script now applies `apply_009_yama_ptrace.py`, so the current LAB
|
||||
policy is `ptrace_scope=2`, not the kernel default `1`. Matching AXP's
|
||||
`persist.native_debug` 0/2 toggle is a separate userspace change and must not
|
||||
be mixed into the CVE-2022-49980 boot test.
|
||||
|
||||
## Out of scope here
|
||||
|
||||
- `CVE-2022-49980` lock-scope port (still denylist)
|
||||
- The original `CVE-2022-49980/ANY/0001.patch` remains denylisted. The next
|
||||
isolated bacon applies `ports/cve-2022-49980-lock-scope.patch` instead.
|
||||
- nf_tables high-offset CVEs
|
||||
- Stage1 slab FAIL patches (`0010`/`0018` still reject on this tree)
|
||||
- `hardened_malloc` / bootloader lock
|
||||
@@ -0,0 +1,414 @@
|
||||
#!/usr/bin/env python3
|
||||
"""012: Graphene hardened_malloc on LOS 23.2, the AXP GRAPHENE_MALLOC set.
|
||||
|
||||
Source of the integration is GrapheneOS platform_bionic branch 16:
|
||||
64-bit libc uses hardened_malloc, 32-bit stays Scudo, and SurfaceFlinger
|
||||
plus camera executables stay on Scudo. AXP documents that camera exception
|
||||
as applying to every camera executable, which on sunfish is
|
||||
/vendor/bin/hw/android.hardware.camera.provider@2.7-service-google rather
|
||||
than the newer Pixel apex path.
|
||||
|
||||
Library pin: GrapheneOS/hardened_malloc 1d7fc7ffe0f8 (branch 14, 2025-04-03),
|
||||
the newest branch that is not the Android 17 line. device_has_arm_mte is
|
||||
removed because LOS soong has no such product variable and sunfish has no MTE.
|
||||
|
||||
Class region size is 2GiB, as DivestOS/AXP set it, because the sunfish
|
||||
kernel has a 39-bit address space (GOLDEN: VA_BITS=39 with hardened_malloc).
|
||||
|
||||
system/core init.rc raises vm.max_map_count to 1048576, same as GrapheneOS 16.
|
||||
frameworks/av no longer sets RLIMIT_AS on this tree, so that AXP/Pie hunk
|
||||
does not apply.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
MARKER = "SUNFISH_A16_012_HARDENED_MALLOC"
|
||||
PIN = "1d7fc7ffe0f8068a32ab2ba33df7515e7bad3f5f"
|
||||
REPO = "https://github.com/GrapheneOS/hardened_malloc.git"
|
||||
REGION_48BIT = "-DCONFIG_CLASS_REGION_SIZE=34359738368"
|
||||
REGION_39BIT = "-DCONFIG_CLASS_REGION_SIZE=2147483648"
|
||||
|
||||
HERE = pathlib.Path(__file__).resolve().parent
|
||||
TREE = pathlib.Path(os.environ.get("ANDROID_BUILD_TOP", "/srv/rom/src/lineage"))
|
||||
|
||||
|
||||
def must_replace(path: pathlib.Path, old: str, new: str, label: str) -> None:
|
||||
text = path.read_text()
|
||||
if new in text:
|
||||
print(f"already applied: {path} ({label})")
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing for {label} in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
print(f"patched {label}: {path}")
|
||||
|
||||
|
||||
def rewrite_region_comment(bp: pathlib.Path) -> None:
|
||||
text = bp.read_text()
|
||||
stale = f'{REGION_39BIT}", // 32GiB'
|
||||
fresh = f'{REGION_39BIT}", // 2GiB, 39-bit VA (DivestOS/AXP)'
|
||||
if stale not in text:
|
||||
return
|
||||
bp.write_text(text.replace(stale, fresh))
|
||||
print(f"region comment: {bp}")
|
||||
|
||||
|
||||
def ensure_library() -> None:
|
||||
dest = TREE / "external/hardened_malloc"
|
||||
if (dest / ".git").is_dir():
|
||||
head = subprocess.check_output(
|
||||
["git", "-C", dest, "rev-parse", "HEAD"], text=True
|
||||
).strip()
|
||||
bp_text = (dest / "Android.bp").read_text()
|
||||
if head == PIN and MARKER in bp_text and REGION_39BIT in bp_text:
|
||||
rewrite_region_comment(dest / "Android.bp")
|
||||
print(f"hardened_malloc already at {PIN}")
|
||||
return
|
||||
subprocess.check_call(["git", "-C", dest, "fetch", "--depth", "1", "origin", PIN])
|
||||
subprocess.check_call(["git", "-C", dest, "checkout", "--detach", PIN])
|
||||
else:
|
||||
if dest.exists():
|
||||
sys.exit(f"{dest} exists and is not a git checkout")
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
subprocess.check_call(
|
||||
["git", "clone", "--depth", "1", REPO, str(dest)]
|
||||
)
|
||||
subprocess.check_call(["git", "-C", dest, "fetch", "--depth", "1", "origin", PIN])
|
||||
subprocess.check_call(["git", "-C", dest, "checkout", "--detach", PIN])
|
||||
bp = dest / "Android.bp"
|
||||
text = bp.read_text()
|
||||
mte = """ device_has_arm_mte: {
|
||||
cflags: ["-DHAS_ARM_MTE", "-march=armv8-a+dotprod+memtag"]
|
||||
},
|
||||
"""
|
||||
if mte in text:
|
||||
text = text.replace(mte, "")
|
||||
# sunfish msm-4.14 is CONFIG_ARM64_VA_BITS=39. The 32GiB default class
|
||||
# region needs 48-bit VA and aborts every 64-bit process at boot.
|
||||
# DivestOS/AXP Patch.sh: sed 's/34359738368/2147483648/' Android.bp.
|
||||
text = text.replace(REGION_48BIT, REGION_39BIT)
|
||||
text = text.replace(
|
||||
f'{REGION_39BIT}", // 32GiB',
|
||||
f'{REGION_39BIT}", // 2GiB, 39-bit VA (DivestOS/AXP)',
|
||||
)
|
||||
bp.write_text(text)
|
||||
text = bp.read_text()
|
||||
if REGION_39BIT not in text:
|
||||
sys.exit(f"CONFIG_CLASS_REGION_SIZE is not 2GiB in {bp}")
|
||||
if MARKER not in text:
|
||||
text = text.replace(
|
||||
"cc_library {\n",
|
||||
f"cc_library {{\n // {MARKER}: sunfish has no MTE; LOS soong has no device_has_arm_mte.\n",
|
||||
1,
|
||||
)
|
||||
bp.write_text(text)
|
||||
head = subprocess.check_output(
|
||||
["git", "-C", dest, "rev-parse", "HEAD"], text=True
|
||||
).strip()
|
||||
if head != PIN:
|
||||
sys.exit(f"hardened_malloc HEAD {head} != {PIN}")
|
||||
print(f"hardened_malloc {PIN}")
|
||||
|
||||
|
||||
def patch_bionic() -> None:
|
||||
wrapper = TREE / "bionic/libc/bionic/h_malloc_wrapper.cpp"
|
||||
src = HERE / "h_malloc_wrapper.cpp"
|
||||
if not wrapper.exists() or wrapper.read_text() != src.read_text():
|
||||
wrapper.write_text(src.read_text())
|
||||
print(f"installed {wrapper}")
|
||||
|
||||
must_replace(
|
||||
TREE / "bionic/libc/Android.bp",
|
||||
"""cc_defaults {
|
||||
name: "libc_native_allocator_defaults",
|
||||
|
||||
whole_static_libs: [
|
||||
"libscudo",
|
||||
],
|
||||
cflags: [
|
||||
"-DUSE_SCUDO",
|
||||
],
|
||||
header_libs: ["gwp_asan_headers"],
|
||||
product_variables: {
|
||||
malloc_low_memory: {
|
||||
cflags: ["-UUSE_SCUDO"],
|
||||
whole_static_libs: [
|
||||
"libjemalloc5",
|
||||
"libc_jemalloc_wrapper",
|
||||
],
|
||||
exclude_static_libs: [
|
||||
"libscudo",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
""",
|
||||
f"""cc_defaults {{
|
||||
// {MARKER}
|
||||
name: "libc_native_allocator_defaults",
|
||||
|
||||
header_libs: ["gwp_asan_headers"],
|
||||
whole_static_libs: ["libscudo"],
|
||||
|
||||
// GrapheneOS 16: hardened_malloc on 64-bit, Scudo on 32-bit.
|
||||
multilib: {{
|
||||
lib32: {{
|
||||
cflags: ["-DUSE_SCUDO"],
|
||||
}},
|
||||
lib64: {{
|
||||
srcs: ["bionic/h_malloc_wrapper.cpp"],
|
||||
cflags: [
|
||||
"-DH_MALLOC_PREFIX",
|
||||
"-DUSE_H_MALLOC",
|
||||
"-DUSE_SCUDO",
|
||||
],
|
||||
whole_static_libs: [
|
||||
"libhardened_malloc",
|
||||
],
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
""",
|
||||
"allocator-defaults",
|
||||
)
|
||||
|
||||
must_replace(
|
||||
TREE / "bionic/libc/bionic/malloc_common.h",
|
||||
"""#else // __has_feature(hwaddress_sanitizer)
|
||||
|
||||
#if defined(USE_SCUDO)
|
||||
""",
|
||||
f"""#else // __has_feature(hwaddress_sanitizer)
|
||||
|
||||
// {MARKER}
|
||||
#ifdef __LP64__
|
||||
#ifndef USE_H_MALLOC
|
||||
#error missing USE_H_MALLOC
|
||||
#endif
|
||||
|
||||
#include "h_malloc.h"
|
||||
#define Malloc(function) h_ ## function
|
||||
__BEGIN_DECLS
|
||||
int h_malloc_info(int options, FILE* fp);
|
||||
__END_DECLS
|
||||
|
||||
#if defined(USE_SCUDO)
|
||||
#include "scudo.h"
|
||||
void InitNativeAllocatorDispatch(libc_globals* globals);
|
||||
#endif
|
||||
|
||||
#define BOTH_H_MALLOC_AND_SCUDO
|
||||
|
||||
#else // 32-bit
|
||||
|
||||
#if defined(USE_SCUDO)
|
||||
""",
|
||||
"malloc-header",
|
||||
)
|
||||
header = TREE / "bionic/libc/bionic/malloc_common.h"
|
||||
text = header.read_text()
|
||||
tail = """#define Malloc(function) je_ ## function
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
const MallocDispatch* NativeAllocatorDispatch();
|
||||
"""
|
||||
tail_new = """#define Malloc(function) je_ ## function
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __LP64__
|
||||
|
||||
#endif // __has_feature(hwaddress_sanitizer)
|
||||
|
||||
const MallocDispatch* NativeAllocatorDispatch();
|
||||
"""
|
||||
if tail_new not in text:
|
||||
if tail not in text:
|
||||
sys.exit(f"header close anchor missing in {header}")
|
||||
header.write_text(text.replace(tail, tail_new, 1))
|
||||
|
||||
must_replace(
|
||||
TREE / "bionic/libc/bionic/malloc_common.cpp",
|
||||
"""const MallocDispatch* NativeAllocatorDispatch() {
|
||||
return &__libc_malloc_default_dispatch;
|
||||
}
|
||||
""",
|
||||
f"""#if defined(BOTH_H_MALLOC_AND_SCUDO)
|
||||
// {MARKER}: camera executables and surfaceflinger stay on Scudo.
|
||||
|
||||
#define ScudoMalloc(function) scudo_ ## function
|
||||
|
||||
static constexpr MallocDispatch __scudo_malloc_dispatch __attribute__((unused)) = {{
|
||||
ScudoMalloc(calloc),
|
||||
ScudoMalloc(free),
|
||||
ScudoMalloc(mallinfo),
|
||||
ScudoMalloc(malloc),
|
||||
ScudoMalloc(malloc_usable_size),
|
||||
ScudoMalloc(memalign),
|
||||
ScudoMalloc(posix_memalign),
|
||||
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
||||
ScudoMalloc(pvalloc),
|
||||
#endif
|
||||
ScudoMalloc(realloc),
|
||||
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
||||
ScudoMalloc(valloc),
|
||||
#endif
|
||||
ScudoMalloc(malloc_iterate),
|
||||
ScudoMalloc(malloc_disable),
|
||||
ScudoMalloc(malloc_enable),
|
||||
ScudoMalloc(mallopt),
|
||||
ScudoMalloc(aligned_alloc),
|
||||
ScudoMalloc(malloc_info),
|
||||
}};
|
||||
|
||||
static const MallocDispatch* native_allocator_dispatch;
|
||||
|
||||
void InitNativeAllocatorDispatch(libc_globals* globals) {{
|
||||
bool hardened_impl = true;
|
||||
if (globals->flags & GLOBAL_FLAG_DISABLE_HARDENED_MALLOC) {{
|
||||
hardened_impl = false;
|
||||
}} else if (getenv("DISABLE_HARDENED_MALLOC") != nullptr) {{
|
||||
hardened_impl = false;
|
||||
}}
|
||||
|
||||
const MallocDispatch* table = hardened_impl ?
|
||||
&__libc_malloc_default_dispatch :
|
||||
&__scudo_malloc_dispatch;
|
||||
|
||||
if (!hardened_impl) {{
|
||||
globals->malloc_dispatch_table = __scudo_malloc_dispatch;
|
||||
globals->current_dispatch_table = &globals->malloc_dispatch_table;
|
||||
globals->default_dispatch_table = &globals->malloc_dispatch_table;
|
||||
}}
|
||||
|
||||
native_allocator_dispatch = table;
|
||||
}}
|
||||
|
||||
const MallocDispatch* NativeAllocatorDispatch() {{
|
||||
return native_allocator_dispatch;
|
||||
}}
|
||||
#else
|
||||
const MallocDispatch* NativeAllocatorDispatch() {{
|
||||
return &__libc_malloc_default_dispatch;
|
||||
}}
|
||||
#endif
|
||||
""",
|
||||
"dispatch",
|
||||
)
|
||||
|
||||
must_replace(
|
||||
TREE / "bionic/libc/bionic/malloc_common_dynamic.cpp",
|
||||
"""void MallocInitImpl(libc_globals* globals) {
|
||||
char prop[PROP_VALUE_MAX];
|
||||
""",
|
||||
f"""void MallocInitImpl(libc_globals* globals) {{
|
||||
#if defined(BOTH_H_MALLOC_AND_SCUDO)
|
||||
// {MARKER}
|
||||
InitNativeAllocatorDispatch(globals);
|
||||
#endif
|
||||
char prop[PROP_VALUE_MAX];
|
||||
""",
|
||||
"malloc-init",
|
||||
)
|
||||
|
||||
must_replace(
|
||||
TREE / "bionic/libc/private/bionic_globals.h",
|
||||
""" MallocDispatch malloc_dispatch_table;
|
||||
};
|
||||
""",
|
||||
f""" MallocDispatch malloc_dispatch_table;
|
||||
// {MARKER}
|
||||
int flags;
|
||||
}};
|
||||
|
||||
#define GLOBAL_FLAG_DISABLE_HARDENED_MALLOC 1
|
||||
""",
|
||||
"globals",
|
||||
)
|
||||
|
||||
init = TREE / "bionic/libc/bionic/libc_init_dynamic.cpp"
|
||||
text = init.read_text()
|
||||
if '#include <string.h>' not in text:
|
||||
if '#include <stdlib.h>' not in text:
|
||||
sys.exit(f"stdlib include missing in {init}")
|
||||
text = text.replace(
|
||||
"#include <stdlib.h>\n",
|
||||
"#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n",
|
||||
1,
|
||||
)
|
||||
helper = f"""
|
||||
// {MARKER}: GrapheneOS disables hardened_malloc for surfaceflinger.
|
||||
// AXP expands the camera exception to every camera executable. sunfish runs
|
||||
// /vendor/bin/hw/android.hardware.camera.provider@2.7-service-google.
|
||||
static void init_hardened_malloc_exclusions(libc_globals* globals) {{
|
||||
char exe_path[500];
|
||||
ssize_t n = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
|
||||
if (n <= 0) {{
|
||||
globals->flags = 0;
|
||||
return;
|
||||
}}
|
||||
exe_path[n] = '\\0';
|
||||
if (strcmp(exe_path, "/system/bin/surfaceflinger") == 0 ||
|
||||
strstr(exe_path, "camera") != nullptr) {{
|
||||
globals->flags = GLOBAL_FLAG_DISABLE_HARDENED_MALLOC;
|
||||
}} else {{
|
||||
globals->flags = 0;
|
||||
}}
|
||||
}}
|
||||
|
||||
"""
|
||||
# __libc_preinit_impl must stay noinline (stack protector guard setup).
|
||||
noinline = "__attribute__((noinline))\n"
|
||||
anchor = noinline + "static void __libc_preinit_impl() {"
|
||||
misplaced = noinline + helper + "static void __libc_preinit_impl() {"
|
||||
if misplaced in text:
|
||||
text = text.replace(misplaced, helper + anchor, 1)
|
||||
if "init_hardened_malloc_exclusions" not in text:
|
||||
if anchor not in text:
|
||||
sys.exit(f"preinit anchor missing in {init}")
|
||||
text = text.replace(anchor, helper + anchor, 1)
|
||||
if anchor not in text:
|
||||
sys.exit(f"__libc_preinit_impl lost noinline in {init}")
|
||||
old_mutate = " __libc_globals.mutate(__libc_init_malloc);\n"
|
||||
new_mutate = """ __libc_globals.mutate([](libc_globals* globals) {
|
||||
init_hardened_malloc_exclusions(globals);
|
||||
__libc_init_malloc(globals);
|
||||
});
|
||||
"""
|
||||
if "init_hardened_malloc_exclusions(globals)" not in text:
|
||||
if old_mutate not in text:
|
||||
sys.exit(f"mutate anchor missing in {init}")
|
||||
text = text.replace(old_mutate, new_mutate, 1)
|
||||
init.write_text(text)
|
||||
print(f"patched exclusions: {init}")
|
||||
|
||||
|
||||
def patch_init_rc() -> None:
|
||||
must_replace(
|
||||
TREE / "system/core/rootdir/init.rc",
|
||||
" symlink /sys/class/block/${dev.mnt.rootdisk.data} /dev/sys/block/by-name/rootdisk\n",
|
||||
" symlink /sys/class/block/${dev.mnt.rootdisk.data} /dev/sys/block/by-name/rootdisk\n\n"
|
||||
f" # {MARKER}: GrapheneOS 16 vm.max_map_count for hardened_malloc\n"
|
||||
" write /proc/sys/vm/max_map_count 1048576\n",
|
||||
"max-map-count",
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not (TREE / "bionic/libc/Android.bp").is_file():
|
||||
sys.exit(f"not an Android tree: {TREE}")
|
||||
ensure_library()
|
||||
patch_bionic()
|
||||
patch_init_rc()
|
||||
print(f"done: {MARKER}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,51 @@
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <private/MallocXmlElem.h>
|
||||
|
||||
#include "h_malloc.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
int h_malloc_info(int options, FILE* fp);
|
||||
__END_DECLS
|
||||
|
||||
int h_malloc_info(int options, FILE* fp) {
|
||||
if (options != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fflush(fp);
|
||||
int fd = fileno(fp);
|
||||
MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\"");
|
||||
|
||||
// Dump all of the large allocations in the arenas.
|
||||
for (size_t i = 0; i < h_mallinfo_narenas(); i++) {
|
||||
struct mallinfo mi = h_mallinfo_arena_info(i);
|
||||
if (mi.hblkhd != 0) {
|
||||
MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i);
|
||||
{
|
||||
MallocXmlElem(fd, "allocated-large").Contents("%zu", mi.ordblks);
|
||||
MallocXmlElem(fd, "allocated-huge").Contents("%zu", mi.uordblks);
|
||||
MallocXmlElem(fd, "allocated-bins").Contents("%zu", mi.fsmblks);
|
||||
|
||||
size_t total = 0;
|
||||
for (size_t j = 0; j < h_mallinfo_nbins(); j++) {
|
||||
struct mallinfo mi = h_mallinfo_bin_info(i, j);
|
||||
if (mi.ordblks != 0) {
|
||||
MallocXmlElem bin_elem(fd, "bin", "nr=\"%d\"", j);
|
||||
MallocXmlElem(fd, "allocated").Contents("%zu", mi.ordblks);
|
||||
MallocXmlElem(fd, "nmalloc").Contents("%zu", mi.uordblks);
|
||||
MallocXmlElem(fd, "ndalloc").Contents("%zu", mi.fordblks);
|
||||
total += mi.ordblks;
|
||||
}
|
||||
}
|
||||
MallocXmlElem(fd, "bins-total").Contents("%zu", total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user