diff --git a/Manifests/Manifest_LAOS-21.0.xml b/Manifests/Manifest_LAOS-21.0.xml
new file mode 100644
index 00000000..48aa56a3
--- /dev/null
+++ b/Manifests/Manifest_LAOS-21.0.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Patches/LineageOS-21.0/android_art/0001-constify_JNINativeMethod.patch b/Patches/LineageOS-21.0/android_art/0001-constify_JNINativeMethod.patch
new file mode 100644
index 00000000..7cabbef0
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_art/0001-constify_JNINativeMethod.patch
@@ -0,0 +1,539 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Thu, 5 Oct 2023 08:27:35 -0400
+Subject: [PATCH] constify JNINativeMethod tables
+
+---
+ benchmark/micro-native/micro_native.cc | 8 ++++----
+ runtime/native/dalvik_system_BaseDexClassLoader.cc | 2 +-
+ runtime/native/dalvik_system_DexFile.cc | 2 +-
+ runtime/native/dalvik_system_VMDebug.cc | 2 +-
+ runtime/native/dalvik_system_VMRuntime.cc | 2 +-
+ runtime/native/dalvik_system_VMStack.cc | 2 +-
+ runtime/native/dalvik_system_ZygoteHooks.cc | 2 +-
+ runtime/native/java_lang_Class.cc | 2 +-
+ runtime/native/java_lang_Object.cc | 2 +-
+ runtime/native/java_lang_StackStreamFactory.cc | 2 +-
+ runtime/native/java_lang_String.cc | 2 +-
+ runtime/native/java_lang_StringFactory.cc | 2 +-
+ runtime/native/java_lang_System.cc | 2 +-
+ runtime/native/java_lang_Thread.cc | 2 +-
+ runtime/native/java_lang_Throwable.cc | 2 +-
+ runtime/native/java_lang_VMClassLoader.cc | 2 +-
+ runtime/native/java_lang_invoke_MethodHandle.cc | 2 +-
+ runtime/native/java_lang_invoke_MethodHandleImpl.cc | 2 +-
+ runtime/native/java_lang_ref_FinalizerReference.cc | 2 +-
+ runtime/native/java_lang_ref_Reference.cc | 2 +-
+ runtime/native/java_lang_reflect_Array.cc | 2 +-
+ runtime/native/java_lang_reflect_Constructor.cc | 2 +-
+ runtime/native/java_lang_reflect_Executable.cc | 2 +-
+ runtime/native/java_lang_reflect_Field.cc | 2 +-
+ runtime/native/java_lang_reflect_Method.cc | 2 +-
+ runtime/native/java_lang_reflect_Parameter.cc | 2 +-
+ runtime/native/java_lang_reflect_Proxy.cc | 2 +-
+ runtime/native/java_util_concurrent_atomic_AtomicLong.cc | 2 +-
+ runtime/native/jdk_internal_misc_Unsafe.cc | 2 +-
+ runtime/native/libcore_io_Memory.cc | 2 +-
+ runtime/native/libcore_util_CharsetUtils.cc | 2 +-
+ .../native/org_apache_harmony_dalvik_ddmc_DdmServer.cc | 2 +-
+ .../org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc | 2 +-
+ runtime/native/sun_misc_Unsafe.cc | 2 +-
+ test/004-JniTest/jni_test.cc | 2 +-
+ test/139-register-natives/regnative.cc | 2 +-
+ 36 files changed, 39 insertions(+), 39 deletions(-)
+
+diff --git a/benchmark/micro-native/micro_native.cc b/benchmark/micro-native/micro_native.cc
+index dffbf3b11d..e70366cc48 100644
+--- a/benchmark/micro-native/micro_native.cc
++++ b/benchmark/micro-native/micro_native.cc
+@@ -38,7 +38,7 @@
+ static void NativeMethods_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
+ static void NativeMethods_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
+
+-static JNINativeMethod gMethods_NormalOnly[] = {
++static const JNINativeMethod gMethods_NormalOnly[] = {
+ NATIVE_METHOD(NativeMethods, emptyJniStaticSynchronizedMethod0, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniSynchronizedMethod0, "()V"),
+ };
+@@ -53,7 +53,7 @@ static void NativeMethods_emptyJniStaticMethod6L(JNIEnv*, jclass, jobject, jarra
+ static void NativeMethods_emptyJniStaticMethod0(JNIEnv*, jclass) { }
+ static void NativeMethods_emptyJniStaticMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(NativeMethods, emptyJniMethod0, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6, "(IIIIII)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+@@ -72,7 +72,7 @@ static void NativeMethods_emptyJniStaticMethod6L_Fast(JNIEnv*, jclass, jobject,
+ static void NativeMethods_emptyJniStaticMethod0_Fast(JNIEnv*, jclass) { }
+ static void NativeMethods_emptyJniStaticMethod6_Fast(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+-static JNINativeMethod gMethods_Fast[] = {
++static const JNINativeMethod gMethods_Fast[] = {
+ NATIVE_METHOD(NativeMethods, emptyJniMethod0_Fast, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6_Fast, "(IIIIII)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+@@ -88,7 +88,7 @@ DEFINE_CRITICAL_JNI_METHOD(void, emptyJniStaticMethod0_1Critical)() { }
+ DEFINE_NORMAL_JNI_METHOD(void, emptyJniStaticMethod6_1Critical)(JNIEnv*, jclass, int, int, int, int, int, int) { }
+ DEFINE_CRITICAL_JNI_METHOD(void, emptyJniStaticMethod6_1Critical)(int, int, int, int, int, int) { }
+
+-static JNINativeMethod gMethods_Critical[] = {
++static const JNINativeMethod gMethods_Critical[] = {
+ // Don't use NATIVE_METHOD because the name is mangled differently.
+ { "emptyJniStaticMethod0_Critical", "()V",
+ reinterpret_cast(NAME_CRITICAL_JNI_METHOD(emptyJniStaticMethod0_1Critical)) },
+diff --git a/runtime/native/dalvik_system_BaseDexClassLoader.cc b/runtime/native/dalvik_system_BaseDexClassLoader.cc
+index a4f702c28d..01ea613b1c 100644
+--- a/runtime/native/dalvik_system_BaseDexClassLoader.cc
++++ b/runtime/native/dalvik_system_BaseDexClassLoader.cc
+@@ -69,7 +69,7 @@ static jobjectArray BaseDexClassLoader_computeClassLoaderContextsNative(JNIEnv*
+ return soa.AddLocalReference(array.Get());
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(BaseDexClassLoader, computeClassLoaderContextsNative,
+ "()[Ljava/lang/String;"),
+ };
+diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
+index f602f73630..8539ed8082 100644
+--- a/runtime/native/dalvik_system_DexFile.cc
++++ b/runtime/native/dalvik_system_DexFile.cc
+@@ -994,7 +994,7 @@ static void DexFile_setTrusted(JNIEnv* env, jclass, jobject j_cookie) {
+ }
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(DexFile, closeDexFile, "(Ljava/lang/Object;)Z"),
+ NATIVE_METHOD(DexFile,
+ defineClassNative,
+diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
+index cf2b25d6a2..d6fdb84873 100644
+--- a/runtime/native/dalvik_system_VMDebug.cc
++++ b/runtime/native/dalvik_system_VMDebug.cc
+@@ -514,7 +514,7 @@ static void VMDebug_setAllocTrackerStackDepth(JNIEnv* env, jclass, jint stack_de
+ }
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
+ NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"),
+ NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;I)V"),
+diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
+index f1561a2530..a1de2b5936 100644
+--- a/runtime/native/dalvik_system_VMRuntime.cc
++++ b/runtime/native/dalvik_system_VMRuntime.cc
+@@ -536,7 +536,7 @@ static jobject VMRuntime_getBaseApkOptimizationInfo(JNIEnv* env, [[maybe_unused]
+ return env->NewObject(cls.get(), ctor, j_compiler_filter.get(), j_compilation_reason.get());
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"),
+ NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, clampGrowthLimit, "()V"),
+diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
+index 71078c9ad2..457d3887df 100644
+--- a/runtime/native/dalvik_system_VMStack.cc
++++ b/runtime/native/dalvik_system_VMStack.cc
+@@ -168,7 +168,7 @@ static jobjectArray VMStack_getAnnotatedThreadStackTrace(JNIEnv* env, jclass, jo
+ return GetThreadStack(soa, javaThread, fn);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(VMStack, fillStackTraceElements, "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
+ FAST_NATIVE_METHOD(VMStack, getCallingClassLoader, "()Ljava/lang/ClassLoader;"),
+ FAST_NATIVE_METHOD(VMStack, getClosestUserClassLoader, "()Ljava/lang/ClassLoader;"),
+diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
+index dd44e2ec4b..22e35360a3 100644
+--- a/runtime/native/dalvik_system_ZygoteHooks.cc
++++ b/runtime/native/dalvik_system_ZygoteHooks.cc
+@@ -466,7 +466,7 @@ static jboolean ZygoteHooks_nativeZygoteLongSuspendOk([[maybe_unused]] JNIEnv* e
+ return (isJitZygote || explicitlyDisabled) ? JNI_FALSE : JNI_TRUE;
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"),
+ NATIVE_METHOD(ZygoteHooks, nativePostZygoteFork, "()V"),
+ NATIVE_METHOD(ZygoteHooks, nativePostForkSystemServer, "(I)V"),
+diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
+index 2abc4935e0..2abe4545a6 100644
+--- a/runtime/native/java_lang_Class.cc
++++ b/runtime/native/java_lang_Class.cc
+@@ -971,7 +971,7 @@ static jobject Class_newInstance(JNIEnv* env, jobject javaThis) {
+ return soa.AddLocalReference(receiver.Get());
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Class, classForName,
+ "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
+ FAST_NATIVE_METHOD(Class, ensureExtDataPresent, "()Ldalvik/system/ClassExt;"),
+diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
+index 8fc10d1114..8740755199 100644
+--- a/runtime/native/java_lang_Object.cc
++++ b/runtime/native/java_lang_Object.cc
+@@ -54,7 +54,7 @@ static jint Object_identityHashCodeNative(JNIEnv* env, jclass, jobject javaObjec
+ return static_cast(o->IdentityHashCode());
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Object, internalClone, "()Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(Object, notify, "()V"),
+ FAST_NATIVE_METHOD(Object, notifyAll, "()V"),
+diff --git a/runtime/native/java_lang_StackStreamFactory.cc b/runtime/native/java_lang_StackStreamFactory.cc
+index f876c1014b..f62670350f 100644
+--- a/runtime/native/java_lang_StackStreamFactory.cc
++++ b/runtime/native/java_lang_StackStreamFactory.cc
+@@ -41,7 +41,7 @@ static jint StackStreamFactory_nativeFetchStackFrameInfo(JNIEnv* env, jclass,
+ startLevel, batchSize, startBufferIndex, frameBuffer);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(StackStreamFactory, nativeGetStackAnchor, "()Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(StackStreamFactory, nativeFetchStackFrameInfo, "(JLjava/lang/Object;III[Ljava/lang/Object;)I"),
+ };
+diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
+index f70a188e79..e982c4e3c9 100644
+--- a/runtime/native/java_lang_String.cc
++++ b/runtime/native/java_lang_String.cc
+@@ -133,7 +133,7 @@ static jstring String_doRepeat(JNIEnv* env, jobject java_this, jint count) {
+ return soa.AddLocalReference(result);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(String, charAt, "(I)C"),
+ FAST_NATIVE_METHOD(String, compareTo, "(Ljava/lang/String;)I"),
+ FAST_NATIVE_METHOD(String, concat, "(Ljava/lang/String;)Ljava/lang/String;"),
+diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
+index 2fbebc0941..62f3fcd566 100644
+--- a/runtime/native/java_lang_StringFactory.cc
++++ b/runtime/native/java_lang_StringFactory.cc
+@@ -294,7 +294,7 @@ static jstring StringFactory_newStringFromUtf8Bytes(JNIEnv* env, jclass, jbyteAr
+ return soa.AddLocalReference(result);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(StringFactory, newStringFromBytes, "([BIII)Ljava/lang/String;"),
+ FAST_NATIVE_METHOD(StringFactory, newStringFromChars, "(II[C)Ljava/lang/String;"),
+ FAST_NATIVE_METHOD(StringFactory, newStringFromString, "(Ljava/lang/String;)Ljava/lang/String;"),
+diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
+index 63cbd2c815..e7b3894aad 100644
+--- a/runtime/native/java_lang_System.cc
++++ b/runtime/native/java_lang_System.cc
+@@ -239,7 +239,7 @@ static void System_arraycopyBooleanUnchecked(JNIEnv* env,
+ javaDst, dstPos, count);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(System, arraycopy, "(Ljava/lang/Object;ILjava/lang/Object;II)V"),
+ FAST_NATIVE_METHOD(System, arraycopyCharUnchecked, "([CI[CII)V"),
+ FAST_NATIVE_METHOD(System, arraycopyByteUnchecked, "([BI[BII)V"),
+diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
+index 570c554782..f90db08a8d 100644
+--- a/runtime/native/java_lang_Thread.cc
++++ b/runtime/native/java_lang_Thread.cc
+@@ -195,7 +195,7 @@ static void Thread_yield(JNIEnv*, jobject) {
+ sched_yield();
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Thread, currentThread, "()Ljava/lang/Thread;"),
+ FAST_NATIVE_METHOD(Thread, interrupted, "()Z"),
+ FAST_NATIVE_METHOD(Thread, isInterrupted, "()Z"),
+diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
+index b89e287481..5cdd70c513 100644
+--- a/runtime/native/java_lang_Throwable.cc
++++ b/runtime/native/java_lang_Throwable.cc
+@@ -38,7 +38,7 @@ static jobjectArray Throwable_nativeGetStackTrace(JNIEnv* env, jclass, jobject j
+ return Thread::InternalStackTraceToStackTraceElementArray(soa, javaStackState);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Throwable, nativeFillInStackTrace, "()Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(Throwable, nativeGetStackTrace, "(Ljava/lang/Object;)[Ljava/lang/StackTraceElement;"),
+ };
+diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
+index 4dad46fb8c..3208a65c8e 100644
+--- a/runtime/native/java_lang_VMClassLoader.cc
++++ b/runtime/native/java_lang_VMClassLoader.cc
+@@ -164,7 +164,7 @@ static jobjectArray VMClassLoader_getBootClassPathEntries(JNIEnv* env, jclass) {
+ MakeTransformRange(Filter(path, dchecked_is_base_dex), get_location)));
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(VMClassLoader, findLoadedClass, "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;"),
+ NATIVE_METHOD(VMClassLoader, getBootClassPathEntries, "()[Ljava/lang/String;"),
+ };
+diff --git a/runtime/native/java_lang_invoke_MethodHandle.cc b/runtime/native/java_lang_invoke_MethodHandle.cc
+index 5309a28a09..ed2d5ae126 100644
+--- a/runtime/native/java_lang_invoke_MethodHandle.cc
++++ b/runtime/native/java_lang_invoke_MethodHandle.cc
+@@ -37,7 +37,7 @@ static void MethodHandle_invokeExactWithFrame(JNIEnv* env, jobject thiz, jobject
+ MethodHandleInvokeExactWithFrame(soa.Self(), handle, frame);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(MethodHandle, invokeExactWithFrame, "(Ldalvik/system/EmulatedStackFrame;)V")
+ };
+
+diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.cc b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
+index 00ce01f11a..fc53b82d36 100644
+--- a/runtime/native/java_lang_invoke_MethodHandleImpl.cc
++++ b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
+@@ -63,7 +63,7 @@ static jobject MethodHandleImpl_getMemberInternal(JNIEnv* env, jobject thiz) {
+ return soa.AddLocalReference(h_object.Get());
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(MethodHandleImpl, getMemberInternal, "()Ljava/lang/reflect/Member;"),
+ };
+
+diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
+index 535b243411..0a8dfb6c09 100644
+--- a/runtime/native/java_lang_ref_FinalizerReference.cc
++++ b/runtime/native/java_lang_ref_FinalizerReference.cc
+@@ -42,7 +42,7 @@ static jobject FinalizerReference_getReferent(JNIEnv* env, jobject javaThis) {
+ return soa.AddLocalReference(referent);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(FinalizerReference, makeCircularListIfUnenqueued, "()Z"),
+ FAST_NATIVE_METHOD(FinalizerReference, getReferent, "()Ljava/lang/Object;"),
+ };
+diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
+index bd7235e14f..c2ee0f4c22 100644
+--- a/runtime/native/java_lang_ref_Reference.cc
++++ b/runtime/native/java_lang_ref_Reference.cc
+@@ -76,7 +76,7 @@ static void Reference_clearReferent(JNIEnv* env, jobject javaThis) {
+ Runtime::Current()->GetHeap()->GetReferenceProcessor()->ClearReferent(ref);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Reference, getReferent, "()Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(Reference, clearReferent, "()V"),
+ FAST_NATIVE_METHOD(Reference, refersTo0, "(Ljava/lang/Object;)Z"),
+diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
+index ff94593cdf..e359e7d8a8 100644
+--- a/runtime/native/java_lang_reflect_Array.cc
++++ b/runtime/native/java_lang_reflect_Array.cc
+@@ -74,7 +74,7 @@ static jobject Array_createObjectArray(JNIEnv* env, jclass, jclass javaElementCl
+ return soa.AddLocalReference(new_array);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Array, createMultiArray, "(Ljava/lang/Class;[I)Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(Array, createObjectArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
+ };
+diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
+index 98afddc260..5f8196a4e5 100644
+--- a/runtime/native/java_lang_reflect_Constructor.cc
++++ b/runtime/native/java_lang_reflect_Constructor.cc
+@@ -129,7 +129,7 @@ static jobject Constructor_newInstanceFromSerialization(JNIEnv* env,
+ return env->NewObject(allocClass, ctor);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Constructor, getExceptionTypes, "()[Ljava/lang/Class;"),
+ FAST_NATIVE_METHOD(Constructor, newInstance0, "([Ljava/lang/Object;)Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(Constructor, newInstanceFromSerialization, "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Object;"),
+diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
+index 87c9f6c341..db54200ef0 100644
+--- a/runtime/native/java_lang_reflect_Executable.cc
++++ b/runtime/native/java_lang_reflect_Executable.cc
+@@ -363,7 +363,7 @@ static jint Executable_getParameterCountInternal(JNIEnv* env, jobject javaMethod
+ }
+
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Executable, compareMethodParametersInternal,
+ "(Ljava/lang/reflect/Method;)I"),
+ FAST_NATIVE_METHOD(Executable, getAnnotationNative,
+diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
+index f2603d4c48..e1b91c6de2 100644
+--- a/runtime/native/java_lang_reflect_Field.cc
++++ b/runtime/native/java_lang_reflect_Field.cc
+@@ -549,7 +549,7 @@ static jboolean Field_isAnnotationPresentNative(JNIEnv* env,
+ return annotations::IsFieldAnnotationPresent(field, klass);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Field, get, "(Ljava/lang/Object;)Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(Field, getBoolean, "(Ljava/lang/Object;)Z"),
+ FAST_NATIVE_METHOD(Field, getByte, "(Ljava/lang/Object;)B"),
+diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
+index 5f02ad0fd9..e2440d3dc8 100644
+--- a/runtime/native/java_lang_reflect_Method.cc
++++ b/runtime/native/java_lang_reflect_Method.cc
+@@ -86,7 +86,7 @@ static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiv
+ return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Method, getDefaultValue, "()Ljava/lang/Object;"),
+ FAST_NATIVE_METHOD(Method, getExceptionTypes, "()[Ljava/lang/Class;"),
+ FAST_NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
+diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
+index 263a56796f..92bf9078a4 100644
+--- a/runtime/native/java_lang_reflect_Parameter.cc
++++ b/runtime/native/java_lang_reflect_Parameter.cc
+@@ -98,7 +98,7 @@ static jobject Parameter_getAnnotationNative(JNIEnv* env,
+ annotations::GetAnnotationForMethodParameter(method, parameterIndex, klass));
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(
+ Parameter,
+ getAnnotationNative,
+diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
+index f723ed223d..c2b533de5d 100644
+--- a/runtime/native/java_lang_reflect_Proxy.cc
++++ b/runtime/native/java_lang_reflect_Proxy.cc
+@@ -37,7 +37,7 @@ static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArra
+ soa, name, interfaces, loader, methods, throws));
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
+ };
+
+diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
+index fa288edcb8..299ac5a61d 100644
+--- a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
++++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
+@@ -30,7 +30,7 @@ static jboolean AtomicLong_VMSupportsCS8(JNIEnv*, jclass) {
+ return QuasiAtomic::LongAtomicsUseMutexes(kRuntimeISA) ? JNI_FALSE : JNI_TRUE;
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(AtomicLong, VMSupportsCS8, "()Z"),
+ };
+
+diff --git a/runtime/native/jdk_internal_misc_Unsafe.cc b/runtime/native/jdk_internal_misc_Unsafe.cc
+index 9b2021d176..c9de0a1862 100644
+--- a/runtime/native/jdk_internal_misc_Unsafe.cc
++++ b/runtime/native/jdk_internal_misc_Unsafe.cc
+@@ -506,7 +506,7 @@ static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) {
+ }
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Unsafe, compareAndSwapInt, "(Ljava/lang/Object;JII)Z"),
+ FAST_NATIVE_METHOD(Unsafe, compareAndSwapLong, "(Ljava/lang/Object;JJJ)Z"),
+ FAST_NATIVE_METHOD(
+diff --git a/runtime/native/libcore_io_Memory.cc b/runtime/native/libcore_io_Memory.cc
+index 5e38280259..8648ea3799 100644
+--- a/runtime/native/libcore_io_Memory.cc
++++ b/runtime/native/libcore_io_Memory.cc
+@@ -181,7 +181,7 @@ static void Memory_peekShortArray(JNIEnv* env,
+ }
+
+ // The remaining Memory methods are contained in libcore/luni/src/main/native/libcore_io_Memory.cpp
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Memory, peekByteArray, "(J[BII)V"),
+ FAST_NATIVE_METHOD(Memory, peekCharArray, "(J[CIIZ)V"),
+ FAST_NATIVE_METHOD(Memory, peekDoubleArray, "(J[DIIZ)V"),
+diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc
+index 46f8993a10..0c053dfb28 100644
+--- a/runtime/native/libcore_util_CharsetUtils.cc
++++ b/runtime/native/libcore_util_CharsetUtils.cc
+@@ -137,7 +137,7 @@ static jbyteArray CharsetUtils_toUtf8Bytes(JNIEnv* env, jclass, jstring java_str
+ return soa.AddLocalReference(result);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(CharsetUtils, asciiBytesToChars, "([BII[C)V"),
+ FAST_NATIVE_METHOD(CharsetUtils, toAsciiBytes, "(Ljava/lang/String;II)[B"),
+ FAST_NATIVE_METHOD(CharsetUtils, toIsoLatin1Bytes, "(Ljava/lang/String;II)[B"),
+diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+index 419aed8578..ccbef4f3f4 100644
+--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
++++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+@@ -38,7 +38,7 @@ static void DdmServer_nativeSendChunk(JNIEnv* env, jclass, jint type,
+ Runtime::Current()->GetRuntimeCallbacks()->DdmPublishChunk(static_cast(type), chunk);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(DdmServer, nativeSendChunk, "(I[BII)V"),
+ };
+
+diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+index 081ec2043a..a84d522e23 100644
+--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
++++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+@@ -211,7 +211,7 @@ static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) {
+ return result;
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(DdmVmInternal, setRecentAllocationsTrackingEnabled, "(Z)V"),
+ NATIVE_METHOD(DdmVmInternal, setThreadNotifyEnabled, "(Z)V"),
+ NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"),
+diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
+index f1e47ee100..d2f3a00897 100644
+--- a/runtime/native/sun_misc_Unsafe.cc
++++ b/runtime/native/sun_misc_Unsafe.cc
+@@ -546,7 +546,7 @@ static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) {
+ }
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Unsafe, compareAndSwapInt, "(Ljava/lang/Object;JII)Z"),
+ FAST_NATIVE_METHOD(Unsafe, compareAndSwapLong, "(Ljava/lang/Object;JJJ)Z"),
+ FAST_NATIVE_METHOD(Unsafe, compareAndSwapObject, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z"),
+diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
+index 429bd94fe0..1518f931ab 100644
+--- a/test/004-JniTest/jni_test.cc
++++ b/test/004-JniTest/jni_test.cc
+@@ -33,7 +33,7 @@ static JavaVM* jvm = nullptr;
+ static jint Java_Main_intFastNativeMethod(JNIEnv*, jclass, jint a, jint b, jint c);
+ static jint Java_Main_intCriticalNativeMethod(jint a, jint b, jint c);
+
+-static JNINativeMethod sMainMethods[] = {
++static const JNINativeMethod sMainMethods[] = {
+ {"intFastNativeMethod", "(III)I", reinterpret_cast(Java_Main_intFastNativeMethod) },
+ {"intCriticalNativeMethod", "(III)I", reinterpret_cast(Java_Main_intCriticalNativeMethod) },
+ };
+diff --git a/test/139-register-natives/regnative.cc b/test/139-register-natives/regnative.cc
+index d9c8b31ac7..083c14c1ec 100644
+--- a/test/139-register-natives/regnative.cc
++++ b/test/139-register-natives/regnative.cc
+@@ -22,7 +22,7 @@ namespace art {
+ static void foo(JNIEnv*, jclass) {
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ { "foo", "()V", reinterpret_cast(foo) }
+ };
+
diff --git a/Patches/LineageOS-21.0/android_bionic/0001-HM-No_GWP_ASan.patch b/Patches/LineageOS-21.0/android_bionic/0001-HM-No_GWP_ASan.patch
new file mode 100644
index 00000000..f5dc9abf
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0001-HM-No_GWP_ASan.patch
@@ -0,0 +1,77 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Wed, 1 Nov 2023 21:27:18 +0200
+Subject: [PATCH] never enable GWP-ASan
+
+It weakens hardened_malloc protections, especially when memory tagging is enabled.
+---
+ libc/bionic/gwp_asan_wrappers.h | 7 -------
+ libc/bionic/malloc_common.cpp | 8 --------
+ libc/bionic/malloc_common_dynamic.cpp | 10 ----------
+ 3 files changed, 25 deletions(-)
+
+diff --git a/libc/bionic/gwp_asan_wrappers.h b/libc/bionic/gwp_asan_wrappers.h
+index 219da9fc5..9053d4aa4 100644
+--- a/libc/bionic/gwp_asan_wrappers.h
++++ b/libc/bionic/gwp_asan_wrappers.h
+@@ -35,13 +35,6 @@
+ #include "private/bionic_globals.h"
+ #include "private/bionic_malloc_dispatch.h"
+
+-// Enable GWP-ASan, used by android_mallopt. Should always be called in a
+-// single-threaded context.
+-bool EnableGwpAsan(const android_mallopt_gwp_asan_options_t& options);
+-
+-// Hooks for libc to possibly install GWP-ASan.
+-bool MaybeInitGwpAsanFromLibc(libc_globals* globals);
+-
+ // Returns whether GWP-ASan is the provided dispatch table pointer. Used in
+ // heapprofd's signal-initialization sequence to determine the intermediate
+ // dispatch pointer to use when initing.
+diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
+index 1ab4861af..9363d7b63 100644
+--- a/libc/bionic/malloc_common.cpp
++++ b/libc/bionic/malloc_common.cpp
+@@ -340,14 +340,6 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) {
+ if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) {
+ return LimitEnable(arg, arg_size);
+ }
+- if (opcode == M_INITIALIZE_GWP_ASAN) {
+- if (arg == nullptr || arg_size != sizeof(android_mallopt_gwp_asan_options_t)) {
+- errno = EINVAL;
+- return false;
+- }
+-
+- return EnableGwpAsan(*reinterpret_cast(arg));
+- }
+ if (opcode == M_MEMTAG_STACK_IS_ON) {
+ if (arg == nullptr || arg_size != sizeof(bool)) {
+ errno = EINVAL;
+diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
+index 2cafe9249..84be92ee1 100644
+--- a/libc/bionic/malloc_common_dynamic.cpp
++++ b/libc/bionic/malloc_common_dynamic.cpp
+@@ -383,8 +383,6 @@ static void MallocInitImpl(libc_globals* globals) {
+ char prop[PROP_VALUE_MAX];
+ char* options = prop;
+
+- MaybeInitGwpAsanFromLibc(globals);
+-
+ #if defined(USE_SCUDO)
+ __libc_shared_globals()->scudo_stack_depot = __scudo_get_stack_depot_addr();
+ __libc_shared_globals()->scudo_region_info = __scudo_get_region_info_addr();
+@@ -533,14 +531,6 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) {
+ }
+ return FreeMallocLeakInfo(reinterpret_cast(arg));
+ }
+- if (opcode == M_INITIALIZE_GWP_ASAN) {
+- if (arg == nullptr || arg_size != sizeof(android_mallopt_gwp_asan_options_t)) {
+- errno = EINVAL;
+- return false;
+- }
+-
+- return EnableGwpAsan(*reinterpret_cast(arg));
+- }
+ if (opcode == M_MEMTAG_STACK_IS_ON) {
+ if (arg == nullptr || arg_size != sizeof(bool)) {
+ errno = EINVAL;
diff --git a/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-1.patch b/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-1.patch
new file mode 100644
index 00000000..fff89b3f
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-1.patch
@@ -0,0 +1,99 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Sun, 14 Aug 2022 15:13:01 +0300
+Subject: [PATCH] add a runtime option to disable hardened_malloc
+
+---
+ libc/bionic/malloc_common.cpp | 50 +++++++++++++++++++++++++++
+ libc/bionic/malloc_common.h | 1 +
+ libc/bionic/malloc_common_dynamic.cpp | 4 +++
+ 3 files changed, 55 insertions(+)
+
+diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
+index 3c4884b2c..86e6fdcf9 100644
+--- a/libc/bionic/malloc_common.cpp
++++ b/libc/bionic/malloc_common.cpp
+@@ -393,6 +393,56 @@ static constexpr MallocDispatch __libc_malloc_default_dispatch __attribute__((un
+ Malloc(malloc_info),
+ };
+
++#if defined(BOTH_H_MALLOC_AND_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) {
++ const bool hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr;
++
++ 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
+diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h
+index 8852c85a2..ef4b1a4be 100644
+--- a/libc/bionic/malloc_common.h
++++ b/libc/bionic/malloc_common.h
+@@ -68,6 +68,7 @@ __END_DECLS
+
+ #if defined(USE_SCUDO)
+ #include "scudo.h"
++void InitNativeAllocatorDispatch(libc_globals* globals);
+ #endif
+
+ #define BOTH_H_MALLOC_AND_SCUDO
+diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
+index a6bf7a7bb..2cafe9249 100644
+--- a/libc/bionic/malloc_common_dynamic.cpp
++++ b/libc/bionic/malloc_common_dynamic.cpp
+@@ -376,6 +376,10 @@ extern "C" size_t __scudo_get_stack_depot_size();
+
+ // Initializes memory allocation framework once per process.
+ static void MallocInitImpl(libc_globals* globals) {
++#if defined(BOTH_H_MALLOC_AND_SCUDO)
++ InitNativeAllocatorDispatch(globals);
++#endif
++
+ char prop[PROP_VALUE_MAX];
+ char* options = prop;
+
diff --git a/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-2.patch b/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-2.patch
new file mode 100644
index 00000000..f3add8f4
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-2.patch
@@ -0,0 +1,95 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Tue, 2 May 2023 16:45:26 +0300
+Subject: [PATCH] support assigning ID to path of current executable
+
+---
+ libc/bionic/libc_init_dynamic.cpp | 27 ++++++++++++++++++++++++++-
+ libc/include/stdlib.h | 3 +++
+ libc/libc.map.txt | 1 +
+ libc/private/bionic_globals.h | 1 +
+ 4 files changed, 31 insertions(+), 1 deletion(-)
+
+diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
+index c61810e34..804e586e2 100644
+--- a/libc/bionic/libc_init_dynamic.cpp
++++ b/libc/bionic/libc_init_dynamic.cpp
+@@ -72,6 +72,28 @@ extern "C" __attribute__((weak)) void __hwasan_library_unloaded(ElfW(Addr) base,
+ const ElfW(Phdr)* phdr,
+ ElfW(Half) phnum);
+
++static void init_prog_id(libc_globals* globals) {
++ char exe_path[500];
++ ssize_t readlink_res = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1 /* space for NUL terminator */);
++ if (readlink_res <= 0) {
++ return;
++ }
++ exe_path[readlink_res] = '\0';
++
++ int prog_id = 0;
++
++#define IS(prog) (!strcmp(exe_path, prog))
++
++#undef IS
++
++ // libc_globals struct is write-protected
++ globals->prog_id = prog_id;
++}
++
++int get_prog_id() {
++ return __libc_globals->prog_id;
++}
++
+ // We need a helper function for __libc_preinit because compiling with LTO may
+ // inline functions requiring a stack protector check, but __stack_chk_guard is
+ // not initialized at the start of __libc_preinit. __libc_preinit_impl will run
+@@ -103,7 +125,10 @@ static void __libc_preinit_impl() {
+ #endif
+
+ // Hooks for various libraries to let them know that we're starting up.
+- __libc_globals.mutate(__libc_init_malloc);
++ __libc_globals.mutate([](libc_globals* globals) {
++ init_prog_id(globals);
++ __libc_init_malloc(globals);
++ });
+
+ // Install reserved signal handlers for assisting the platform's profilers.
+ __libc_init_profiling_handlers();
+diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
+index 2830a493d..5ce8f9103 100644
+--- a/libc/include/stdlib.h
++++ b/libc/include/stdlib.h
+@@ -210,6 +210,9 @@ long strtol_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, i
+ // Implemented as static inlines before 26.
+ #endif
+
++int get_prog_id();
++#define is_prog(id) (get_prog_id() == id)
++
+ __END_DECLS
+
+ #include
+diff --git a/libc/libc.map.txt b/libc/libc.map.txt
+index 156e9ee32..5d87cd8ef 100644
+--- a/libc/libc.map.txt
++++ b/libc/libc.map.txt
+@@ -420,6 +420,7 @@ LIBC {
+ get_nprocs; # introduced=23
+ get_nprocs_conf; # introduced=23
+ get_phys_pages; # introduced=23
++ get_prog_id;
+ getaddrinfo;
+ getauxval; # introduced-arm=18 introduced-arm64=21 introduced-x86=18 introduced-x86_64=21
+ getc;
+diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
+index 8ea7d4d66..66f8d84b0 100644
+--- a/libc/private/bionic_globals.h
++++ b/libc/private/bionic_globals.h
+@@ -65,6 +65,7 @@ struct libc_globals {
+ // limit is enabled and some other hook is enabled at the same time.
+ _Atomic(const MallocDispatch*) default_dispatch_table;
+ MallocDispatch malloc_dispatch_table;
++ int prog_id;
+ };
+
+ struct memtag_dynamic_entries_t {
diff --git a/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-3.patch b/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-3.patch
new file mode 100644
index 00000000..eb0bc4b9
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0001-HM-Runtime_Control-3.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Tue, 2 May 2023 16:46:56 +0300
+Subject: [PATCH] support disabling hardened_malloc for specific program IDs
+
+---
+ libc/bionic/malloc_common.cpp | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
+index 86e6fdcf9..3d3e8ef61 100644
+--- a/libc/bionic/malloc_common.cpp
++++ b/libc/bionic/malloc_common.cpp
+@@ -423,7 +423,11 @@ static constexpr MallocDispatch __scudo_malloc_dispatch __attribute__((unused))
+ static const MallocDispatch* native_allocator_dispatch;
+
+ void InitNativeAllocatorDispatch(libc_globals* globals) {
+- const bool hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr;
++ bool hardened_impl = true;
++ switch (get_prog_id()) {
++ default:
++ hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr;
++ }
+
+ const MallocDispatch* table = hardened_impl ?
+ &__libc_malloc_default_dispatch :
diff --git a/Patches/LineageOS-21.0/android_bionic/0001-HM-Use_HM.patch b/Patches/LineageOS-21.0/android_bionic/0001-HM-Use_HM.patch
new file mode 100644
index 00000000..39367a0b
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0001-HM-Use_HM.patch
@@ -0,0 +1,189 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 5 Dec 2018 08:51:56 +0200
+Subject: [PATCH] use Scudo on 32-bit and hardened_malloc on 64-bit
+
+64-bit Scudo can be swithed to at runtime, see the next commit.
+
+Squashed with 6562b94dfc6dec13e1df79a1b029e6c78f4aa9ad
+
+Co-authored-by: anupritaisno1
+---
+ libc/Android.bp | 45 ++++++++++++++++++++++------
+ libc/bionic/h_malloc_wrapper.cpp | 51 ++++++++++++++++++++++++++++++++
+ libc/bionic/malloc_common.h | 25 +++++++++-------
+ 3 files changed, 102 insertions(+), 19 deletions(-)
+ create mode 100644 libc/bionic/h_malloc_wrapper.cpp
+
+diff --git a/libc/Android.bp b/libc/Android.bp
+index 71d8ee556..13cefe94f 100644
+--- a/libc/Android.bp
++++ b/libc/Android.bp
+@@ -76,6 +76,8 @@ libc_common_flags = [
+ // ever touch 0, 1, or 2 bytes into a call to memset, which was never going
+ // to amortize.)
+ "-fno-builtin",
++
++ "-DH_MALLOC_PREFIX",
+ ]
+
+ // Define some common cflags
+@@ -159,13 +161,30 @@ libc_scudo_product_variables = {
+ // ========================================================
+ cc_defaults {
+ name: "libc_native_allocator_defaults",
++ whole_static_libs: ["libc_jemalloc_wrapper"],
++ multilib: {
++ lib32: {
++ cflags: ["-DUSE_SCUDO"],
++ whole_static_libs: ["libscudo"],
++ exclude_static_libs: [
++ "libjemalloc5",
++ "libc_jemalloc_wrapper",
++ ],
++ },
++ lib64: {
++ cflags: [
++ "-DH_MALLOC_PREFIX",
++ "-DUSE_H_MALLOC",
++ "-DUSE_SCUDO",
++ ],
++ whole_static_libs: [
++ "libhardened_malloc",
++ "libscudo",
++ ],
++ },
++ },
+
+- whole_static_libs: [
+- "libjemalloc5",
+- "libc_jemalloc_wrapper",
+- ],
+ header_libs: ["gwp_asan_headers"],
+- product_variables: libc_scudo_product_variables,
+ }
+
+ // Functions not implemented by jemalloc directly, or that need to
+@@ -173,12 +192,20 @@ cc_defaults {
+ cc_library_static {
+ name: "libc_jemalloc_wrapper",
+ defaults: ["libc_defaults"],
+- srcs: ["bionic/jemalloc_wrapper.cpp"],
++ multilib: {
++ lib32: {
++ // Used to pull in the jemalloc/hardened_malloc include directory so that if the
++ // library is removed, the include directory is also removed.
++ srcs: ["bionic/jemalloc_wrapper.cpp"],
++ static_libs: ["libjemalloc5"],
++ },
++ lib64: {
++ srcs: ["bionic/h_malloc_wrapper.cpp"],
++ static_libs: ["libhardened_malloc"],
++ },
++ },
+ cflags: ["-fvisibility=hidden"],
+
+- // Used to pull in the jemalloc include directory so that if the
+- // library is removed, the include directory is also removed.
+- static_libs: ["libjemalloc5"],
+ }
+
+ // ========================================================
+diff --git a/libc/bionic/h_malloc_wrapper.cpp b/libc/bionic/h_malloc_wrapper.cpp
+new file mode 100644
+index 000000000..5fb0968c2
+--- /dev/null
++++ b/libc/bionic/h_malloc_wrapper.cpp
+@@ -0,0 +1,51 @@
++#include
++#include
++#include
++#include
++
++#include
++
++#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;
++}
+diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h
+index 4afcc4a8d..8852c85a2 100644
+--- a/libc/bionic/malloc_common.h
++++ b/libc/bionic/malloc_common.h
+@@ -55,21 +55,26 @@ __END_DECLS
+
+ #else // __has_feature(hwaddress_sanitizer)
+
+-#if defined(USE_SCUDO)
+-
+-#include "scudo.h"
+-#define Malloc(function) scudo_ ## function
++#ifdef __LP64__
++#ifndef USE_H_MALLOC
++#error missing USE_H_MALLOC
++#endif
+
+-#elif defined(USE_SCUDO_SVELTE)
++#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"
+-#define Malloc(function) scudo_svelte_ ## function
+-
+-#else
++#endif
+
+-#include "jemalloc.h"
+-#define Malloc(function) je_ ## function
++#define BOTH_H_MALLOC_AND_SCUDO
+
++#else // 32-bit
++#include "scudo.h"
++#define Malloc(function) scudo_ ## function
+ #endif
+
+ #endif
diff --git a/Patches/LineageOS-21.0/android_bionic/0001-HM-Workaround-1.patch b/Patches/LineageOS-21.0/android_bionic/0001-HM-Workaround-1.patch
new file mode 100644
index 00000000..e314c767
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0001-HM-Workaround-1.patch
@@ -0,0 +1,51 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Tue, 2 May 2023 16:47:49 +0300
+Subject: [PATCH] disable hardened_malloc for Pixel camera provider service
+
+---
+ libc/bionic/libc_init_dynamic.cpp | 3 +++
+ libc/bionic/malloc_common.cpp | 3 +++
+ libc/include/stdlib.h | 1 +
+ 3 files changed, 7 insertions(+)
+
+diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
+index 804e586e2..7097a70b0 100644
+--- a/libc/bionic/libc_init_dynamic.cpp
++++ b/libc/bionic/libc_init_dynamic.cpp
+@@ -84,6 +84,9 @@ static void init_prog_id(libc_globals* globals) {
+
+ #define IS(prog) (!strcmp(exe_path, prog))
+
++ if (IS("/apex/com.google.pixel.camera.hal/bin/hw/android.hardware.camera.provider@2.7-service-google")) {
++ prog_id = PROG_PIXEL_CAMERA_PROVIDER_SERVICE;
++ }
+ #undef IS
+
+ // libc_globals struct is write-protected
+diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
+index 3d3e8ef61..9b7310347 100644
+--- a/libc/bionic/malloc_common.cpp
++++ b/libc/bionic/malloc_common.cpp
+@@ -425,6 +425,9 @@ static const MallocDispatch* native_allocator_dispatch;
+ void InitNativeAllocatorDispatch(libc_globals* globals) {
+ bool hardened_impl = true;
+ switch (get_prog_id()) {
++ case PROG_PIXEL_CAMERA_PROVIDER_SERVICE:
++ hardened_impl = false;
++ break;
+ default:
+ hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr;
+ }
+diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
+index 5ce8f9103..cb8d3d3b2 100644
+--- a/libc/include/stdlib.h
++++ b/libc/include/stdlib.h
+@@ -213,6 +213,7 @@ long strtol_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, i
+ int get_prog_id();
+ #define is_prog(id) (get_prog_id() == id)
+
++#define PROG_PIXEL_CAMERA_PROVIDER_SERVICE 1
+ __END_DECLS
+
+ #include
diff --git a/Patches/LineageOS-21.0/android_bionic/0001-HM-Workaround-2.patch b/Patches/LineageOS-21.0/android_bionic/0001-HM-Workaround-2.patch
new file mode 100644
index 00000000..d65d7cd3
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0001-HM-Workaround-2.patch
@@ -0,0 +1,49 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Tue, 12 Dec 2023 20:37:48 +0200
+Subject: [PATCH] disable hardened_malloc for surfaceflinger
+
+---
+ libc/bionic/libc_init_dynamic.cpp | 3 +++
+ libc/bionic/malloc_common.cpp | 1 +
+ libc/include/stdlib.h | 1 +
+ 3 files changed, 5 insertions(+)
+
+diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
+index 7097a70b0..f83d24ea7 100644
+--- a/libc/bionic/libc_init_dynamic.cpp
++++ b/libc/bionic/libc_init_dynamic.cpp
+@@ -87,6 +87,9 @@ static void init_prog_id(libc_globals* globals) {
+ if (IS("/apex/com.google.pixel.camera.hal/bin/hw/android.hardware.camera.provider@2.7-service-google")) {
+ prog_id = PROG_PIXEL_CAMERA_PROVIDER_SERVICE;
+ }
++ else if (IS("/system/bin/surfaceflinger")) {
++ prog_id = PROG_SURFACEFLINGER;
++ }
+ #undef IS
+
+ // libc_globals struct is write-protected
+diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
+index 9b7310347..1ab4861af 100644
+--- a/libc/bionic/malloc_common.cpp
++++ b/libc/bionic/malloc_common.cpp
+@@ -426,6 +426,7 @@ void InitNativeAllocatorDispatch(libc_globals* globals) {
+ bool hardened_impl = true;
+ switch (get_prog_id()) {
+ case PROG_PIXEL_CAMERA_PROVIDER_SERVICE:
++ case PROG_SURFACEFLINGER:
+ hardened_impl = false;
+ break;
+ default:
+diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
+index cb8d3d3b2..5dd67daa4 100644
+--- a/libc/include/stdlib.h
++++ b/libc/include/stdlib.h
+@@ -214,6 +214,7 @@ int get_prog_id();
+ #define is_prog(id) (get_prog_id() == id)
+
+ #define PROG_PIXEL_CAMERA_PROVIDER_SERVICE 1
++#define PROG_SURFACEFLINGER 3
+ __END_DECLS
+
+ #include
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-1.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-1.patch
new file mode 100644
index 00000000..146b75fc
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-1.patch
@@ -0,0 +1,92 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: anupritaisno1
+Date: Wed, 13 Oct 2021 12:30:25 +0300
+Subject: [PATCH] add a real explicit_bzero implementation
+
+Clang, GCC and other compilers special-case standard C functions like
+memset. Calls to memset will be optimized out.
+
+OpenBSD provides explicit_bzero to work around this but Android simply
+defines it as memset so nothing prevents it from being optimized away.
+
+This implementation uses a memory read constraint via empty inline
+assembly rather than something that may be broken via link-time
+optimization in the future.
+
+Signed-off-by: anupritaisno1
+Change-Id: Ia021e30f86ee4b998d541fbf7262110f9d1d6fbf
+Signed-off-by: anupritaisno1
+---
+ libc/Android.bp | 1 +
+ libc/bionic/explicit_bzero.cpp | 7 +++++++
+ libc/include/string.h | 2 ++
+ libc/libc.map.txt | 1 +
+ libc/upstream-openbsd/android/include/openbsd-compat.h | 4 ----
+ 5 files changed, 11 insertions(+), 4 deletions(-)
+ create mode 100644 libc/bionic/explicit_bzero.cpp
+
+diff --git a/libc/Android.bp b/libc/Android.bp
+index 13cefe94f..9f8b689af 100644
+--- a/libc/Android.bp
++++ b/libc/Android.bp
+@@ -1127,6 +1127,7 @@ cc_library_static {
+ "bionic/eventfd.cpp",
+ "bionic/exec.cpp",
+ "bionic/execinfo.cpp",
++ "bionic/explicit_bzero.cpp",
+ "bionic/faccessat.cpp",
+ "bionic/fchmod.cpp",
+ "bionic/fchmodat.cpp",
+diff --git a/libc/bionic/explicit_bzero.cpp b/libc/bionic/explicit_bzero.cpp
+new file mode 100644
+index 000000000..dd43f9c00
+--- /dev/null
++++ b/libc/bionic/explicit_bzero.cpp
+@@ -0,0 +1,7 @@
++#include
++
++void* _Nonnull explicit_bzero(void* _Nonnull s, size_t n) {
++ void *ptr = memset(s, 0, n);
++ __asm__ __volatile__("" : : "r"(ptr) : "memory");
++ return ptr;
++}
+diff --git a/libc/include/string.h b/libc/include/string.h
+index 47bdd7271..e601ea022 100644
+--- a/libc/include/string.h
++++ b/libc/include/string.h
+@@ -64,6 +64,8 @@ void* _Nonnull memmove(void* _Nonnull __dst, const void* _Nonnull __src, size_t
+ */
+ void* _Nonnull memset(void* _Nonnull __dst, int __ch, size_t __n);
+
++void* _Nonnull explicit_bzero(void* _Nonnull s, size_t n);
++
+ /**
+ * [memset_explicit(3)](http://man7.org/linux/man-pages/man3/memset_explicit.3.html)
+ * writes the bottom 8 bits of the given int to the next `n` bytes of `dst`,
+diff --git a/libc/libc.map.txt b/libc/libc.map.txt
+index 5d87cd8ef..dd2e6c6f7 100644
+--- a/libc/libc.map.txt
++++ b/libc/libc.map.txt
+@@ -332,6 +332,7 @@ LIBC {
+ execvp;
+ execvpe; # introduced=21
+ exit;
++ explicit_bzero; # introduced=33
+ faccessat;
+ fallocate; # introduced=21
+ fallocate64; # introduced=21
+diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
+index 8e6f87da8..26dc01863 100644
+--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
++++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
+@@ -57,10 +57,6 @@ extern const char* __progname;
+ /* OpenBSD has this, but we can't really implement it correctly on Linux. */
+ #define issetugid() 0
+
+-#if !defined(ANDROID_HOST_MUSL)
+-#define explicit_bzero(p, s) memset(p, 0, s)
+-#endif
+-
+ #if defined(ANDROID_HOST_MUSL)
+ #define __LIBC_HIDDEN__ __attribute__((visibility("hidden")))
+ #endif
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-10.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-10.patch
new file mode 100644
index 00000000..999f642f
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-10.patch
@@ -0,0 +1,84 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 2 Dec 2015 23:37:28 -0500
+Subject: [PATCH] switch pthread_atfork handler allocation to mmap
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/pthread_atfork.cpp | 35 ++++++++++++++++++++++++++++------
+ 1 file changed, 29 insertions(+), 6 deletions(-)
+
+diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
+index 0dcabdfb2..6306052ee 100644
+--- a/libc/bionic/pthread_atfork.cpp
++++ b/libc/bionic/pthread_atfork.cpp
+@@ -29,6 +29,9 @@
+ #include
+ #include
+ #include
++#include
++#include
++#include
+
+ #include "platform/bionic/macros.h"
+
+@@ -43,6 +46,8 @@ struct atfork_t {
+ void* dso_handle;
+ };
+
++static atfork_t* pool;
++
+ class atfork_list_t {
+ public:
+ constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {}
+@@ -101,7 +106,8 @@ class atfork_list_t {
+ last_ = entry->prev;
+ }
+
+- free(entry);
++ entry->next = pool;
++ pool = entry;
+ }
+
+ atfork_t* first_;
+@@ -154,18 +160,35 @@ void __bionic_atfork_run_parent() {
+ // __register_atfork is the name used by glibc
+ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
+ void(*child)(void), void* dso) {
+- atfork_t* entry = reinterpret_cast(malloc(sizeof(atfork_t)));
+- if (entry == nullptr) {
+- return ENOMEM;
++ pthread_mutex_lock(&g_atfork_list_mutex);
++
++ if (!pool) {
++ size_t page_size = getpagesize();
++ char* page = static_cast(mmap(NULL, page_size, PROT_READ|PROT_WRITE,
++ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0));
++ if (page == MAP_FAILED) {
++ pthread_mutex_unlock(&g_atfork_list_mutex);
++ return ENOMEM;
++ }
++
++ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, page_size,
++ "atfork handlers");
++
++ for (char* it = page; it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) {
++ atfork_t* node = reinterpret_cast(it);
++ node->next = pool;
++ pool = node;
++ }
+ }
+
++ atfork_t* entry = pool;
++ pool = entry->next;
++
+ entry->prepare = prepare;
+ entry->parent = parent;
+ entry->child = child;
+ entry->dso_handle = dso;
+
+- pthread_mutex_lock(&g_atfork_list_mutex);
+-
+ g_atfork_list.push_back(entry);
+
+ pthread_mutex_unlock(&g_atfork_list_mutex);
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-11.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-11.patch
new file mode 100644
index 00000000..b8635e8d
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-11.patch
@@ -0,0 +1,95 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Thu, 3 Dec 2015 12:58:31 -0500
+Subject: [PATCH] add memory protection for pthread_atfork handlers
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/pthread_atfork.cpp | 34 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 32 insertions(+), 2 deletions(-)
+
+diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp
+index 6306052ee..d59f3ae54 100644
+--- a/libc/bionic/pthread_atfork.cpp
++++ b/libc/bionic/pthread_atfork.cpp
+@@ -47,6 +47,7 @@ struct atfork_t {
+ };
+
+ static atfork_t* pool;
++static atfork_t* page_list;
+
+ class atfork_list_t {
+ public:
+@@ -160,13 +161,22 @@ void __bionic_atfork_run_parent() {
+ // __register_atfork is the name used by glibc
+ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
+ void(*child)(void), void* dso) {
++ size_t page_size = getpagesize();
++
+ pthread_mutex_lock(&g_atfork_list_mutex);
+
++ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
++ mprotect(page_it, page_size, PROT_READ|PROT_WRITE);
++ }
++
+ if (!pool) {
+- size_t page_size = getpagesize();
+ char* page = static_cast(mmap(NULL, page_size, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0));
+ if (page == MAP_FAILED) {
++ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
++ mprotect(page_it, page_size, PROT_READ);
++ }
++
+ pthread_mutex_unlock(&g_atfork_list_mutex);
+ return ENOMEM;
+ }
+@@ -174,11 +184,15 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, page_size,
+ "atfork handlers");
+
+- for (char* it = page; it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) {
++ for (char* it = page + sizeof(atfork_t); it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) {
+ atfork_t* node = reinterpret_cast(it);
+ node->next = pool;
+ pool = node;
+ }
++
++ atfork_t* page_node = reinterpret_cast(page);
++ page_node->next = page_list;
++ page_list = page_node;
+ }
+
+ atfork_t* entry = pool;
+@@ -191,6 +205,10 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
+
+ g_atfork_list.push_back(entry);
+
++ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
++ mprotect(page_it, page_size, PROT_READ);
++ }
++
+ pthread_mutex_unlock(&g_atfork_list_mutex);
+
+ return 0;
+@@ -198,8 +216,20 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
+
+ extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) {
+ pthread_mutex_lock(&g_atfork_list_mutex);
++
++ size_t page_size = getpagesize();
++
++ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
++ mprotect(page_it, page_size, PROT_READ|PROT_WRITE);
++ }
++
+ g_atfork_list.remove_if([&](const atfork_t* entry) {
+ return entry->dso_handle == dso;
+ });
++
++ for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) {
++ mprotect(page_it, page_size, PROT_READ);
++ }
++
+ pthread_mutex_unlock(&g_atfork_list_mutex);
+ }
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-12.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-12.patch
new file mode 100644
index 00000000..e1c1c7a9
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-12.patch
@@ -0,0 +1,87 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 27 Jan 2016 18:02:15 -0500
+Subject: [PATCH] add XOR mangling mitigation for thread-local dtors
+
+memtag_stack struct member is required to be at its exact position by static_assert below.
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/__cxa_thread_atexit_impl.cpp | 8 +++++---
+ libc/bionic/libc_init_common.cpp | 2 ++
+ libc/private/bionic_globals.h | 1 +
+ 3 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
+index 99077c101..74608513e 100644
+--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
++++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
+@@ -13,15 +13,17 @@
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
++#include
+ #include
+
+ #include
++#include
+
+ #include "pthread_internal.h"
+
+ class thread_local_dtor {
+ public:
+- void (*func) (void *);
++ uintptr_t func;
+ void *arg;
+ void *dso_handle; // unused...
+ thread_local_dtor* next;
+@@ -35,7 +37,7 @@ __BIONIC_WEAK_FOR_NATIVE_BRIDGE
+ int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) {
+ thread_local_dtor* dtor = new thread_local_dtor();
+
+- dtor->func = func;
++ dtor->func = __libc_globals->dtor_cookie ^ reinterpret_cast(func);
+ dtor->arg = arg;
+ dtor->dso_handle = dso_handle;
+
+@@ -54,7 +56,7 @@ extern "C" __LIBC_HIDDEN__ void __cxa_thread_finalize() {
+ thread_local_dtor* current = thread->thread_local_dtors;
+ thread->thread_local_dtors = current->next;
+
+- current->func(current->arg);
++ (reinterpret_cast(__libc_globals->dtor_cookie ^ current->func))(current->arg);
+ if (__loader_remove_thread_local_dtor != nullptr) {
+ __loader_remove_thread_local_dtor(current->dso_handle);
+ }
+diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
+index 7ef79b61a..9c946b077 100644
+--- a/libc/bionic/libc_init_common.cpp
++++ b/libc/bionic/libc_init_common.cpp
+@@ -46,6 +46,7 @@
+ #include "heap_tagging.h"
+ #include "private/ScopedPthreadMutexLocker.h"
+ #include "private/WriteProtected.h"
++#include "private/bionic_arc4random.h"
+ #include "private/bionic_defs.h"
+ #include "private/bionic_globals.h"
+ #include "private/bionic_tls.h"
+@@ -70,6 +71,7 @@ void __libc_init_globals() {
+ __libc_globals.mutate([](libc_globals* globals) {
+ __libc_init_vdso(globals);
+ __libc_init_setjmp_cookie(globals);
++ arc4random_buf(&globals->dtor_cookie, sizeof(globals->dtor_cookie));
+ });
+ }
+
+diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
+index 66f8d84b0..bd34e3a08 100644
+--- a/libc/private/bionic_globals.h
++++ b/libc/private/bionic_globals.h
+@@ -50,6 +50,7 @@ struct libc_globals {
+ uintptr_t heap_pointer_tag;
+ _Atomic(bool) memtag_stack;
+ _Atomic(bool) decay_time_enabled;
++ long dtor_cookie;
+
+ // In order to allow a complete switch between dispatch tables without
+ // the need for copying each function by function in the structure,
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-13.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-13.patch
new file mode 100644
index 00000000..6cebd2ea
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-13.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Fri, 29 Jan 2016 20:20:09 -0500
+Subject: [PATCH] use a better pthread_attr junk filling pattern
+
+Guarantee that junk filled pointers will fault, at least on pure 64-bit.
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/pthread_attr.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
+index de4cc9e8d..7e74b8a80 100644
+--- a/libc/bionic/pthread_attr.cpp
++++ b/libc/bionic/pthread_attr.cpp
+@@ -54,7 +54,7 @@ int pthread_attr_init(pthread_attr_t* attr) {
+
+ __BIONIC_WEAK_FOR_NATIVE_BRIDGE
+ int pthread_attr_destroy(pthread_attr_t* attr) {
+- memset(attr, 0x42, sizeof(pthread_attr_t));
++ memset(attr, 0xdf, sizeof(pthread_attr_t));
+ return 0;
+ }
+
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-14.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-14.patch
new file mode 100644
index 00000000..6c7645bb
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-14.patch
@@ -0,0 +1,82 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Renlord
+Date: Thu, 12 Sep 2019 14:51:51 +1000
+Subject: [PATCH] add guard page(s) between static_tls and stack
+
+---
+ libc/bionic/pthread_create.cpp | 29 ++++++++++++++++++++---------
+ 1 file changed, 20 insertions(+), 9 deletions(-)
+
+diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
+index 194db1821..88e57f973 100644
+--- a/libc/bionic/pthread_create.cpp
++++ b/libc/bionic/pthread_create.cpp
+@@ -212,9 +212,10 @@ int __init_thread(pthread_internal_t* thread) {
+ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size) {
+ const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
+
+- // Allocate in order: stack guard, stack, static TLS, guard page.
++ // Allocate in order: stack guard, stack, guard page, static TLS, guard page.
+ size_t mmap_size;
+ if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {};
++ if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, layout.size(), &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {};
+
+@@ -223,8 +224,8 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ mmap_size = __BIONIC_ALIGN(mmap_size, page_size());
+ if (mmap_size < unaligned_size) return {};
+
+- // Create a new private anonymous map. Make the entire mapping PROT_NONE, then carve out a
+- // read+write area in the middle.
++ // Create a new private anonymous map. Make the entire mapping PROT_NONE, then carve out
++ // read+write areas for the stack and static TLS
+ const int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
+ char* const space = static_cast(mmap(nullptr, mmap_size, PROT_NONE, flags, -1, 0));
+ if (space == MAP_FAILED) {
+@@ -233,7 +234,6 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ mmap_size);
+ return {};
+ }
+- const size_t writable_size = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE;
+ int prot = PROT_READ | PROT_WRITE;
+ const char* prot_str = "R+W";
+ #ifdef __aarch64__
+@@ -242,11 +242,22 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ prot_str = "R+W+MTE";
+ }
+ #endif
+- if (mprotect(space + stack_guard_size, writable_size, prot) != 0) {
++ if (mprotect(space + stack_guard_size, stack_size, prot) != 0) {
++ async_safe_format_log(
++ ANDROID_LOG_WARN, "libc",
++ "pthread_create failed: couldn't mprotect %s %zu-byte stack mapping region: %m", prot_str,
++ stack_size);
++ munmap(space, mmap_size);
++ return {};
++ }
++
++ char* const static_tls_space = space + stack_guard_size + stack_size + PTHREAD_GUARD_SIZE;
++
++ if (mprotect(static_tls_space, layout.size(), PROT_READ | PROT_WRITE) != 0) {
+ async_safe_format_log(
+ ANDROID_LOG_WARN, "libc",
+- "pthread_create failed: couldn't mprotect %s %zu-byte thread mapping region: %m", prot_str,
+- writable_size);
++ "pthread_create failed: couldn't mprotect R+W %zu-byte static TLS mapping region: %m",
++ layout.size());
+ munmap(space, mmap_size);
+ return {};
+ }
+@@ -256,9 +267,9 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ result.mmap_size = mmap_size;
+ result.mmap_base_unguarded = space + stack_guard_size;
+ result.mmap_size_unguarded = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE;
+- result.static_tls = space + mmap_size - PTHREAD_GUARD_SIZE - layout.size();
++ result.static_tls = static_tls_space;
+ result.stack_base = space;
+- result.stack_top = result.static_tls;
++ result.stack_top = space + stack_guard_size + stack_size;
+ return result;
+ }
+
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-15.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-15.patch
new file mode 100644
index 00000000..a3eb9a5f
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-15.patch
@@ -0,0 +1,63 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Fri, 11 Oct 2019 05:52:49 +0300
+Subject: [PATCH] move pthread_internal_t behind guard page
+
+---
+ libc/bionic/pthread_create.cpp | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
+index 88e57f973..f21e3a63f 100644
+--- a/libc/bionic/pthread_create.cpp
++++ b/libc/bionic/pthread_create.cpp
+@@ -212,10 +212,13 @@ int __init_thread(pthread_internal_t* thread) {
+ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size) {
+ const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
+
+- // Allocate in order: stack guard, stack, guard page, static TLS, guard page.
++ size_t thread_page_size = __BIONIC_ALIGN(sizeof(pthread_internal_t), PAGE_SIZE);
++
++ // Allocate in order: stack guard, stack, guard page, pthread_internal_t, static TLS, guard page.
+ size_t mmap_size;
+ if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {};
++ if (__builtin_add_overflow(mmap_size, thread_page_size, &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, layout.size(), &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {};
+
+@@ -251,13 +254,14 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ return {};
+ }
+
+- char* const static_tls_space = space + stack_guard_size + stack_size + PTHREAD_GUARD_SIZE;
++ char* const thread = space + stack_guard_size + stack_size + PTHREAD_GUARD_SIZE;
++ char* const static_tls_space = thread + thread_page_size;
+
+- if (mprotect(static_tls_space, layout.size(), PROT_READ | PROT_WRITE) != 0) {
++ if (mprotect(thread, thread_page_size + layout.size(), PROT_READ | PROT_WRITE) != 0) {
+ async_safe_format_log(
+ ANDROID_LOG_WARN, "libc",
+- "pthread_create failed: couldn't mprotect R+W %zu-byte static TLS mapping region: %m",
+- layout.size());
++ "pthread_create failed: couldn't mprotect R+W %zu-byte static TLS and pthread_internal mapping region: %m",
++ thread_page_size + layout.size());
+ munmap(space, mmap_size);
+ return {};
+ }
+@@ -299,13 +303,8 @@ static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** chi
+ stack_top = static_cast(attr->stack_base) + attr->stack_size;
+ }
+
+- // Carve out space from the stack for the thread's pthread_internal_t. This
+- // memory isn't counted in pthread_attr_getstacksize.
+-
+- // To safely access the pthread_internal_t and thread stack, we need to find a 16-byte aligned boundary.
+- stack_top = align_down(stack_top - sizeof(pthread_internal_t), 16);
+-
+- pthread_internal_t* thread = reinterpret_cast(stack_top);
++ pthread_internal_t* thread = reinterpret_cast(
++ mapping.static_tls - __BIONIC_ALIGN(sizeof(pthread_internal_t), PAGE_SIZE));
+ if (!stack_clean) {
+ // If thread was not allocated by mmap(), it may not have been cleared to zero.
+ // So assume the worst and zero it.
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-16.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-16.patch
new file mode 100644
index 00000000..4f495cca
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-16.patch
@@ -0,0 +1,97 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Renlord
+Date: Sun, 20 Oct 2019 00:17:11 +0300
+Subject: [PATCH] add secondary stack randomization
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/pthread_create.cpp | 30 ++++++++++++++++++++++++++----
+ libc/include/sys/cdefs.h | 1 +
+ 2 files changed, 27 insertions(+), 4 deletions(-)
+
+diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
+index f21e3a63f..035967d3c 100644
+--- a/libc/bionic/pthread_create.cpp
++++ b/libc/bionic/pthread_create.cpp
+@@ -29,6 +29,7 @@
+ #include
+
+ #include
++#include
+ #include
+ #include
+ #include
+@@ -212,12 +213,24 @@ int __init_thread(pthread_internal_t* thread) {
+ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size) {
+ const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
+
++ // round up if the given stack size is not in multiples of PAGE_SIZE
++ stack_size = __BIONIC_ALIGN(stack_size, PAGE_SIZE);
+ size_t thread_page_size = __BIONIC_ALIGN(sizeof(pthread_internal_t), PAGE_SIZE);
+
+- // Allocate in order: stack guard, stack, guard page, pthread_internal_t, static TLS, guard page.
++ // Place a randomly sized gap above the stack, up to 10% as large as the stack
++ // on 32-bit and 50% on 64-bit where virtual memory is plentiful.
++#if __LP64__
++ size_t max_gap_size = stack_size / 2;
++#else
++ size_t max_gap_size = stack_size / 10;
++#endif
++ // Make sure random stack top guard size are multiples of PAGE_SIZE.
++ size_t gap_size = __BIONIC_ALIGN(arc4random_uniform(max_gap_size), PAGE_SIZE);
++
++ // Allocate in order: stack guard, stack, (random) guard page(s), pthread_internal_t, static TLS, guard page.
+ size_t mmap_size;
+ if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {};
+- if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {};
++ if (__builtin_add_overflow(mmap_size, gap_size, &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, thread_page_size, &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, layout.size(), &mmap_size)) return {};
+ if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {};
+@@ -245,6 +258,9 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ prot_str = "R+W+MTE";
+ }
+ #endif
++ // Stack is at the lower end of mapped space, stack guard region is at the lower end of stack.
++ // Make the usable portion of the stack between the guard region and random gap readable and
++ // writable.
+ if (mprotect(space + stack_guard_size, stack_size, prot) != 0) {
+ async_safe_format_log(
+ ANDROID_LOG_WARN, "libc",
+@@ -253,8 +269,11 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ munmap(space, mmap_size);
+ return {};
+ }
++ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, space, stack_guard_size, "stack guard");
++ char* const stack_top_guard = space + stack_guard_size + stack_size;
++ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, stack_top_guard, gap_size, "stack top guard");
+
+- char* const thread = space + stack_guard_size + stack_size + PTHREAD_GUARD_SIZE;
++ char* const thread = space + stack_guard_size + stack_size + gap_size;
+ char* const static_tls_space = thread + thread_page_size;
+
+ if (mprotect(thread, thread_page_size + layout.size(), PROT_READ | PROT_WRITE) != 0) {
+@@ -273,7 +292,10 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si
+ result.mmap_size_unguarded = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE;
+ result.static_tls = static_tls_space;
+ result.stack_base = space;
+- result.stack_top = space + stack_guard_size + stack_size;
++ // Choose a random base within the first page of the stack. Waste no more
++ // than the space originally wasted by pthread_internal_t for compatibility.
++ result.stack_top = space + stack_guard_size + stack_size - arc4random_uniform(sizeof(pthread_internal_t));
++ result.stack_top = reinterpret_cast(__BIONIC_ALIGN_DOWN(reinterpret_cast(result.stack_top), 16));
+ return result;
+ }
+
+diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
+index a8fb6240a..dd95423c4 100644
+--- a/libc/include/sys/cdefs.h
++++ b/libc/include/sys/cdefs.h
+@@ -61,6 +61,7 @@
+ #endif
+
+ #define __BIONIC_ALIGN(__value, __alignment) (((__value) + (__alignment)-1) & ~((__alignment)-1))
++#define __BIONIC_ALIGN_DOWN(value, alignment) ((value) & ~((alignment) - 1))
+
+ /*
+ * The nullness constraints of this parameter or return value are
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-2.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-2.patch
new file mode 100644
index 00000000..5cb8b39d
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-2.patch
@@ -0,0 +1,76 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Sun, 8 Feb 2015 01:18:54 -0500
+Subject: [PATCH] replace brk and sbrk with stubs
+
+Pretend that there is never room to grow the heap in order to prevent
+usage of these unsafe legacy functions. There are likely no users of
+these in practice as it is inherently broken to use them outside of
+malloc.
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/brk.cpp | 48 ++++++++-------------------------------------
+ 1 file changed, 8 insertions(+), 40 deletions(-)
+
+diff --git a/libc/bionic/brk.cpp b/libc/bionic/brk.cpp
+index 566c33a7a..ef9305513 100644
+--- a/libc/bionic/brk.cpp
++++ b/libc/bionic/brk.cpp
+@@ -29,48 +29,16 @@
+ #include
+ #include
+
+-#if defined(__LP64__)
+-static void* __bionic_brk;
+-#else
+-void* __bionic_brk; // Accidentally exported by the NDK.
++#if !defined(__LP64__)
++void* __bionic_brk = reinterpret_cast(-1); // Accidentally exported by the NDK.
+ #endif
+
+-extern "C" void* __brk(void* __addr);
+-
+-int brk(void* end_data) {
+- __bionic_brk = __brk(end_data);
+- if (__bionic_brk < end_data) {
+- errno = ENOMEM;
+- return -1;
+- }
+- return 0;
++int brk(void*) {
++ errno = ENOMEM;
++ return -1;
+ }
+
+-void* sbrk(ptrdiff_t increment) {
+- // Initialize __bionic_brk if necessary.
+- if (__bionic_brk == nullptr) {
+- __bionic_brk = __brk(nullptr);
+- }
+-
+- // Don't ask the kernel if we already know the answer.
+- if (increment == 0) {
+- return __bionic_brk;
+- }
+-
+- // Avoid overflow.
+- uintptr_t old_brk = reinterpret_cast(__bionic_brk);
+- if ((increment > 0 && static_cast(increment) > (UINTPTR_MAX - old_brk)) ||
+- (increment < 0 && static_cast(-increment) > old_brk)) {
+- errno = ENOMEM;
+- return reinterpret_cast(-1);
+- }
+-
+- void* desired_brk = reinterpret_cast(old_brk + increment);
+- __bionic_brk = __brk(desired_brk);
+- if (__bionic_brk < desired_brk) {
+- errno = ENOMEM;
+- return reinterpret_cast(-1);
+- }
+-
+- return reinterpret_cast(old_brk);
++void* sbrk(ptrdiff_t) {
++ errno = ENOMEM;
++ return reinterpret_cast(-1);
+ }
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-3.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-3.patch
new file mode 100644
index 00000000..303c4566
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-3.patch
@@ -0,0 +1,57 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Mon, 4 Mar 2019 04:26:04 -0500
+Subject: [PATCH] use blocking getrandom and avoid urandom fallback
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/getentropy.cpp | 28 +++-------------------------
+ 1 file changed, 3 insertions(+), 25 deletions(-)
+
+diff --git a/libc/bionic/getentropy.cpp b/libc/bionic/getentropy.cpp
+index 9c93e713b..c9438ad2b 100644
+--- a/libc/bionic/getentropy.cpp
++++ b/libc/bionic/getentropy.cpp
+@@ -33,22 +33,6 @@
+
+ #include "private/ScopedFd.h"
+
+-static int getentropy_urandom(void* buffer, size_t buffer_size, int saved_errno) {
+- ScopedFd fd(TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_NOFOLLOW | O_CLOEXEC, 0)));
+- if (fd.get() == -1) return -1;
+-
+- size_t collected = 0;
+- while (collected < buffer_size) {
+- ssize_t count = TEMP_FAILURE_RETRY(read(fd.get(), static_cast(buffer) + collected,
+- buffer_size - collected));
+- if (count == -1) return -1;
+- collected += count;
+- }
+-
+- errno = saved_errno;
+- return 0;
+-}
+-
+ int getentropy(void* buffer, size_t buffer_size) {
+ if (buffer_size > 256) {
+ errno = EIO;
+@@ -59,16 +43,10 @@ int getentropy(void* buffer, size_t buffer_size) {
+
+ size_t collected = 0;
+ while (collected < buffer_size) {
+- long count = TEMP_FAILURE_RETRY(getrandom(static_cast(buffer) + collected,
+- buffer_size - collected, GRND_NONBLOCK));
++ long count = TEMP_FAILURE_RETRY(
++ getrandom(static_cast(buffer) + collected, buffer_size - collected, 0));
+ if (count == -1) {
+- // EAGAIN: there isn't enough entropy right now.
+- // ENOSYS/EINVAL: getrandom(2) or GRND_NONBLOCK isn't supported.
+- // EFAULT: `buffer` is invalid.
+- // Try /dev/urandom regardless because it can't hurt,
+- // and we don't need to optimize the EFAULT case.
+- // See http://b/33059407 and http://b/67015565.
+- return getentropy_urandom(buffer, buffer_size, saved_errno);
++ return -1;
+ }
+ collected += count;
+ }
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-4.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-4.patch
new file mode 100644
index 00000000..f3959e32
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-4.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Mon, 19 Sep 2016 07:57:43 -0400
+Subject: [PATCH] fix undefined out-of-bounds accesses in sched.h
+
+Signed-off-by: anupritaisno1
+---
+ libc/include/sched.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/libc/include/sched.h b/libc/include/sched.h
+index b1f18421b..20e25662f 100644
+--- a/libc/include/sched.h
++++ b/libc/include/sched.h
+@@ -215,7 +215,10 @@ int sched_getcpu(void);
+ * statically-sized CPU set. See `CPU_ALLOC` for dynamically-sized CPU sets.
+ */
+ typedef struct {
+- __CPU_BITTYPE __bits[ CPU_SETSIZE / __CPU_BITS ];
++ union {
++ __CPU_BITTYPE __bits_minimum[ CPU_SETSIZE / __CPU_BITS ];
++ __CPU_BITTYPE __bits[0];
++ };
+ } cpu_set_t;
+
+ /**
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-6.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-6.patch
new file mode 100644
index 00000000..99b01441
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-6.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Sat, 16 Jul 2016 23:55:16 -0400
+Subject: [PATCH] replace VLA formatting with dprintf-like function
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/bionic_systrace.cpp | 10 +---------
+ 1 file changed, 1 insertion(+), 9 deletions(-)
+
+diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
+index 227cb84c3..25ae76a89 100644
+--- a/libc/bionic/bionic_systrace.cpp
++++ b/libc/bionic/bionic_systrace.cpp
+@@ -29,8 +29,6 @@
+ #include
+ #include // For ATRACE_TAG_BIONIC.
+
+-#define WRITE_OFFSET 32
+-
+ static Lock g_lock;
+ static CachedProperty g_debug_atrace_tags_enableflags("debug.atrace.tags.enableflags");
+ static uint64_t g_tags;
+@@ -67,15 +65,9 @@ static void trace_begin_internal(const char* message) {
+ return;
+ }
+
+- // If bionic tracing has been enabled, then write the message to the
+- // kernel trace_marker.
+- int length = strlen(message);
+- char buf[length + WRITE_OFFSET];
+- size_t len = async_safe_format_buffer(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message);
+-
+ // Tracing may stop just after checking property and before writing the message.
+ // So the write is acceptable to fail. See b/20666100.
+- TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
++ async_safe_format_fd(trace_marker_fd, "B|%d|%s", getpid(), message);
+ }
+
+ void bionic_trace_begin(const char* message) {
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-7.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-7.patch
new file mode 100644
index 00000000..498fcdb8
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-7.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Fri, 17 Jul 2015 21:32:05 -0400
+Subject: [PATCH] increase default pthread stack to 8MiB on 64-bit
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/pthread_internal.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
+index 3b9e6a481..c4d124e8e 100644
+--- a/libc/bionic/pthread_internal.h
++++ b/libc/bionic/pthread_internal.h
+@@ -256,7 +256,11 @@ __LIBC_HIDDEN__ void pthread_key_clean_all(void);
+ // stack overflows, we subtracted the same amount we were using there
+ // from the default thread stack size. This should keep memory usage
+ // roughly constant.
++#ifdef __LP64__
++#define PTHREAD_STACK_SIZE_DEFAULT ((8 * 1024 * 1024) - SIGNAL_STACK_SIZE_WITHOUT_GUARD)
++#else
+ #define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGNAL_STACK_SIZE_WITHOUT_GUARD)
++#endif
+
+ // Leave room for a guard page in the internally created signal stacks.
+ #define SIGNAL_STACK_SIZE (SIGNAL_STACK_SIZE_WITHOUT_GUARD + PTHREAD_GUARD_SIZE)
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-8.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-8.patch
new file mode 100644
index 00000000..4de1f01e
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-8.patch
@@ -0,0 +1,59 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Sat, 1 Oct 2016 05:11:44 -0400
+Subject: [PATCH] make __stack_chk_guard read-only at runtime
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/__libc_init_main_thread.cpp | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
+index 1b539f274..a6ddc64d5 100644
+--- a/libc/bionic/__libc_init_main_thread.cpp
++++ b/libc/bionic/__libc_init_main_thread.cpp
+@@ -28,6 +28,9 @@
+
+ #include "libc_init_common.h"
+
++#include
++#include
++
+ #include
+
+ #include "private/KernelArgumentBlock.h"
+@@ -35,14 +38,14 @@
+ #include "private/bionic_defs.h"
+ #include "private/bionic_elf_tls.h"
+ #include "private/bionic_globals.h"
+-#include "private/bionic_ssp.h"
+ #include "pthread_internal.h"
+
+ extern "C" pid_t __getpid();
+ extern "C" int __set_tid_address(int* tid_address);
+
+ // Declared in "private/bionic_ssp.h".
+-uintptr_t __stack_chk_guard = 0;
++__attribute__((aligned(PAGE_SIZE)))
++uintptr_t __stack_chk_guard[PAGE_SIZE / sizeof(uintptr_t)] = {0};
+
+ static pthread_internal_t main_thread;
+
+@@ -107,10 +110,16 @@ void __init_tcb_dtv(bionic_tcb* tcb) {
+ // Note in particular that it is not possible to return from any existing
+ // stack frame with stack protector enabled after this function is called.
+ extern "C" void android_reset_stack_guards() {
++ if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ|PROT_WRITE) == -1) {
++ async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno));
++ }
+ // The TLS stack guard is set from the global, so ensure that we've initialized the global
+ // before we initialize the TLS. Dynamic executables will initialize their copy of the global
+ // stack protector from the one in the main thread's TLS.
+- __libc_safe_arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard));
++ __libc_safe_arc4random_buf(&__stack_chk_guard[0], sizeof(__stack_chk_guard[0]));
++ if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ) == -1) {
++ async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno));
++ }
+ __init_tcb_stack_guard(__get_bionic_tcb());
+ }
+
diff --git a/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-9.patch b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-9.patch
new file mode 100644
index 00000000..6bc20f8a
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0002-Graphene_Bionic_Hardening-9.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Sun, 12 Mar 2017 17:49:13 -0400
+Subject: [PATCH] on 64-bit, zero the leading stack canary byte
+
+This reduces entropy of the canary from 64-bit to 56-bit in exchange for
+mitigating non-terminated C string overflows.
+
+Signed-off-by: anupritaisno1
+---
+ libc/bionic/__libc_init_main_thread.cpp | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
+index a6ddc64d5..c03a8b79d 100644
+--- a/libc/bionic/__libc_init_main_thread.cpp
++++ b/libc/bionic/__libc_init_main_thread.cpp
+@@ -49,6 +49,12 @@ uintptr_t __stack_chk_guard[PAGE_SIZE / sizeof(uintptr_t)] = {0};
+
+ static pthread_internal_t main_thread;
+
++#if __LP64__
++static const uintptr_t canary_mask = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ?
++ 0xffffffffffffff00UL :
++ 0x00ffffffffffffffUL;
++#endif
++
+ // Setup for the main thread. For dynamic executables, this is called by the
+ // linker _before_ libc is mapped in memory. This means that all writes to
+ // globals from this function will apply to linker-private copies and will not
+@@ -117,6 +123,10 @@ extern "C" void android_reset_stack_guards() {
+ // before we initialize the TLS. Dynamic executables will initialize their copy of the global
+ // stack protector from the one in the main thread's TLS.
+ __libc_safe_arc4random_buf(&__stack_chk_guard[0], sizeof(__stack_chk_guard[0]));
++#if __LP64__
++ // Sacrifice 8 bits of entropy on 64-bit to mitigate non-terminated C string overflows
++ __stack_chk_guard[0] &= canary_mask;
++#endif
+ if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ) == -1) {
+ async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno));
+ }
diff --git a/Patches/LineageOS-21.0/android_bionic/0003-Hosts_Cache.patch b/Patches/LineageOS-21.0/android_bionic/0003-Hosts_Cache.patch
new file mode 100644
index 00000000..85a4602d
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0003-Hosts_Cache.patch
@@ -0,0 +1,639 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Tom Marshall
+Date: Fri, 17 Jun 2016 16:38:12 -0700
+Subject: [PATCH] bionic: Sort and cache hosts file data for fast lookup
+
+The hosts file is normally searched linearly. This is very slow when
+the file is large. To mitigate this, read the hosts file and sort the
+entries in an in-memory cache. When an address is requested via
+gethostbyname or getaddrinfo, binary search the cache.
+
+In case where the cache is not available, return a suitable error code
+and fall back to the existing lookup code.
+
+This has been written to behave as much like the existing lookup code as
+possible. But note bionic and glibc differ in behavior for some corner
+cases. Choose the most standard compliant behavior for these where
+possible. Otherwise choose the behavior that seems most reasonable.
+
+RM-290
+
+Change-Id: I3b322883cbc48b0d76a0ce9d149b59faaac1dc58
+(cherry picked from commit ed4c3a6bd449a4ed70645071a440ae146f194116)
+---
+ libc/dns/net/getaddrinfo.c | 10 +
+ libc/dns/net/hosts_cache.c | 520 +++++++++++++++++++++++++++++++++++++
+ libc/dns/net/hosts_cache.h | 23 ++
+ libc/dns/net/sethostent.c | 7 +
+ 4 files changed, 560 insertions(+)
+ create mode 100644 libc/dns/net/hosts_cache.c
+ create mode 100644 libc/dns/net/hosts_cache.h
+
+diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
+index d0c11d2b0..cc94b21e2 100644
+--- a/libc/dns/net/getaddrinfo.c
++++ b/libc/dns/net/getaddrinfo.c
+@@ -109,6 +109,8 @@
+ #include "nsswitch.h"
+ #include "private/bionic_defs.h"
+
++#include "hosts_cache.h"
++
+ typedef union sockaddr_union {
+ struct sockaddr generic;
+ struct sockaddr_in in;
+@@ -2125,6 +2127,14 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, struct addrinfo *);
+
++ memset(&sentinel, 0, sizeof(sentinel));
++ cur = &sentinel;
++ int gai_error = hc_getaddrinfo(name, NULL, pai, &cur);
++ if (gai_error != EAI_SYSTEM) {
++ *((struct addrinfo **)rv) = sentinel.ai_next;
++ return (gai_error == 0 ? NS_SUCCESS : NS_NOTFOUND);
++ }
++
+ // fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name);
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+diff --git a/libc/dns/net/hosts_cache.c b/libc/dns/net/hosts_cache.c
+new file mode 100644
+index 000000000..52d29e032
+--- /dev/null
++++ b/libc/dns/net/hosts_cache.c
+@@ -0,0 +1,520 @@
++/*
++ * Copyright (C) 2016 The CyanogenMod Project
++ *
++ * 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.
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++#include
++#include
++
++#include "hostent.h"
++#include "resolv_private.h"
++
++#define MAX_ADDRLEN (INET6_ADDRSTRLEN - (1 + 5))
++#define MAX_HOSTLEN MAXHOSTNAMELEN
++
++#define ESTIMATED_LINELEN 32
++#define HCFILE_ALLOC_SIZE 256
++
++/*
++ * Host cache entry for hcfile.c_data.
++ * Offsets are into hcfile.h_data.
++ * Strings are *not* terminated by NULL, but by whitespace (isspace) or '#'.
++ * Use hstr* functions with these.
++ */
++struct hcent
++{
++ uint32_t addr;
++ uint32_t name;
++};
++
++/*
++ * Overall host cache file state.
++ */
++struct hcfile
++{
++ int h_fd;
++ struct stat h_st;
++ char *h_data;
++
++ uint32_t c_alloc;
++ uint32_t c_len;
++ struct hcent *c_data;
++};
++static struct hcfile hcfile;
++static pthread_mutex_t hclock = PTHREAD_MUTEX_INITIALIZER;
++
++static size_t hstrlen(const char *s)
++{
++ const char *p = s;
++ while (*p && *p != '#' && !isspace(*p))
++ ++p;
++ return p - s;
++}
++
++static int hstrcmp(const char *a, const char *b)
++{
++ size_t alen = hstrlen(a);
++ size_t blen = hstrlen(b);
++ int res = strncmp(a, b, MIN(alen, blen));
++ if (res == 0)
++ res = alen - blen;
++ return res;
++}
++
++static char *hstrcpy(char *dest, const char *src)
++{
++ size_t len = hstrlen(src);
++ memcpy(dest, src, len);
++ dest[len] = '\0';
++ return dest;
++}
++
++static char *hstrdup(const char *s)
++{
++ size_t len = hstrlen(s);
++ char *dest = (char *)malloc(len + 1);
++ if (!dest)
++ return NULL;
++ memcpy(dest, s, len);
++ dest[len] = '\0';
++ return dest;
++}
++
++static int cmp_hcent_name(const void *a, const void *b)
++{
++ struct hcent *ea = (struct hcent *)a;
++ const char *na = hcfile.h_data + ea->name;
++ struct hcent *eb = (struct hcent *)b;
++ const char *nb = hcfile.h_data + eb->name;
++
++ return hstrcmp(na, nb);
++}
++
++static struct hcent *_hcfindname(const char *name)
++{
++ size_t first, last, mid;
++ struct hcent *cur = NULL;
++ int cmp;
++
++ if (hcfile.c_len == 0)
++ return NULL;
++
++ first = 0;
++ last = hcfile.c_len - 1;
++ mid = (first + last) / 2;
++ while (first <= last) {
++ cur = hcfile.c_data + mid;
++ cmp = hstrcmp(hcfile.h_data + cur->name, name);
++ if (cmp == 0)
++ goto found;
++ if (cmp < 0)
++ first = mid + 1;
++ else {
++ if (mid > 0)
++ last = mid - 1;
++ else
++ return NULL;
++ }
++ mid = (first + last) / 2;
++ }
++ return NULL;
++
++found:
++ while (cur > hcfile.c_data) {
++ struct hcent *prev = cur - 1;
++ cmp = cmp_hcent_name(cur, prev);
++ if (cmp)
++ break;
++ cur = prev;
++ }
++
++ return cur;
++}
++
++/*
++ * Find next name on line, if any.
++ *
++ * Assumes that line is terminated by LF.
++ */
++static const char *_hcnextname(const char *name)
++{
++ while (!isspace(*name)) {
++ if (*name == '#')
++ return NULL;
++ ++name;
++ }
++ while (isspace(*name)) {
++ if (*name == '\n')
++ return NULL;
++ ++name;
++ }
++ if (*name == '#')
++ return NULL;
++ return name;
++}
++
++static int _hcfilemmap(void)
++{
++ struct stat st;
++ int h_fd;
++ char *h_addr;
++ const char *p, *pend;
++ uint32_t c_alloc;
++
++ h_fd = open(_PATH_HOSTS, O_RDONLY);
++ if (h_fd < 0)
++ return -1;
++ if (flock(h_fd, LOCK_EX) != 0) {
++ close(h_fd);
++ return -1;
++ }
++
++ if (hcfile.h_data) {
++ memset(&st, 0, sizeof(st));
++ if (fstat(h_fd, &st) == 0) {
++ if (st.st_size == hcfile.h_st.st_size &&
++ st.st_mtime == hcfile.h_st.st_mtime) {
++ flock(h_fd, LOCK_UN);
++ close(h_fd);
++ return 0;
++ }
++ }
++ free(hcfile.c_data);
++ munmap(hcfile.h_data, hcfile.h_st.st_size);
++ close(hcfile.h_fd);
++ memset(&hcfile, 0, sizeof(struct hcfile));
++ }
++
++ if (fstat(h_fd, &st) != 0) {
++ flock(h_fd, LOCK_UN);
++ close(h_fd);
++ return -1;
++ }
++ h_addr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, h_fd, 0);
++ if (h_addr == MAP_FAILED) {
++ flock(h_fd, LOCK_UN);
++ close(h_fd);
++ return -1;
++ }
++
++ hcfile.h_fd = h_fd;
++ hcfile.h_st = st;
++ hcfile.h_data = h_addr;
++
++ c_alloc = 0;
++ /*
++ * Do an initial allocation if the file is "large". Estimate
++ * 32 bytes per line and define "large" as more than half of
++ * the alloc growth size (256 entries).
++ */
++ if (st.st_size >= ESTIMATED_LINELEN * HCFILE_ALLOC_SIZE / 2) {
++ c_alloc = st.st_size / ESTIMATED_LINELEN;
++ hcfile.c_data = malloc(c_alloc * sizeof(struct hcent));
++ if (!hcfile.c_data) {
++ goto oom;
++ }
++ }
++
++ p = (const char *)h_addr;
++ pend = p + st.st_size;
++ while (p < pend) {
++ const char *eol, *addr, *name;
++ size_t len;
++ addr = p;
++ eol = memchr(p, '\n', pend - p);
++ if (!eol)
++ break;
++ p = eol + 1;
++ if (*addr == '#' || *addr == '\n')
++ continue;
++ len = hstrlen(addr);
++ if (len > MAX_ADDRLEN)
++ continue;
++ name = addr + len;
++ while (name < eol && isspace(*name))
++ ++name;
++ while (name < eol) {
++ len = hstrlen(name);
++ if (len == 0)
++ break;
++ if (len < MAX_HOSTLEN) {
++ struct hcent *ent;
++ if (c_alloc <= hcfile.c_len) {
++ struct hcent *c_data;
++ c_alloc += HCFILE_ALLOC_SIZE;
++ c_data = realloc(hcfile.c_data, c_alloc * sizeof(struct hcent));
++ if (!c_data) {
++ goto oom;
++ }
++ hcfile.c_data = c_data;
++ }
++ ent = hcfile.c_data + hcfile.c_len;
++ ent->addr = addr - h_addr;
++ ent->name = name - h_addr;
++ ++hcfile.c_len;
++ }
++ name += len;
++ while (name < eol && isspace(*name))
++ ++name;
++ }
++ }
++
++ qsort(hcfile.c_data, hcfile.c_len,
++ sizeof(struct hcent), cmp_hcent_name);
++
++ flock(h_fd, LOCK_UN);
++
++ return 0;
++
++oom:
++ free(hcfile.c_data);
++ munmap(hcfile.h_data, hcfile.h_st.st_size);
++ flock(hcfile.h_fd, LOCK_UN);
++ close(hcfile.h_fd);
++ memset(&hcfile, 0, sizeof(struct hcfile));
++ return -1;
++}
++
++/*
++ * Caching version of getaddrinfo.
++ *
++ * If we find the requested host name in the cache, use getaddrinfo to
++ * populate the result for each address we find.
++ *
++ * Note glibc and bionic differ in the handling of ai_canonname. POSIX
++ * says that ai_canonname is only populated in the first result entry.
++ * glibc does this. bionic populates ai_canonname in all result entries.
++ * We choose the POSIX/glibc way here.
++ */
++int hc_getaddrinfo(const char *host, const char *service,
++ const struct addrinfo *hints,
++ struct addrinfo **result)
++{
++ int ret = 0;
++ struct hcent *ent, *cur;
++ struct addrinfo *ai;
++ struct addrinfo rhints;
++ struct addrinfo *last;
++ int canonname = 0;
++ int cmp;
++
++ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
++ return EAI_SYSTEM;
++
++ /* Avoid needless work and recursion */
++ if (hints && (hints->ai_flags & AI_NUMERICHOST))
++ return EAI_SYSTEM;
++ if (!host)
++ return EAI_SYSTEM;
++
++ pthread_mutex_lock(&hclock);
++
++ if (_hcfilemmap() != 0) {
++ ret = EAI_SYSTEM;
++ goto out;
++ }
++ ent = _hcfindname(host);
++ if (!ent) {
++ ret = EAI_NONAME;
++ goto out;
++ }
++
++ if (hints) {
++ canonname = (hints->ai_flags & AI_CANONNAME);
++ memcpy(&rhints, hints, sizeof(rhints));
++ rhints.ai_flags &= ~AI_CANONNAME;
++ }
++ else {
++ memset(&rhints, 0, sizeof(rhints));
++ }
++ rhints.ai_flags |= AI_NUMERICHOST;
++
++ last = NULL;
++ cur = ent;
++ do {
++ char addrstr[MAX_ADDRLEN];
++ struct addrinfo *res;
++
++ hstrcpy(addrstr, hcfile.h_data + cur->addr);
++
++ if (getaddrinfo(addrstr, service, &rhints, &res) == 0) {
++ if (!last)
++ (*result)->ai_next = res;
++ else
++ last->ai_next = res;
++ last = res;
++ while (last->ai_next)
++ last = last->ai_next;
++ }
++
++ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
++ break;
++ cmp = cmp_hcent_name(cur, cur + 1);
++ cur = cur + 1;
++ }
++ while (!cmp);
++
++ if (last == NULL) {
++ /* This check is equivalent to (*result)->ai_next == NULL */
++ ret = EAI_NODATA;
++ goto out;
++ }
++
++ if (canonname) {
++ ai = (*result)->ai_next;
++ free(ai->ai_canonname);
++ ai->ai_canonname = hstrdup(hcfile.h_data + ent->name);
++ }
++
++out:
++ pthread_mutex_unlock(&hclock);
++ return ret;
++}
++
++/*
++ * Caching version of gethtbyname.
++ *
++ * Note glibc and bionic differ in the handling of aliases. glibc returns
++ * all aliases for all entries, regardless of whether they match h_addrtype.
++ * bionic returns only the aliases for the first hosts entry. We return all
++ * aliases for all IPv4 entries.
++ *
++ * Additionally, if an alias is IPv6 and the primary name for an alias also
++ * has an IPv4 entry, glibc will return the IPv4 address(es), but bionic
++ * will not. Neither do we.
++ */
++int hc_gethtbyname(const char *host, int af, struct getnamaddr *info)
++{
++ int ret = NETDB_SUCCESS;
++ struct hcent *ent, *cur;
++ int cmp;
++ size_t addrlen;
++ unsigned int naliases = 0;
++ char *aliases[MAXALIASES];
++ unsigned int naddrs = 0;
++ char *addr_ptrs[MAXADDRS];
++ unsigned int n;
++
++ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
++ return NETDB_INTERNAL;
++
++ switch (af) {
++ case AF_INET: addrlen = NS_INADDRSZ; break;
++ case AF_INET6: addrlen = NS_IN6ADDRSZ; break;
++ default:
++ return NETDB_INTERNAL;
++ }
++
++ pthread_mutex_lock(&hclock);
++
++ if (_hcfilemmap() != 0) {
++ ret = NETDB_INTERNAL;
++ goto out;
++ }
++
++ ent = _hcfindname(host);
++ if (!ent) {
++ ret = HOST_NOT_FOUND;
++ goto out;
++ }
++
++ cur = ent;
++ do {
++ char addr[16];
++ char addrstr[MAX_ADDRLEN];
++ char namestr[MAX_HOSTLEN];
++ const char *name;
++
++ hstrcpy(addrstr, hcfile.h_data + cur->addr);
++ if (inet_pton(af, addrstr, &addr) == 1) {
++ char *aligned;
++ /* First match is considered the official hostname */
++ if (naddrs == 0) {
++ hstrcpy(namestr, hcfile.h_data + cur->name);
++ HENT_SCOPY(info->hp->h_name, namestr, info->buf, info->buflen);
++ }
++ for (name = hcfile.h_data + cur->name; name; name = _hcnextname(name)) {
++ if (!hstrcmp(name, host))
++ continue;
++ hstrcpy(namestr, name);
++ HENT_SCOPY(aliases[naliases], namestr, info->buf, info->buflen);
++ ++naliases;
++ if (naliases >= MAXALIASES)
++ goto nospc;
++ }
++ aligned = (char *)ALIGN(info->buf);
++ if (info->buf != aligned) {
++ if ((ptrdiff_t)info->buflen < (aligned - info->buf))
++ goto nospc;
++ info->buflen -= (aligned - info->buf);
++ info->buf = aligned;
++ }
++ HENT_COPY(addr_ptrs[naddrs], addr, addrlen, info->buf, info->buflen);
++ ++naddrs;
++ if (naddrs >= MAXADDRS)
++ goto nospc;
++ }
++
++ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
++ break;
++ cmp = cmp_hcent_name(cur, cur + 1);
++ cur = cur + 1;
++ }
++ while (!cmp);
++
++ if (naddrs == 0) {
++ ret = HOST_NOT_FOUND;
++ goto out;
++ }
++
++ addr_ptrs[naddrs++] = NULL;
++ aliases[naliases++] = NULL;
++
++ /* hp->h_name already populated */
++ HENT_ARRAY(info->hp->h_aliases, naliases, info->buf, info->buflen);
++ for (n = 0; n < naliases; ++n) {
++ info->hp->h_aliases[n] = aliases[n];
++ }
++ info->hp->h_addrtype = af;
++ info->hp->h_length = addrlen;
++ HENT_ARRAY(info->hp->h_addr_list, naddrs, info->buf, info->buflen);
++ for (n = 0; n < naddrs; ++n) {
++ info->hp->h_addr_list[n] = addr_ptrs[n];
++ }
++
++out:
++ pthread_mutex_unlock(&hclock);
++ *info->he = ret;
++ return ret;
++
++nospc:
++ ret = NETDB_INTERNAL;
++ goto out;
++}
+diff --git a/libc/dns/net/hosts_cache.h b/libc/dns/net/hosts_cache.h
+new file mode 100644
+index 000000000..fa5488f51
+--- /dev/null
++++ b/libc/dns/net/hosts_cache.h
+@@ -0,0 +1,23 @@
++/*
++ * Copyright (C) 2016 The CyanogenMod Project
++ *
++ * 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.
++ */
++
++struct getnamaddr;
++
++int hc_getaddrinfo(const char *host, const char *service,
++ const struct addrinfo *hints,
++ struct addrinfo **result);
++
++int hc_gethtbyname(const char *host, int af, struct getnamaddr *info);
+diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
+index 5c4bdb5ab..5e4e174fa 100644
+--- a/libc/dns/net/sethostent.c
++++ b/libc/dns/net/sethostent.c
+@@ -55,6 +55,8 @@ __RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $");
+ #include "hostent.h"
+ #include "resolv_private.h"
+
++#include "hosts_cache.h"
++
+ #ifndef _REENTRANT
+ void res_close(void);
+ #endif
+@@ -109,6 +111,11 @@ _hf_gethtbyname(void *rv, void *cb_data, va_list ap)
+ /* NOSTRICT skip string len */(void)va_arg(ap, int);
+ af = va_arg(ap, int);
+
++ int rc = hc_gethtbyname(name, af, info);
++ if (rc != NETDB_INTERNAL) {
++ return (rc == NETDB_SUCCESS ? NS_SUCCESS : NS_NOTFOUND);
++ }
++
+ #if 0
+ {
+ res_state res = __res_get_state();
diff --git a/Patches/LineageOS-21.0/android_bionic/0003-Hosts_Wildcards.patch b/Patches/LineageOS-21.0/android_bionic/0003-Hosts_Wildcards.patch
new file mode 100644
index 00000000..abadbc86
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0003-Hosts_Wildcards.patch
@@ -0,0 +1,69 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Tom Marshall
+Date: Thu, 16 Jan 2020 13:07:04 -0800
+Subject: [PATCH] bionic: Support wildcards in cached hosts file
+
+If an exact name is not found in the hosts file and the host name
+contains at least one dot, search for entries of the form "*.domain",
+where domain is the portion of the host name after the first dot. If
+that is not found, repeat using the domain.
+
+Example: a.b.c.example.com would search for the following in turn:
+ a.b.c.example.com
+ *.b.c.example.com
+ *.c.example.com
+ *.example.com
+ *.com
+
+Change-Id: I4b0bb81699151d5b371850daebf785e35ec9b180
+---
+ libc/dns/net/hosts_cache.c | 29 ++++++++++++++++++++++++++++-
+ 1 file changed, 28 insertions(+), 1 deletion(-)
+
+diff --git a/libc/dns/net/hosts_cache.c b/libc/dns/net/hosts_cache.c
+index 52d29e032..fc6370d0c 100644
+--- a/libc/dns/net/hosts_cache.c
++++ b/libc/dns/net/hosts_cache.c
+@@ -117,7 +117,7 @@ static int cmp_hcent_name(const void *a, const void *b)
+ return hstrcmp(na, nb);
+ }
+
+-static struct hcent *_hcfindname(const char *name)
++static struct hcent *_hcfindname_exact(const char *name)
+ {
+ size_t first, last, mid;
+ struct hcent *cur = NULL;
+@@ -158,6 +158,33 @@ found:
+ return cur;
+ }
+
++static struct hcent *_hcfindname(const char *name)
++{
++ struct hcent *ent;
++ char namebuf[MAX_HOSTLEN];
++ char *p;
++ char *dot;
++
++ ent = _hcfindname_exact(name);
++ if (!ent && strlen(name) < sizeof(namebuf)) {
++ strcpy(namebuf, name);
++ p = namebuf;
++ do {
++ dot = strchr(p, '.');
++ if (!dot)
++ break;
++ if (dot > p) {
++ *(dot - 1) = '*';
++ ent = _hcfindname_exact(dot - 1);
++ }
++ p = dot + 1;
++ }
++ while (!ent);
++ }
++
++ return ent;
++}
++
+ /*
+ * Find next name on line, if any.
+ *
diff --git a/Patches/LineageOS-21.0/android_bionic/0004-hosts_toggle.patch b/Patches/LineageOS-21.0/android_bionic/0004-hosts_toggle.patch
new file mode 100644
index 00000000..3d8c3c90
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bionic/0004-hosts_toggle.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Tad
+Date: Wed, 20 Apr 2022 00:40:52 -0400
+Subject: [PATCH] Add a toggle to disable /etc/hosts lookup
+
+Signed-off-by: Tad
+Change-Id: I92679c57e73228dc194e61a86ea1a18b2ac90e04
+---
+ libc/dns/net/getaddrinfo.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
+index cc94b21e2..12294da04 100644
+--- a/libc/dns/net/getaddrinfo.c
++++ b/libc/dns/net/getaddrinfo.c
+@@ -83,6 +83,7 @@
+ #include
+ #include
+ #include
++#include
+ #include
+ #include
+ #include
+@@ -2127,6 +2128,11 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, struct addrinfo *);
+
++ char value[PROP_VALUE_MAX] = { 0 };
++ if (__system_property_get("persist.security.hosts_disable", value) != 0)
++ if (atoi(value) != 0 && strcmp(name, "localhost") != 0 && strcmp(name, "ip6-localhost") != 0)
++ return NS_NOTFOUND;
++
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+ int gai_error = hc_getaddrinfo(name, NULL, pai, &cur);
diff --git a/Patches/LineageOS-21.0/android_bootable_recovery/0001-No_SerialNum_Restrictions.patch b/Patches/LineageOS-21.0/android_bootable_recovery/0001-No_SerialNum_Restrictions.patch
new file mode 100644
index 00000000..a5413755
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_bootable_recovery/0001-No_SerialNum_Restrictions.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 19 Aug 2020 09:31:04 -0400
+Subject: [PATCH] reject updates with serialno constraints
+
+---
+ install/install.cpp | 13 ++-----------
+ 1 file changed, 2 insertions(+), 11 deletions(-)
+
+diff --git a/install/install.cpp b/install/install.cpp
+index 9906a41f..e85a95c5 100644
+--- a/install/install.cpp
++++ b/install/install.cpp
+@@ -234,17 +234,8 @@ bool CheckPackageMetadata(const std::map& metadata, Ot
+
+ 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;
+- }
++ LOG(ERROR) << "Serial number constraint not permitted: " << pkg_serial_no;
++ return INSTALL_ERROR;
+ } else if (ota_type == OtaType::BRICK) {
+ const auto device_build_tag = android::base::GetProperty("ro.build.tags", "");
+ if (device_build_tag.empty()) {
diff --git a/Patches/LineageOS-21.0/android_build/0001-Enable_fwrapv.patch b/Patches/LineageOS-21.0/android_build/0001-Enable_fwrapv.patch
new file mode 100644
index 00000000..35fcfd39
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_build/0001-Enable_fwrapv.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 13 Sep 2016 22:05:56 -0400
+Subject: [PATCH] use -fwrapv when signed overflow checking is off
+
+Signed-off-by: anupritaisno1
+---
+ core/config_sanitizers.mk | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
+index 3507961833..01cb295bfe 100644
+--- a/core/config_sanitizers.mk
++++ b/core/config_sanitizers.mk
+@@ -572,3 +572,9 @@ ifneq ($(findstring fsanitize,$(my_cflags)),)
+ endif
+ endif
+ endif
++
++ifeq ($(filter signed-integer-overflow integer undefined,$(my_sanitize)),)
++ ifeq ($(filter -ftrapv,$(my_cflags)),)
++ my_cflags += -fwrapv
++ endif
++endif
diff --git a/Patches/LineageOS-21.0/android_build/0003-Exec_Based_Spawning.patch b/Patches/LineageOS-21.0/android_build/0003-Exec_Based_Spawning.patch
new file mode 100644
index 00000000..c1a18ee7
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_build/0003-Exec_Based_Spawning.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Thu, 17 Sep 2020 10:53:00 -0400
+Subject: [PATCH] disable enforce RRO for mainline devices
+
+This is currently incompatible with exec-based spawning. This also
+impacts the wrapper spawning model for the stock OS which is available
+by default, making it an upstream bug rather than a missing feature for
+exec-based spawning in GrapheneOS.
+
+Signed-off-by: anupritaisno1
+---
+ target/product/generic_system.mk | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/target/product/generic_system.mk b/target/product/generic_system.mk
+index 08a7cdf83e..8ed85ab6fa 100644
+--- a/target/product/generic_system.mk
++++ b/target/product/generic_system.mk
+@@ -112,7 +112,7 @@ PRODUCT_COPY_FILES += \
+ # Enable dynamic partition size
+ PRODUCT_USE_DYNAMIC_PARTITION_SIZE := true
+
+-PRODUCT_ENFORCE_RRO_TARGETS := *
++#PRODUCT_ENFORCE_RRO_TARGETS := *
+
+ PRODUCT_NAME := generic_system
+ PRODUCT_BRAND := generic
diff --git a/Patches/LineageOS-21.0/android_build/0004-Selective_APEX.patch b/Patches/LineageOS-21.0/android_build/0004-Selective_APEX.patch
new file mode 100644
index 00000000..315377ce
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_build/0004-Selective_APEX.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: flawedworld
+Date: Mon, 7 Mar 2022 01:38:23 +0000
+Subject: [PATCH] only enable APEX on 6th/7th gen Pixel devices
+
+Change-Id: Icffb72d8c3ed0e33e76538bb3427377c33c55ff9
+[tad@spotco.us]: adjusted for Lineage
+---
+ target/product/generic_system.mk | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/target/product/generic_system.mk b/target/product/generic_system.mk
+index 8ed85ab6fa..7b9ed53281 100644
+--- a/target/product/generic_system.mk
++++ b/target/product/generic_system.mk
+@@ -21,8 +21,10 @@ $(call inherit-product, $(SRC_TARGET_DIR)/product/languages_default.mk)
+ # Add adb keys to debuggable AOSP builds (if they exist)
+ $(call inherit-product-if-exists, vendor/google/security/adb/vendor_key.mk)
+
+-# Enable updating of APEXes
+-$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
++# Enable updating of APEXes on 6th and 7th generation Pixel devices only
++ifneq (,$(filter lineage_cheetah lineage_panther lineage_oriole lineage_raven lineage_bluejay lineage_lynx lineage_tangorpro lineage_felix, $(TARGET_PRODUCT)))
++ $(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
++endif
+
+ # Shared java libs
+ PRODUCT_PACKAGES += \
diff --git a/Patches/LineageOS-21.0/android_build_soong/0001-Enable_fwrapv.patch b/Patches/LineageOS-21.0/android_build_soong/0001-Enable_fwrapv.patch
new file mode 100644
index 00000000..6290a2e7
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_build_soong/0001-Enable_fwrapv.patch
@@ -0,0 +1,65 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 23 Aug 2017 20:28:03 -0400
+Subject: [PATCH] use -fwrapv when signed overflow checking is off
+
+13: 62bea80ab9189b81a8728b71b284b7afba9d5969
+---
+ cc/cc.go | 2 ++
+ cc/cc_test.go | 2 +-
+ cc/sanitize.go | 14 ++++++++++++++
+ 3 files changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/cc/cc.go b/cc/cc.go
+index 9d5b8d894..01cae261a 100644
+--- a/cc/cc.go
++++ b/cc/cc.go
+@@ -2052,6 +2052,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+ }
+ if c.sanitize != nil {
+ flags = c.sanitize.flags(ctx, flags)
++ } else {
++ flags.Local.CFlags = append(flags.Local.CFlags, "-fwrapv")
+ }
+ if c.coverage != nil {
+ flags, deps = c.coverage.flags(ctx, flags, deps)
+diff --git a/cc/cc_test.go b/cc/cc_test.go
+index 3631f1998..af9498499 100644
+--- a/cc/cc_test.go
++++ b/cc/cc_test.go
+@@ -4427,7 +4427,7 @@ func TestIncludeDirectoryOrdering(t *testing.T) {
+ conly := []string{"-fPIC", "${config.CommonGlobalConlyflags}"}
+ cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
+
+- cflags := []string{"-Werror", "-std=candcpp"}
++ cflags := []string{"-Werror", "-std=candcpp", "-fwrapv"}
+ cstd := []string{"-std=gnu17", "-std=conly"}
+ cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"}
+
+diff --git a/cc/sanitize.go b/cc/sanitize.go
+index 31c050018..38eeb12af 100644
+--- a/cc/sanitize.go
++++ b/cc/sanitize.go
+@@ -787,8 +787,22 @@ func toDisableUnsignedShiftBaseChange(flags []string) bool {
+
+ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
+ if !s.Properties.SanitizerEnabled && !s.Properties.UbsanRuntimeDep {
++ flags.Local.CFlags = append(flags.Local.CFlags, "-fwrapv")
+ return flags
+ }
++
++ wrapv := true
++ for _, san := range s.Properties.Sanitizers {
++ if san == "signed-integer-overflow" || san == "integer" || san == "undefined" {
++ wrapv = false
++ break
++ }
++ }
++
++ if wrapv {
++ flags.Local.CFlags = append(flags.Local.CFlags, "-fwrapv")
++ }
++
+ sanProps := &s.Properties.SanitizeMutated
+
+ if Bool(sanProps.Address) {
diff --git a/Patches/LineageOS-21.0/android_build_soong/0002-hm_available.patch b/Patches/LineageOS-21.0/android_build_soong/0002-hm_available.patch
new file mode 100644
index 00000000..2d3305f1
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_build_soong/0002-hm_available.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Thu, 5 Oct 2023 15:16:24 +0300
+Subject: [PATCH] mark hardened_malloc as bp2build_available
+
+---
+ android/allowlists/allowlists.go | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
+index b9d26f884..34c83e00c 100644
+--- a/android/allowlists/allowlists.go
++++ b/android/allowlists/allowlists.go
+@@ -160,6 +160,7 @@ var (
+ "external/guava": Bp2BuildDefaultTrueRecursively,
+ "external/gwp_asan": Bp2BuildDefaultTrueRecursively,
+ "external/hamcrest": Bp2BuildDefaultTrueRecursively,
++ "external/hardened_malloc": Bp2BuildDefaultTrueRecursively,
+ "external/icu": Bp2BuildDefaultTrueRecursively,
+ "external/icu/android_icu4j": Bp2BuildDefaultFalse, // java rules incomplete
+ "external/icu/icu4j": Bp2BuildDefaultFalse, // java rules incomplete
diff --git a/Patches/LineageOS-21.0/android_external_conscrypt/0001-constify_JNINativeMethod.patch b/Patches/LineageOS-21.0/android_external_conscrypt/0001-constify_JNINativeMethod.patch
new file mode 100644
index 00000000..64e19cb3
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_external_conscrypt/0001-constify_JNINativeMethod.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 18 Nov 2020 14:28:24 -0500
+Subject: [PATCH] constify JNINativeMethod table
+
+---
+ common/src/jni/main/cpp/conscrypt/native_crypto.cc | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/common/src/jni/main/cpp/conscrypt/native_crypto.cc b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
+index 6d831d03..db24fbc3 100644
+--- a/common/src/jni/main/cpp/conscrypt/native_crypto.cc
++++ b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
+@@ -10940,7 +10940,7 @@ static jlong NativeCrypto_SSL_get1_session(JNIEnv* env, jclass, jlong ssl_addres
+ #define REF_X509_CRL "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLX509CRL;"
+ #define REF_SSL "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeSsl;"
+ #define REF_SSL_CTX "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/AbstractSessionContext;"
+-static JNINativeMethod sNativeCryptoMethods[] = {
++static const JNINativeMethod sNativeCryptoMethods[] = {
+ CONSCRYPT_NATIVE_METHOD(clinit, "()V"),
+ CONSCRYPT_NATIVE_METHOD(CMAC_CTX_new, "()J"),
+ CONSCRYPT_NATIVE_METHOD(CMAC_CTX_free, "(J)V"),
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0003-SUPL_No_IMSI.patch b/Patches/LineageOS-21.0/android_frameworks_base/0003-SUPL_No_IMSI.patch
new file mode 100644
index 00000000..e7c36dd8
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0003-SUPL_No_IMSI.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: MSe1969
+Date: Mon, 29 Oct 2018 12:14:17 +0100
+Subject: [PATCH] SUPL: Don't send IMSI / Phone number to SUPL server
+
+Change-Id: I5ccc4d61e52ac11ef33f44618d0e610089885b87
+---
+ .../android/server/location/gnss/GnssLocationProvider.java | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+index 0386ee454278..af7dcc7d917a 100644
+--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
++++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+@@ -1798,6 +1798,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
+ int type = AGPS_SETID_TYPE_NONE;
+ String setId = null;
+
++ /*
++ * We don't want to tell Google our IMSI or phone number to spy on us!
++ * As devices w/o SIM card also have working GPS, providing this data does
++ * not seem to add a lot of value, at least not for the device holder
++ *
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ if (mGnssConfiguration.isActiveSimEmergencySuplEnabled() && mNIHandler.getInEmergency()
+ && mNetworkConnectivityHandler.getActiveSubId() >= 0) {
+@@ -1818,7 +1823,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
+ // This means the framework has the SIM card.
+ type = AGPS_SETID_TYPE_MSISDN;
+ }
+- }
++ } */
+
+ mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId);
+ }
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0004-Fingerprint_Lockout.patch b/Patches/LineageOS-21.0/android_frameworks_base/0004-Fingerprint_Lockout.patch
new file mode 100644
index 00000000..f7ba2902
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0004-Fingerprint_Lockout.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 12 Sep 2017 01:52:11 -0400
+Subject: [PATCH] use permanent fingerprint lockout immediately
+
+Signed-off-by: anupritaisno1
+---
+ .../sensors/fingerprint/hidl/LockoutFrameworkImpl.java | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
+index 0730c672acd9..cbd7a8963eb1 100644
+--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
++++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
+@@ -43,7 +43,7 @@ public class LockoutFrameworkImpl implements LockoutTracker {
+ private static final String ACTION_LOCKOUT_RESET =
+ "com.android.server.biometrics.sensors.fingerprint.ACTION_LOCKOUT_RESET";
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
+- private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
++ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 5;
+ private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
+ private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
+
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0005-User_Logout-a1.patch b/Patches/LineageOS-21.0/android_frameworks_base/0005-User_Logout-a1.patch
new file mode 100644
index 00000000..3f0401da
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0005-User_Logout-a1.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Thu, 18 Aug 2022 10:04:46 +0300
+Subject: [PATCH] fix DevicePolicyManager#logoutUser() never succeeding
+
+To succeed, userId to switch to needs to be set with setLogoutUserIdLocked(), but this is not done
+in both callers of this method (both of which are "End session" buttons), making them no-ops.
+---
+ .../server/devicepolicy/DevicePolicyManagerService.java | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+index cc8da148d272..6a2d88e49c27 100644
+--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
++++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+@@ -12698,6 +12698,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ Preconditions.checkCallAuthorization(canManageUsers(caller)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
+
++ synchronized (getLockObject()) {
++ if (getLogoutUserIdUnchecked() == UserHandle.USER_NULL) {
++ setLogoutUserIdLocked(UserHandle.USER_SYSTEM);
++ }
++ }
++
+ int currentUserId = getCurrentForegroundUserId();
+ if (VERBOSE_LOG) {
+ Slogf.v(LOG_TAG, "logout() called by uid %d; current user is %d", caller.getUid(),
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0005-User_Logout.patch b/Patches/LineageOS-21.0/android_frameworks_base/0005-User_Logout.patch
new file mode 100644
index 00000000..5a64663d
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0005-User_Logout.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: flawedworld
+Date: Fri, 15 Oct 2021 17:07:13 +0100
+Subject: [PATCH] enable secondary user logout support by default
+
+Ported from 11, 12 moved the isLogoutEnabled boolean to ActiveAdmin.java
+---
+ .../java/com/android/server/devicepolicy/ActiveAdmin.java | 2 +-
+ .../server/devicepolicy/DevicePolicyManagerService.java | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+index 17638fcaba68..7e416811c45a 100644
+--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
++++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+@@ -234,7 +234,7 @@ class ActiveAdmin {
+ boolean requireAutoTime = false;
+ boolean forceEphemeralUsers = false;
+ boolean isNetworkLoggingEnabled = false;
+- boolean isLogoutEnabled = false;
++ boolean isLogoutEnabled = true;
+
+ // one notification after enabling + one more after reboots
+ static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2;
+diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+index fb07763f58d6..cc8da148d272 100644
+--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
++++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+@@ -18919,11 +18919,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ @Override
+ public boolean isLogoutEnabled() {
+ if (!mHasFeature) {
+- return false;
++ return true;
+ }
+ synchronized (getLockObject()) {
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+- return (deviceOwner != null) && deviceOwner.isLogoutEnabled;
++ return (deviceOwner == null) || deviceOwner.isLogoutEnabled;
+ }
+ }
+
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0007-Always_Restict_Serial.patch b/Patches/LineageOS-21.0/android_frameworks_base/0007-Always_Restict_Serial.patch
new file mode 100644
index 00000000..42b7db9a
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0007-Always_Restict_Serial.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 6 Sep 2017 21:40:48 -0400
+Subject: [PATCH] always set deprecated Build.SERIAL to UNKNOWN
+
+Only support fetching the serial number via the new Build.getSerial()
+requiring the READ_PHONE_STATE permission.
+---
+ .../java/com/android/server/am/ActivityManagerService.java | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
+index 89b53aab1539..0d95e615911d 100644
+--- a/services/core/java/com/android/server/am/ActivityManagerService.java
++++ b/services/core/java/com/android/server/am/ActivityManagerService.java
+@@ -4707,12 +4707,7 @@ public class ActivityManagerService extends IActivityManager.Stub
+
+ ProfilerInfo profilerInfo = mAppProfiler.setupProfilerInfoLocked(thread, app, instr);
+
+- // 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;
++ final String buildSerial = Build.UNKNOWN;
+
+ // Figure out whether the app needs to run in autofill compat mode.
+ AutofillOptions autofillOptions = null;
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0008-Browser_No_Location.patch b/Patches/LineageOS-21.0/android_frameworks_base/0008-Browser_No_Location.patch
new file mode 100644
index 00000000..63a84459
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0008-Browser_No_Location.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Mon, 18 Mar 2019 01:54:30 +0200
+Subject: [PATCH] stop auto-granting location to system browsers
+
+---
+ .../pm/permission/DefaultPermissionGrantPolicy.java | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+index f7f76aaaee16..2c5b6ddc876e 100644
+--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
++++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+@@ -776,19 +776,6 @@ final class DefaultPermissionGrantPolicy {
+ Intent.CATEGORY_APP_EMAIL, userId),
+ userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS);
+
+- // Browser
+- String browserPackage = ArrayUtils.firstOrNull(getKnownPackages(
+- KnownPackages.PACKAGE_BROWSER, userId));
+- if (browserPackage == null) {
+- browserPackage = getDefaultSystemHandlerActivityPackageForCategory(pm,
+- Intent.CATEGORY_APP_BROWSER, userId);
+- if (!pm.isSystemPackage(browserPackage)) {
+- browserPackage = null;
+- }
+- }
+- grantPermissionsToPackage(pm, browserPackage, userId, false /* ignoreSystemPackage */,
+- true /*whitelistRestrictedPermissions*/, FOREGROUND_LOCATION_PERMISSIONS);
+-
+ // Voice interaction
+ if (voiceInteractPackageNames != null) {
+ for (String voiceInteractPackageName : voiceInteractPackageNames) {
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0017-constify_JNINativeMethod.patch b/Patches/LineageOS-21.0/android_frameworks_base/0017-constify_JNINativeMethod.patch
new file mode 100644
index 00000000..df33b123
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0017-constify_JNINativeMethod.patch
@@ -0,0 +1,509 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Mon, 9 Oct 2023 14:21:11 +0300
+Subject: [PATCH] constify JNINativeMethod tables
+
+fd '.+\.(c|cpp|cc)$' --exec sed -i 's/static JNINativeMethod/static const JNINativeMethod/'
+---
+ .../jni/com_android_commands_hid_Device.cpp | 2 +-
+ .../com_android_commands_uinput_Device.cpp | 2 +-
+ core/jni/LayoutlibLoader.cpp | 2 +-
+ core/jni/android_app_ActivityThread.cpp | 2 +-
+ core/jni/android_media_MediaMetricsJNI.cpp | 238 +++++++++++++++++-
+ core/jni/android_os_HidlMemory.cpp | 2 +-
+ core/jni/android_os_HwBinder.cpp | 2 +-
+ core/jni/android_os_HwBlob.cpp | 2 +-
+ core/jni/android_os_HwParcel.cpp | 2 +-
+ core/jni/android_os_HwRemoteBinder.cpp | 2 +-
+ .../android_graphics_DisplayListCanvas.cpp | 2 +-
+ media/jni/android_media_ImageWriter.cpp | 4 +-
+ media/jni/android_media_MediaSync.cpp | 2 +-
+ .../jni/soundpool/android_media_SoundPool.cpp | 2 +-
+ .../com_android_server_UsbAlsaMidiDevice.cpp | 2 +-
+ ...rver_companion_virtual_InputController.cpp | 2 +-
+ .../com_android_server_tv_TvUinputBridge.cpp | 2 +-
+ ...oid_view_tests_ChoreographerNativeTest.cpp | 2 +-
+ 18 files changed, 255 insertions(+), 19 deletions(-)
+ mode change 120000 => 100644 core/jni/android_media_MediaMetricsJNI.cpp
+
+diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
+index 8b8d361edbd4..60aa5e4267aa 100644
+--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
++++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
+@@ -368,7 +368,7 @@ static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
+ }
+ }
+
+-static JNINativeMethod sMethods[] = {
++static const JNINativeMethod sMethods[] = {
+ {"nativeOpenDevice",
+ "(Ljava/lang/String;IIII[B"
+ "Lcom/android/commands/hid/Device$DeviceCallback;)J",
+diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
+index a78a46504684..5752be8829cb 100644
+--- a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
++++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
+@@ -325,7 +325,7 @@ static jint getEvdevInputPropByLabel(JNIEnv* env, jclass /* clazz */, jstring ra
+ return InputEventLookup::getLinuxEvdevInputPropByLabel(label.c_str()).value_or(-1);
+ }
+
+-static JNINativeMethod sMethods[] = {
++static const JNINativeMethod sMethods[] = {
+ {"nativeOpenUinputDevice",
+ "(Ljava/lang/String;IIIIIILjava/lang/String;"
+ "Lcom/android/commands/uinput/Device$DeviceCallback;)J",
+diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp
+index 200ddefc3bbc..e7acbdfbddf6 100644
+--- a/core/jni/LayoutlibLoader.cpp
++++ b/core/jni/LayoutlibLoader.cpp
+@@ -69,7 +69,7 @@ static void NativeAllocationRegistry_Delegate_nativeApplyFreeFunction(JNIEnv*, j
+ nativeFreeFunction(nativePtr);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(NativeAllocationRegistry_Delegate, nativeApplyFreeFunction, "(JJ)V"),
+ };
+
+diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
+index e25ba76cbbeb..16a8d4656179 100644
+--- a/core/jni/android_app_ActivityThread.cpp
++++ b/core/jni/android_app_ActivityThread.cpp
+@@ -33,7 +33,7 @@ static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env,
+ android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0);
+ }
+
+-static JNINativeMethod gActivityThreadMethods[] = {
++static const JNINativeMethod gActivityThreadMethods[] = {
+ // ------------ Regular JNI ------------------
+ { "nPurgePendingResources", "()V",
+ (void*) android_app_ActivityThread_purgePendingResources },
+diff --git a/core/jni/android_media_MediaMetricsJNI.cpp b/core/jni/android_media_MediaMetricsJNI.cpp
+deleted file mode 120000
+index 3204317cab68..000000000000
+--- a/core/jni/android_media_MediaMetricsJNI.cpp
++++ /dev/null
+@@ -1 +0,0 @@
+-../../media/jni/android_media_MediaMetricsJNI.cpp
+\ No newline at end of file
+diff --git a/core/jni/android_media_MediaMetricsJNI.cpp b/core/jni/android_media_MediaMetricsJNI.cpp
+new file mode 100644
+index 000000000000..2769dbc430ba
+--- /dev/null
++++ b/core/jni/android_media_MediaMetricsJNI.cpp
+@@ -0,0 +1,237 @@
++/*
++ * Copyright 2017, The Android Open Source Project
++ *
++ * 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.
++ */
++
++#define LOG_TAG "MediaMetricsJNI"
++
++#include
++#include
++#include
++#include
++#include
++
++#include "android_media_MediaMetricsJNI.h"
++#include "android_os_Parcel.h"
++#include "android_runtime/AndroidRuntime.h"
++
++// This source file is compiled and linked into:
++// core/jni/ (libandroid_runtime.so)
++
++namespace android {
++
++namespace {
++struct BundleHelper {
++ BundleHelper(JNIEnv* _env, jobject _bundle)
++ : env(_env)
++ , clazzBundle(env->FindClass("android/os/PersistableBundle"))
++ , putIntID(env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"))
++ , putLongID(env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"))
++ , putDoubleID(env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"))
++ , putStringID(env->GetMethodID(clazzBundle,
++ "putString", "(Ljava/lang/String;Ljava/lang/String;)V"))
++ , constructID(env->GetMethodID(clazzBundle, "", "()V"))
++ , bundle(_bundle == nullptr ? env->NewObject(clazzBundle, constructID) : _bundle)
++ { }
++
++ JNIEnv* const env;
++ const jclass clazzBundle;
++ const jmethodID putIntID;
++ const jmethodID putLongID;
++ const jmethodID putDoubleID;
++ const jmethodID putStringID;
++ const jmethodID constructID;
++ jobject const bundle;
++
++ // We use templated put to access mediametrics::Item based on data type not type enum.
++ // See std::variant and std::visit.
++ template
++ void put(jstring keyName, const T& value) = delete;
++
++ template<>
++ void put(jstring keyName, const int32_t& value) {
++ env->CallVoidMethod(bundle, putIntID, keyName, (jint)value);
++ }
++
++ template<>
++ void put(jstring keyName, const int64_t& value) {
++ env->CallVoidMethod(bundle, putLongID, keyName, (jlong)value);
++ }
++
++ template<>
++ void put(jstring keyName, const double& value) {
++ env->CallVoidMethod(bundle, putDoubleID, keyName, (jdouble)value);
++ }
++
++ template<>
++ void put(jstring keyName, const std::string& value) {
++ env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value.c_str()));
++ }
++
++ template<>
++ void put(jstring keyName, const std::pair& value) {
++ ; // rate is currently ignored
++ }
++
++ template<>
++ void put(jstring keyName, const std::monostate& value) {
++ ; // none is currently ignored
++ }
++
++ // string char * helpers
++
++ template<>
++ void put(jstring keyName, const char * const& value) {
++ env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
++ }
++
++ template<>
++ void put(jstring keyName, char * const& value) {
++ env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
++ }
++
++ // We allow both jstring and non-jstring variants.
++ template
++ void put(const char *keyName, const T& value) {
++ put(env->NewStringUTF(keyName), value);
++ }
++};
++} // namespace
++
++// place the attributes into a java PersistableBundle object
++jobject MediaMetricsJNI::writeMetricsToBundle(
++ JNIEnv* env, mediametrics::Item *item, jobject bundle)
++{
++ BundleHelper bh(env, bundle);
++
++ if (bh.bundle == nullptr) {
++ ALOGE("%s: unable to create Bundle", __func__);
++ return nullptr;
++ }
++
++ bh.put(mediametrics::BUNDLE_KEY, item->getKey().c_str());
++ if (item->getPid() != -1) {
++ bh.put(mediametrics::BUNDLE_PID, (int32_t)item->getPid());
++ }
++ if (item->getTimestamp() > 0) {
++ bh.put(mediametrics::BUNDLE_TIMESTAMP, (int64_t)item->getTimestamp());
++ }
++ if (static_cast(item->getUid()) != -1) {
++ bh.put(mediametrics::BUNDLE_UID, (int32_t)item->getUid());
++ }
++ for (const auto &prop : *item) {
++ const char *name = prop.getName();
++ if (name == nullptr) continue;
++ prop.visit([&] (auto &value) { bh.put(name, value); });
++ }
++ return bh.bundle;
++}
++
++// Implementation of MediaMetrics.native_submit_bytebuffer(),
++// Delivers the byte buffer to the mediametrics service.
++static jint android_media_MediaMetrics_submit_bytebuffer(
++ JNIEnv* env, jobject thiz, jobject byteBuffer, jint length)
++{
++ const jbyte* buffer =
++ reinterpret_cast(env->GetDirectBufferAddress(byteBuffer));
++ if (buffer == nullptr) {
++ ALOGE("Error retrieving source of audio data to play, can't play");
++ return (jint)BAD_VALUE;
++ }
++
++ return (jint)mediametrics::BaseItem::submitBuffer((char *)buffer, length);
++}
++
++// Helper function to convert a native PersistableBundle to a Java
++// PersistableBundle.
++jobject MediaMetricsJNI::nativeToJavaPersistableBundle(JNIEnv *env,
++ os::PersistableBundle* nativeBundle) {
++ if (env == NULL || nativeBundle == NULL) {
++ ALOGE("Unexpected NULL parmeter");
++ return NULL;
++ }
++
++ // Create a Java parcel with the native parcel data.
++ // Then create a new PersistableBundle with that parcel as a parameter.
++ jobject jParcel = android::createJavaParcelObject(env);
++ if (jParcel == NULL) {
++ ALOGE("Failed to create a Java Parcel.");
++ return NULL;
++ }
++
++ android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
++ if (nativeParcel == NULL) {
++ ALOGE("Failed to get the native Parcel.");
++ return NULL;
++ }
++
++ android::status_t result = nativeBundle->writeToParcel(nativeParcel);
++ nativeParcel->setDataPosition(0);
++ if (result != android::OK) {
++ ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
++ return NULL;
++ }
++
++#define STATIC_INIT_JNI(T, obj, method, globalref, ...) \
++ static T obj{};\
++ if (obj == NULL) { \
++ obj = method(__VA_ARGS__); \
++ if (obj == NULL) { \
++ ALOGE("%s can't find " #obj, __func__); \
++ return NULL; \
++ } else { \
++ obj = globalref; \
++ }\
++ } \
++
++ STATIC_INIT_JNI(jclass, clazzBundle, env->FindClass,
++ static_cast(env->NewGlobalRef(clazzBundle)),
++ "android/os/PersistableBundle");
++ STATIC_INIT_JNI(jfieldID, bundleCreatorId, env->GetStaticFieldID,
++ bundleCreatorId,
++ clazzBundle, "CREATOR", "Landroid/os/Parcelable$Creator;");
++ STATIC_INIT_JNI(jobject, bundleCreator, env->GetStaticObjectField,
++ env->NewGlobalRef(bundleCreator),
++ clazzBundle, bundleCreatorId);
++ STATIC_INIT_JNI(jclass, clazzCreator, env->FindClass,
++ static_cast(env->NewGlobalRef(clazzCreator)),
++ "android/os/Parcelable$Creator");
++ STATIC_INIT_JNI(jmethodID, createFromParcelId, env->GetMethodID,
++ createFromParcelId,
++ clazzCreator, "createFromParcel", "(Landroid/os/Parcel;)Ljava/lang/Object;");
++
++ jobject newBundle = env->CallObjectMethod(bundleCreator, createFromParcelId, jParcel);
++ if (newBundle == NULL) {
++ ALOGE("Failed to create a new PersistableBundle "
++ "from the createFromParcel call.");
++ }
++
++ return newBundle;
++}
++
++// ----------------------------------------------------------------------------
++
++static constexpr JNINativeMethod gMethods[] = {
++ {"native_submit_bytebuffer", "(Ljava/nio/ByteBuffer;I)I",
++ (void *)android_media_MediaMetrics_submit_bytebuffer},
++};
++
++// Registers the native methods, called from core/jni/AndroidRuntime.cpp
++int register_android_media_MediaMetrics(JNIEnv *env)
++{
++ return AndroidRuntime::registerNativeMethods(
++ env, "android/media/MediaMetrics", gMethods, std::size(gMethods));
++}
++
++}; // namespace android
+diff --git a/core/jni/android_os_HidlMemory.cpp b/core/jni/android_os_HidlMemory.cpp
+index 69e48184c0ad..612fc95776a5 100644
+--- a/core/jni/android_os_HidlMemory.cpp
++++ b/core/jni/android_os_HidlMemory.cpp
+@@ -50,7 +50,7 @@ static void nativeFinalize(JNIEnv* env, jobject jobj) {
+ delete native;
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ {"nativeFinalize", "()V", (void*) nativeFinalize},
+ };
+
+diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
+index 781895eeeaba..cbec79144826 100644
+--- a/core/jni/android_os_HwBinder.cpp
++++ b/core/jni/android_os_HwBinder.cpp
+@@ -352,7 +352,7 @@ static void JHwBinder_report_sysprop_change(JNIEnv * /*env*/, jclass /*clazz*/)
+ report_sysprop_change();
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ { "native_init", "()J", (void *)JHwBinder_native_init },
+ { "native_setup", "()V", (void *)JHwBinder_native_setup },
+
+diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
+index e554b44233b5..065937f935fb 100644
+--- a/core/jni/android_os_HwBlob.cpp
++++ b/core/jni/android_os_HwBlob.cpp
+@@ -599,7 +599,7 @@ static jlong JHwBlob_native_handle(JNIEnv *env, jobject thiz) {
+ return handle;
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ { "native_init", "()J", (void *)JHwBlob_native_init },
+ { "native_setup", "(I)V", (void *)JHwBlob_native_setup },
+
+diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
+index 0e3c51047b31..edda99533f63 100644
+--- a/core/jni/android_os_HwParcel.cpp
++++ b/core/jni/android_os_HwParcel.cpp
+@@ -1066,7 +1066,7 @@ static void JHwParcel_native_writeBuffer(
+ }
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ { "native_init", "()J", (void *)JHwParcel_native_init },
+ { "native_setup", "(Z)V", (void *)JHwParcel_native_setup },
+
+diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
+index d2d7213e5761..497aa193eb4d 100644
+--- a/core/jni/android_os_HwRemoteBinder.cpp
++++ b/core/jni/android_os_HwRemoteBinder.cpp
+@@ -452,7 +452,7 @@ static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) {
+ return static_cast(longHash ^ (longHash >> 32)); // See Long.hashCode()
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ { "native_init", "()J", (void *)JHwRemoteBinder_native_init },
+
+ { "native_setup_empty", "()V",
+diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+index 426644ee6a4e..f886d7dc4e5c 100644
+--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
++++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+@@ -174,7 +174,7 @@ static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAM
+
+ const char* const kClassPathName = "android/graphics/RecordingCanvas";
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ {"nGetMaximumTextureWidth", "()I", (void*)android_view_DisplayListCanvas_getMaxTextureSize},
+ {"nGetMaximumTextureHeight", "()I",
+ (void*)android_view_DisplayListCanvas_getMaxTextureSize},
+diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
+index f64233fb9c79..a99fcea46911 100644
+--- a/media/jni/android_media_ImageWriter.cpp
++++ b/media/jni/android_media_ImageWriter.cpp
+@@ -1114,7 +1114,7 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
+
+ // ----------------------------------------------------------------------------
+
+-static JNINativeMethod gImageWriterMethods[] = {
++static const JNINativeMethod gImageWriterMethods[] = {
+ {"nativeClassInit", "()V", (void*)ImageWriter_classInit },
+ {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;IIIZIIJ)J",
+ (void*)ImageWriter_init },
+@@ -1131,7 +1131,7 @@ static JNINativeMethod gImageWriterMethods[] = {
+ {"cancelImage", "(JLandroid/media/Image;)V", (void*)ImageWriter_cancelImage },
+ };
+
+-static JNINativeMethod gImageMethods[] = {
++static const JNINativeMethod gImageMethods[] = {
+ {"nativeCreatePlanes", "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
+ (void*)Image_createSurfacePlanes },
+ {"nativeGetWidth", "()I", (void*)Image_getWidth },
+diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
+index d1ce30a3e827..d93bda166c44 100644
+--- a/media/jni/android_media_MediaSync.cpp
++++ b/media/jni/android_media_MediaSync.cpp
+@@ -514,7 +514,7 @@ static void android_media_MediaSync_native_finalize(JNIEnv *env, jobject thiz) {
+ android_media_MediaSync_release(env, thiz);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ { "native_setSurface",
+ "(Landroid/view/Surface;)V",
+ (void *)android_media_MediaSync_native_setSurface },
+diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
+index 25040a942061..f62c4340428c 100644
+--- a/media/jni/soundpool/android_media_SoundPool.cpp
++++ b/media/jni/soundpool/android_media_SoundPool.cpp
+@@ -560,7 +560,7 @@ android_media_SoundPool_release(JNIEnv *env, jobject thiz)
+ // ----------------------------------------------------------------------------
+
+ // Dalvik VM type signatures
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ { "_load",
+ "(Ljava/io/FileDescriptor;JJI)I",
+ (void *)android_media_SoundPool_load_FD
+diff --git a/services/core/jni/com_android_server_UsbAlsaMidiDevice.cpp b/services/core/jni/com_android_server_UsbAlsaMidiDevice.cpp
+index 93938b1ff1bc..47b22c5fd39f 100644
+--- a/services/core/jni/com_android_server_UsbAlsaMidiDevice.cpp
++++ b/services/core/jni/com_android_server_UsbAlsaMidiDevice.cpp
+@@ -138,7 +138,7 @@ static void android_server_UsbAlsaMidiDevice_close(JNIEnv *env, jobject thiz, jo
+ }
+ }
+
+-static JNINativeMethod method_table[] = {
++static const JNINativeMethod method_table[] = {
+ {"nativeOpen", "(IIII)[Ljava/io/FileDescriptor;",
+ (void *)android_server_UsbAlsaMidiDevice_open},
+ {"nativeClose", "([Ljava/io/FileDescriptor;)V",
+diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+index 4cd018b0269e..039258cf983c 100644
+--- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp
++++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+@@ -287,7 +287,7 @@ static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat
+ std::chrono::nanoseconds(eventTimeNanos));
+ }
+
+-static JNINativeMethod methods[] = {
++static const JNINativeMethod methods[] = {
+ {"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)J",
+ (void*)nativeOpenUinputDpad},
+ {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)J",
+diff --git a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
+index 99deab4fd652..2cb1aaef13fa 100644
+--- a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
++++ b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
+@@ -534,7 +534,7 @@ static void nativeClear(JNIEnv* env, jclass clazz, jlong ptr) {
+ * JNI registration
+ */
+
+-static JNINativeMethod gUinputBridgeMethods[] = {
++static const JNINativeMethod gUinputBridgeMethods[] = {
+ {"nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J", (void*)nativeOpen},
+ {"nativeGamepadOpen", "(Ljava/lang/String;Ljava/lang/String;)J", (void*)nativeGamepadOpen},
+ {"nativeClose", "(J)V", (void*)nativeClose},
+diff --git a/tests/ChoreographerTests/jni/android_view_tests_ChoreographerNativeTest.cpp b/tests/ChoreographerTests/jni/android_view_tests_ChoreographerNativeTest.cpp
+index 27f4bae9e65a..b5620251d41b 100644
+--- a/tests/ChoreographerTests/jni/android_view_tests_ChoreographerNativeTest.cpp
++++ b/tests/ChoreographerTests/jni/android_view_tests_ChoreographerNativeTest.cpp
+@@ -151,7 +151,7 @@ static void android_view_ChoreographerNativeTest_testPostVsyncCallbackAtFrameRat
+ endTest(env, clazz);
+ }
+
+-static JNINativeMethod gMethods[] = {
++static const JNINativeMethod gMethods[] = {
+ {"nativeSurfaceControl_getChoreographer", "(Landroid/view/SurfaceControl;)J",
+ (void*)SurfaceControl_getChoreographer},
+ {"nativeTestPostVsyncCallbackAtFrameRate", "(JF)V",
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-1.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-1.patch
new file mode 100644
index 00000000..64a2d088
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-1.patch
@@ -0,0 +1,181 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Sat, 14 Mar 2015 18:10:20 -0400
+Subject: [PATCH] add exec-based spawning support
+
+---
+ .../com/android/internal/os/ExecInit.java | 115 ++++++++++++++++++
+ .../com/android/internal/os/WrapperInit.java | 2 +-
+ .../android/internal/os/ZygoteConnection.java | 10 +-
+ 3 files changed, 125 insertions(+), 2 deletions(-)
+ create mode 100644 core/java/com/android/internal/os/ExecInit.java
+
+diff --git a/core/java/com/android/internal/os/ExecInit.java b/core/java/com/android/internal/os/ExecInit.java
+new file mode 100644
+index 000000000000..2adcab7fdbe6
+--- /dev/null
++++ b/core/java/com/android/internal/os/ExecInit.java
+@@ -0,0 +1,115 @@
++package com.android.internal.os;
++
++import android.os.Trace;
++import android.system.ErrnoException;
++import android.system.Os;
++import android.util.Slog;
++import android.util.TimingsTraceLog;
++import dalvik.system.VMRuntime;
++
++/**
++ * Startup class for the process.
++ * @hide
++ */
++public class ExecInit {
++ /**
++ * Class not instantiable.
++ */
++ private ExecInit() {
++ }
++
++ /**
++ * The main function called when starting a runtime application.
++ *
++ * The first argument is the target SDK version for the app.
++ *
++ * The remaining arguments are passed to the runtime.
++ *
++ * @param args The command-line arguments.
++ */
++ public static void main(String[] args) {
++ // Parse our mandatory argument.
++ int targetSdkVersion = Integer.parseInt(args[0], 10);
++
++ // Mimic system Zygote preloading.
++ ZygoteInit.preload(new TimingsTraceLog("ExecInitTiming",
++ Trace.TRACE_TAG_DALVIK));
++
++ // Launch the application.
++ String[] runtimeArgs = new String[args.length - 1];
++ System.arraycopy(args, 1, runtimeArgs, 0, runtimeArgs.length);
++ Runnable r = execInit(targetSdkVersion, runtimeArgs);
++
++ r.run();
++ }
++
++ /**
++ * Executes a runtime application with exec-based spawning.
++ * This method never returns.
++ *
++ * @param niceName The nice name for the application, or null if none.
++ * @param targetSdkVersion The target SDK version for the app.
++ * @param args Arguments for {@link RuntimeInit#main}.
++ */
++ public static void execApplication(String niceName, int targetSdkVersion,
++ String instructionSet, String[] args) {
++ int niceArgs = niceName == null ? 0 : 1;
++ int baseArgs = 5 + niceArgs;
++ String[] argv = new String[baseArgs + args.length];
++ if (VMRuntime.is64BitInstructionSet(instructionSet)) {
++ argv[0] = "/system/bin/app_process64";
++ } else {
++ argv[0] = "/system/bin/app_process32";
++ }
++ argv[1] = "/system/bin";
++ argv[2] = "--application";
++ if (niceName != null) {
++ argv[3] = "--nice-name=" + niceName;
++ }
++ argv[3 + niceArgs] = "com.android.internal.os.ExecInit";
++ argv[4 + niceArgs] = Integer.toString(targetSdkVersion);
++ System.arraycopy(args, 0, argv, baseArgs, args.length);
++
++ WrapperInit.preserveCapabilities();
++ try {
++ Os.execv(argv[0], argv);
++ } catch (ErrnoException e) {
++ throw new RuntimeException(e);
++ }
++ }
++
++ /**
++ * The main function called when an application is started with exec-based spawning.
++ *
++ * When the app starts, the runtime starts {@link RuntimeInit#main}
++ * which calls {@link main} which then calls this method.
++ * So we don't need to call commonInit() here.
++ *
++ * @param targetSdkVersion target SDK version
++ * @param argv arg strings
++ */
++ private static Runnable execInit(int targetSdkVersion, String[] argv) {
++ if (RuntimeInit.DEBUG) {
++ Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from exec");
++ }
++
++ // Check whether the first argument is a "-cp" in argv, and assume the next argument is the
++ // classpath. If found, create a PathClassLoader and use it for applicationInit.
++ ClassLoader classLoader = null;
++ if (argv != null && argv.length > 2 && argv[0].equals("-cp")) {
++ classLoader = ZygoteInit.createPathClassLoader(argv[1], targetSdkVersion);
++
++ // Install this classloader as the context classloader, too.
++ Thread.currentThread().setContextClassLoader(classLoader);
++
++ // Remove the classpath from the arguments.
++ String removedArgs[] = new String[argv.length - 2];
++ System.arraycopy(argv, 2, removedArgs, 0, argv.length - 2);
++ argv = removedArgs;
++ }
++
++ // Perform the same initialization that would happen after the Zygote forks.
++ Zygote.nativePreApplicationInit();
++ return RuntimeInit.applicationInit(targetSdkVersion, /*disabledCompatChanges*/ null, argv, classLoader);
++ }
++}
+diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
+index 6860759eea8a..a2eef62f80be 100644
+--- a/core/java/com/android/internal/os/WrapperInit.java
++++ b/core/java/com/android/internal/os/WrapperInit.java
+@@ -186,7 +186,7 @@ public class WrapperInit {
+ * This is acceptable here as failure will leave the wrapped app with strictly less
+ * capabilities, which may make it crash, but not exceed its allowances.
+ */
+- private static void preserveCapabilities() {
++ public static void preserveCapabilities() {
+ StructCapUserHeader header = new StructCapUserHeader(
+ OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
+ StructCapUserData[] data;
+diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
+index cbe070048811..9e78c3a8b16c 100644
+--- a/core/java/com/android/internal/os/ZygoteConnection.java
++++ b/core/java/com/android/internal/os/ZygoteConnection.java
+@@ -29,6 +29,7 @@ import android.net.Credentials;
+ import android.net.LocalSocket;
+ import android.os.Parcel;
+ import android.os.Process;
++import android.os.SystemProperties;
+ import android.os.Trace;
+ import android.system.ErrnoException;
+ import android.system.Os;
+@@ -247,7 +248,7 @@ class ZygoteConnection {
+ fdsToClose[1] = zygoteFd.getInt$();
+ }
+
+- if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
++ if (parsedArgs.mInvokeWith != null || SystemProperties.getBoolean("sys.spawn.exec", false) || parsedArgs.mStartChildZygote
+ || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
+ // Continue using old code for now. TODO: Handle these cases in the other path.
+ pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
+@@ -535,6 +536,13 @@ class ZygoteConnection {
+ throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
+ } else {
+ if (!isZygote) {
++ if (SystemProperties.getBoolean("sys.spawn.exec", false)) {
++ ExecInit.execApplication(parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
++ VMRuntime.getCurrentInstructionSet(), parsedArgs.mRemainingArgs);
++
++ // Should not get here.
++ throw new IllegalStateException("ExecInit.execApplication unexpectedly returned");
++ }
+ return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
+ parsedArgs.mDisabledCompatChanges,
+ parsedArgs.mRemainingArgs, null /* classLoader */);
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-10.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-10.patch
new file mode 100644
index 00000000..cd474d7a
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-10.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 11 Sep 2019 06:57:24 -0400
+Subject: [PATCH] disable preloading classloaders for exec spawning
+
+---
+ core/java/com/android/internal/os/ZygoteInit.java | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 55c68981f919..699899e02f85 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -132,9 +132,11 @@ public class ZygoteInit {
+ preloadClasses();
+ bootTimingsTraceLog.traceEnd(); // PreloadClasses
+ }
+- bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
+- cacheNonBootClasspathClassLoaders();
+- bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
++ if (fullPreload) {
++ bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
++ cacheNonBootClasspathClassLoaders();
++ bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
++ }
+ if (fullPreload) {
+ bootTimingsTraceLog.traceBegin("PreloadResources");
+ Resources.preloadResources();
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-11.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-11.patch
new file mode 100644
index 00000000..bcaca8b7
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-11.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 11 Sep 2019 06:58:51 -0400
+Subject: [PATCH] disable preloading HALs for exec spawning
+
+---
+ core/java/com/android/internal/os/ZygoteInit.java | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 699899e02f85..da2f93d4539c 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -142,9 +142,11 @@ public class ZygoteInit {
+ Resources.preloadResources();
+ bootTimingsTraceLog.traceEnd(); // PreloadResources
+ }
+- Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
+- nativePreloadAppProcessHALs();
+- Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
++ if (fullPreload) {
++ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
++ nativePreloadAppProcessHALs();
++ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
++ }
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
+ maybePreloadGraphicsDriver();
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-12.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-12.patch
new file mode 100644
index 00000000..ca4782f4
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-12.patch
@@ -0,0 +1,289 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: anupritaisno1
+Date: Sat, 31 Oct 2020 00:26:09 +0200
+Subject: [PATCH] pass through runtime flags for exec spawning and implement
+ them in the child
+
+Signed-off-by: anupritaisno1
+---
+ .../com/android/internal/os/ExecInit.java | 14 +-
+ core/java/com/android/internal/os/Zygote.java | 9 +
+ .../android/internal/os/ZygoteConnection.java | 2 +-
+ core/jni/com_android_internal_os_Zygote.cpp | 164 ++++++++++--------
+ 4 files changed, 107 insertions(+), 82 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ExecInit.java b/core/java/com/android/internal/os/ExecInit.java
+index 830e5b562a91..749c67abf389 100644
+--- a/core/java/com/android/internal/os/ExecInit.java
++++ b/core/java/com/android/internal/os/ExecInit.java
+@@ -31,15 +31,20 @@ public class ExecInit {
+ // Parse our mandatory argument.
+ int targetSdkVersion = Integer.parseInt(args[0], 10);
+
++ // Parse the runtime_flags.
++ int runtimeFlags = Integer.parseInt(args[1], 10);
++
+ // Mimic system Zygote preloading.
+ ZygoteInit.preload(new TimingsTraceLog("ExecInitTiming",
+ Trace.TRACE_TAG_DALVIK), false);
+
+ // Launch the application.
+- String[] runtimeArgs = new String[args.length - 1];
+- System.arraycopy(args, 1, runtimeArgs, 0, runtimeArgs.length);
++ String[] runtimeArgs = new String[args.length - 2];
++ System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
+ Runnable r = execInit(targetSdkVersion, runtimeArgs);
+
++ Zygote.nativeHandleRuntimeFlags(runtimeFlags);
++
+ r.run();
+ }
+
+@@ -52,9 +57,9 @@ public class ExecInit {
+ * @param args Arguments for {@link RuntimeInit#main}.
+ */
+ public static void execApplication(String niceName, int targetSdkVersion,
+- String instructionSet, String[] args) {
++ String instructionSet, int runtimeFlags, String[] args) {
+ int niceArgs = niceName == null ? 0 : 1;
+- int baseArgs = 5 + niceArgs;
++ int baseArgs = 6 + niceArgs;
+ String[] argv = new String[baseArgs + args.length];
+ if (VMRuntime.is64BitInstructionSet(instructionSet)) {
+ argv[0] = "/system/bin/app_process64";
+@@ -68,6 +73,7 @@ public class ExecInit {
+ }
+ argv[3 + niceArgs] = "com.android.internal.os.ExecInit";
+ argv[4 + niceArgs] = Integer.toString(targetSdkVersion);
++ argv[5 + niceArgs] = Integer.toString(runtimeFlags);
+ System.arraycopy(args, 0, argv, baseArgs, args.length);
+
+ WrapperInit.preserveCapabilities();
+diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
+index cab84bb01f70..07691fcec545 100644
+--- a/core/java/com/android/internal/os/Zygote.java
++++ b/core/java/com/android/internal/os/Zygote.java
+@@ -1497,4 +1497,13 @@ public final class Zygote {
+ }
+ return runtimeFlags;
+ }
++
++ /**
++ * Used on GrapheneOS to set up runtime flags
++ *
++ * @param runtimeFlags flags to be passed to the native method
++ *
++ * @hide
++ */
++ public static native void nativeHandleRuntimeFlags(int runtimeFlags);
+ }
+diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
+index cc936ccefb91..eea7b1e57b37 100644
+--- a/core/java/com/android/internal/os/ZygoteConnection.java
++++ b/core/java/com/android/internal/os/ZygoteConnection.java
+@@ -539,7 +539,7 @@ class ZygoteConnection {
+ if (SystemProperties.getBoolean("sys.spawn.exec", false) &&
+ (parsedArgs.mRuntimeFlags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ ExecInit.execApplication(parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
+- VMRuntime.getCurrentInstructionSet(), parsedArgs.mRemainingArgs);
++ VMRuntime.getCurrentInstructionSet(), parsedArgs.mRuntimeFlags, parsedArgs.mRemainingArgs);
+
+ // Should not get here.
+ throw new IllegalStateException("ExecInit.execApplication unexpectedly returned");
+diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
+index 7c5885adb220..9fc92a480e1e 100644
+--- a/core/jni/com_android_internal_os_Zygote.cpp
++++ b/core/jni/com_android_internal_os_Zygote.cpp
+@@ -1872,6 +1872,86 @@ static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list,
+ }
+ }
+
++static void HandleRuntimeFlags(JNIEnv* env, jint& runtime_flags, const char* process_name, const char* nice_name_ptr) {
++ // Set process properties to enable debugging if required.
++ if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_PTRACE) != 0) {
++ EnableDebugger();
++ // Don't pass unknown flag to the ART runtime.
++ runtime_flags &= ~RuntimeFlags::DEBUG_ENABLE_PTRACE;
++ }
++ if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) {
++ // simpleperf needs the process to be dumpable to profile it.
++ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
++ ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno));
++ RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed");
++ }
++ }
++
++ HeapTaggingLevel heap_tagging_level;
++ switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) {
++ case RuntimeFlags::MEMORY_TAG_LEVEL_TBI:
++ heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
++ break;
++ case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC:
++ heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC;
++ break;
++ case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC:
++ heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
++ break;
++ default:
++ heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
++ break;
++ }
++ mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
++
++ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
++ // runtime.
++ runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
++
++ // Avoid heap zero initialization for applications without MTE. Zero init may
++ // cause app compat problems, use more memory, or reduce performance. While it
++ // would be nice to have them for apps, we will have to wait until they are
++ // proven out, have more efficient hardware, and/or apply them only to new
++ // applications.
++ if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED)) {
++ mallopt(M_BIONIC_ZERO_INIT, 0);
++ }
++
++ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
++ // runtime.
++ runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED;
++
++ android_mallopt_gwp_asan_options_t gwp_asan_options;
++ const char* kGwpAsanAppRecoverableSysprop =
++ "persist.device_config.memory_safety_native.gwp_asan_recoverable_apps";
++ // The system server doesn't have its nice name set by the time SpecializeCommon is called.
++ gwp_asan_options.program_name = nice_name_ptr ?: process_name;
++ switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
++ default:
++ case RuntimeFlags::GWP_ASAN_LEVEL_DEFAULT:
++ gwp_asan_options.desire = GetBoolProperty(kGwpAsanAppRecoverableSysprop, true)
++ ? Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING
++ : Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
++ android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
++ break;
++ case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
++ gwp_asan_options.desire = Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
++ android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
++ break;
++ case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
++ gwp_asan_options.desire = Action::TURN_ON_FOR_APP;
++ android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
++ break;
++ case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
++ gwp_asan_options.desire = Action::TURN_ON_WITH_SAMPLING;
++ android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
++ break;
++ }
++ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
++ // runtime.
++ runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
++}
++
+ // Utility routine to specialize a zygote child process.
+ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
+ jobjectArray rlimits, jlong permitted_capabilities,
+@@ -2019,84 +2099,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
+ }
+ }
+
+- // Set process properties to enable debugging if required.
+- if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_PTRACE) != 0) {
+- EnableDebugger();
+- // Don't pass unknown flag to the ART runtime.
+- runtime_flags &= ~RuntimeFlags::DEBUG_ENABLE_PTRACE;
+- }
+- if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) {
+- // simpleperf needs the process to be dumpable to profile it.
+- if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
+- ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno));
+- RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed");
+- }
+- }
+-
+- HeapTaggingLevel heap_tagging_level;
+- switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) {
+- case RuntimeFlags::MEMORY_TAG_LEVEL_TBI:
+- heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
+- break;
+- case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC:
+- heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC;
+- break;
+- case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC:
+- heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
+- break;
+- default:
+- heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
+- break;
+- }
+- mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
+-
+- // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
+- // runtime.
+- runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
+-
+- // Avoid heap zero initialization for applications without MTE. Zero init may
+- // cause app compat problems, use more memory, or reduce performance. While it
+- // would be nice to have them for apps, we will have to wait until they are
+- // proven out, have more efficient hardware, and/or apply them only to new
+- // applications.
+- if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED)) {
+- mallopt(M_BIONIC_ZERO_INIT, 0);
+- }
+-
+- // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
+- // runtime.
+- runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT_ENABLED;
+-
+ const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
+- android_mallopt_gwp_asan_options_t gwp_asan_options;
+- const char* kGwpAsanAppRecoverableSysprop =
+- "persist.device_config.memory_safety_native.gwp_asan_recoverable_apps";
+- // The system server doesn't have its nice name set by the time SpecializeCommon is called.
+- gwp_asan_options.program_name = nice_name_ptr ?: process_name;
+- switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
+- default:
+- case RuntimeFlags::GWP_ASAN_LEVEL_DEFAULT:
+- gwp_asan_options.desire = GetBoolProperty(kGwpAsanAppRecoverableSysprop, true)
+- ? Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING
+- : Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
+- android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
+- break;
+- case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
+- gwp_asan_options.desire = Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
+- android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
+- break;
+- case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
+- gwp_asan_options.desire = Action::TURN_ON_FOR_APP;
+- android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
+- break;
+- case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
+- gwp_asan_options.desire = Action::TURN_ON_WITH_SAMPLING;
+- android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
+- break;
+- }
+- // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
+- // runtime.
+- runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
++
++ HandleRuntimeFlags(env, runtime_flags, process_name, nice_name_ptr);
+
+ SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
+ fail_fn);
+@@ -3004,6 +3009,10 @@ static void com_android_internal_os_Zygote_nativeAllowFilesOpenedByPreload(JNIEn
+ gPreloadFdsExtracted = true;
+ }
+
++static void nativeHandleRuntimeFlagsWrapper(JNIEnv* env, jclass, jint runtime_flags) {
++ HandleRuntimeFlags(env, runtime_flags, nullptr, nullptr);
++}
++
+ static const JNINativeMethod gMethods[] = {
+ {"nativeForkAndSpecialize",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
+@@ -3056,6 +3065,7 @@ static const JNINativeMethod gMethods[] = {
+ (void*)com_android_internal_os_Zygote_nativeMarkOpenedFilesBeforePreload},
+ {"nativeAllowFilesOpenedByPreload", "()V",
+ (void*)com_android_internal_os_Zygote_nativeAllowFilesOpenedByPreload},
++ {"nativeHandleRuntimeFlags", "(I)V", (void*)nativeHandleRuntimeFlagsWrapper},
+ };
+
+ int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-13.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-13.patch
new file mode 100644
index 00000000..fe367633
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-13.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Mon, 8 Aug 2022 18:42:19 +0300
+Subject: [PATCH] exec spawning: don't close the binder connection when the app
+ crashes
+
+When an unhandled exception occured, binder connections were closed with
+IPCThreadState::stopProcess() before the invocation of java.lang.Thread#dispatchUncaughtException().
+By default, that method tries to report the crash via ActivityManager#handleApplicationCrash(),
+which always failed due to the closed binder connection.
+This meant that the crash dialog was never shown and additional crash handling was skipped.
+
+Zygote-based spawning never calls IPCThreadState::stopProcess().
+---
+ cmds/app_process/app_main.cpp | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
+index 4e41f2c1ac35..9ce4bef5bb6c 100644
+--- a/cmds/app_process/app_main.cpp
++++ b/cmds/app_process/app_main.cpp
+@@ -85,8 +85,10 @@ public:
+ AndroidRuntime* ar = AndroidRuntime::getRuntime();
+ ar->callMain(mClassName, mClass, mArgs);
+
+- IPCThreadState::self()->stopProcess();
+- hardware::IPCThreadState::self()->stopProcess();
++ if (mClassName != "com.android.internal.os.ExecInit") {
++ IPCThreadState::self()->stopProcess();
++ hardware::IPCThreadState::self()->stopProcess();
++ }
+ }
+
+ virtual void onZygoteInit()
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-14.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-14.patch
new file mode 100644
index 00000000..fbd98630
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-14.patch
@@ -0,0 +1,125 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Thu, 30 Mar 2023 17:42:56 +0300
+Subject: [PATCH] exec spawning: support runtime resource overlays
+
+---
+ core/java/android/app/IActivityManager.aidl | 2 ++
+ .../android/content/res/AssetManager.java | 33 +++++++++++++++++--
+ .../com/android/internal/os/ExecInit.java | 4 +++
+ .../server/am/ActivityManagerService.java | 6 ++++
+ 4 files changed, 43 insertions(+), 2 deletions(-)
+
+diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
+index 260e9859c72d..c3fdad0624d4 100644
+--- a/core/java/android/app/IActivityManager.aidl
++++ b/core/java/android/app/IActivityManager.aidl
+@@ -950,4 +950,6 @@ interface IActivityManager {
+ */
+ oneway void frozenBinderTransactionDetected(int debugPid, int code, int flags, int err);
+ int getBindingUidProcessState(int uid, in String callingPackage);
++
++ String[] getSystemIdmapPaths();
+ }
+diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
+index 0399995540e7..3885f0fe3dd4 100644
+--- a/core/java/android/content/res/AssetManager.java
++++ b/core/java/android/content/res/AssetManager.java
+@@ -26,6 +26,7 @@ import android.annotation.Nullable;
+ import android.annotation.StringRes;
+ import android.annotation.StyleRes;
+ import android.annotation.TestApi;
++import android.app.ActivityManager;
+ import android.compat.annotation.UnsupportedAppUsage;
+ import android.content.pm.ActivityInfo;
+ import android.content.res.Configuration.NativeConfig;
+@@ -40,6 +41,7 @@ import android.util.TypedValue;
+ import com.android.internal.annotations.GuardedBy;
+ import com.android.internal.annotations.VisibleForTesting;
+ import com.android.internal.content.om.OverlayConfig;
++import com.android.internal.os.ExecInit;
+
+ import java.io.FileDescriptor;
+ import java.io.FileNotFoundException;
+@@ -235,6 +237,9 @@ public final class AssetManager implements AutoCloseable {
+ }
+ }
+
++ /** @hide */
++ public static volatile String[] systemIdmapPaths_;
++
+ /**
+ * This must be called from Zygote so that system assets are shared by all applications.
+ * @hide
+@@ -251,8 +256,32 @@ public final class AssetManager implements AutoCloseable {
+ final ArrayList apkAssets = new ArrayList<>();
+ apkAssets.add(ApkAssets.loadFromPath(frameworkPath, ApkAssets.PROPERTY_SYSTEM));
+
+- final String[] systemIdmapPaths =
+- OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote();
++ // createImmutableFrameworkIdmapsInZygote() should be called only in zygote, it fails
++ // in regular processes and is unnecessary there.
++ // When it's called in zygote, overlay state is cached in /data/resource-cache/*@idmap
++ // files. These files are readable by regular app processes.
++ //
++ // When exec-based spawning in used, in-memory cache of assets is lost, and the spawned
++ // process is unable to recreate it, since it's not allowed to create idmaps.
++ //
++ // As a workaround, ask the ActivityManager to return paths of cached idmaps and use
++ // them directly. ActivityManager runs in system_server, which always uses zygote-based
++ // spawning.
++
++ String[] systemIdmapPaths;
++ if (ExecInit.isExecSpawned) {
++ try {
++ systemIdmapPaths = ActivityManager.getService().getSystemIdmapPaths();
++ Objects.requireNonNull(systemIdmapPaths);
++ } catch (Throwable t) {
++ Log.e(TAG, "unable to retrieve systemIdmapPaths", t);
++ systemIdmapPaths = new String[0];
++ }
++ } else {
++ systemIdmapPaths = OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote();
++ systemIdmapPaths_ = systemIdmapPaths;
++ }
++
+ for (String idmapPath : systemIdmapPaths) {
+ apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM));
+ }
+diff --git a/core/java/com/android/internal/os/ExecInit.java b/core/java/com/android/internal/os/ExecInit.java
+index 749c67abf389..39f08b6a0f15 100644
+--- a/core/java/com/android/internal/os/ExecInit.java
++++ b/core/java/com/android/internal/os/ExecInit.java
+@@ -84,6 +84,8 @@ public class ExecInit {
+ }
+ }
+
++ public static boolean isExecSpawned;
++
+ /**
+ * The main function called when an application is started with exec-based spawning.
+ *
+@@ -99,6 +101,8 @@ public class ExecInit {
+ Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from exec");
+ }
+
++ isExecSpawned = true;
++
+ // Check whether the first argument is a "-cp" in argv, and assume the next argument is the
+ // classpath. If found, create a PathClassLoader and use it for applicationInit.
+ ClassLoader classLoader = null;
+diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
+index 0d95e615911d..ba6d5a027c9d 100644
+--- a/services/core/java/com/android/server/am/ActivityManagerService.java
++++ b/services/core/java/com/android/server/am/ActivityManagerService.java
+@@ -20673,4 +20673,10 @@ public class ActivityManagerService extends IActivityManager.Stub
+ }
+ mOomAdjuster.mCachedAppOptimizer.binderError(debugPid, app, code, flags, err);
+ }
++
++ @Override
++ public String[] getSystemIdmapPaths() {
++ // see comment in AssetManager#createSystemAssetsInZygoteLocked()
++ return android.content.res.AssetManager.systemIdmapPaths_;
++ }
+ }
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-15.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-15.patch
new file mode 100644
index 00000000..cb83859c
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-15.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Tue, 9 Apr 2024 14:06:27 +0300
+Subject: [PATCH] exec spawning: add workaround for late init of ART
+ userfaultfd GC
+
+Chromium browser and its derivatives setup a seccomp syscall filter in their isolated processes,
+which blocks creation of new userfaultfds.
+
+Since 14 QPR2, ART uses a new userfaultfd-based GC.
+
+When zygote-based process spawning is used, userfaultfd GC is initialized before any of app's code
+is executed, i.e. before Chromium's seccomp syscall filter is installed.
+
+When exec spawning is used, userfaultfd GC initialization is delayed until first garbage collection.
+Chromium's seccomp syscall filter is already installed at that point.
+
+This leads to crashes of isolated Chromium processes (both browser and WebView), with the following
+log messages:
+ E cr_seccomp: ../../sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc:**CRASHING**:seccomp-bpf failure in syscall
+ E cr_seccomp: nr=0x11a arg1=0x80001 arg2=0xc arg3=0xffffffffffffffff arg4=0xc
+
+As a workaround, perform early initialization of ART userfaultfd GC in isolated processes by calling
+System.gc() before executing app's code. On Pixel 8, this increases startup latency by around 4 to
+10 milliseconds.
+---
+ core/java/com/android/internal/os/ExecInit.java | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/core/java/com/android/internal/os/ExecInit.java b/core/java/com/android/internal/os/ExecInit.java
+index 39f08b6a0f15..b4b135cde18f 100644
+--- a/core/java/com/android/internal/os/ExecInit.java
++++ b/core/java/com/android/internal/os/ExecInit.java
+@@ -1,5 +1,6 @@
+ package com.android.internal.os;
+
++import android.os.Process;
+ import android.os.Trace;
+ import android.system.ErrnoException;
+ import android.system.Os;
+@@ -120,6 +121,9 @@ public class ExecInit {
+
+ // Perform the same initialization that would happen after the Zygote forks.
+ Zygote.nativePreApplicationInit();
++ if (Process.isIsolated()) {
++ System.gc();
++ }
+ return RuntimeInit.applicationInit(targetSdkVersion, /*disabledCompatChanges*/ null, argv, classLoader);
+ }
+ }
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-2.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-2.patch
new file mode 100644
index 00000000..74c0fb2a
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-2.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 21 May 2019 23:54:20 -0400
+Subject: [PATCH] disable exec spawning when using debugging options
+
+The debugging options are not yet supported probably, so disable exec
+spawning when doing debugging.
+---
+ core/java/com/android/internal/os/ZygoteConnection.java | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
+index 9e78c3a8b16c..cc936ccefb91 100644
+--- a/core/java/com/android/internal/os/ZygoteConnection.java
++++ b/core/java/com/android/internal/os/ZygoteConnection.java
+@@ -536,7 +536,8 @@ class ZygoteConnection {
+ throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
+ } else {
+ if (!isZygote) {
+- if (SystemProperties.getBoolean("sys.spawn.exec", false)) {
++ if (SystemProperties.getBoolean("sys.spawn.exec", false) &&
++ (parsedArgs.mRuntimeFlags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ ExecInit.execApplication(parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
+ VMRuntime.getCurrentInstructionSet(), parsedArgs.mRemainingArgs);
+
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-3.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-3.patch
new file mode 100644
index 00000000..e5c6fa6b
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-3.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 14 May 2019 14:24:21 -0400
+Subject: [PATCH] add parameter for avoiding full preload with exec
+
+---
+ core/java/com/android/internal/os/ExecInit.java | 2 +-
+ core/java/com/android/internal/os/ZygoteInit.java | 6 +++++-
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ExecInit.java b/core/java/com/android/internal/os/ExecInit.java
+index 2adcab7fdbe6..830e5b562a91 100644
+--- a/core/java/com/android/internal/os/ExecInit.java
++++ b/core/java/com/android/internal/os/ExecInit.java
+@@ -33,7 +33,7 @@ public class ExecInit {
+
+ // Mimic system Zygote preloading.
+ ZygoteInit.preload(new TimingsTraceLog("ExecInitTiming",
+- Trace.TRACE_TAG_DALVIK));
++ Trace.TRACE_TAG_DALVIK), false);
+
+ // Launch the application.
+ String[] runtimeArgs = new String[args.length - 1];
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 7af196513cae..1675d41580d6 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -122,7 +122,7 @@ public class ZygoteInit {
+ */
+ private static ClassLoader sCachedSystemServerClassLoader = null;
+
+- static void preload(TimingsTraceLog bootTimingsTraceLog) {
++ static void preload(TimingsTraceLog bootTimingsTraceLog, boolean fullPreload) {
+ Log.d(TAG, "begin preload");
+ bootTimingsTraceLog.traceBegin("BeginPreload");
+ beginPreload();
+@@ -154,6 +154,10 @@ public class ZygoteInit {
+ sPreloadComplete = true;
+ }
+
++ static void preload(TimingsTraceLog bootTimingsTraceLog) {
++ preload(bootTimingsTraceLog, true);
++ }
++
+ static void lazyPreload() {
+ Preconditions.checkState(!sPreloadComplete);
+ Log.i(TAG, "Lazily preloading resources.");
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-4.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-4.patch
new file mode 100644
index 00000000..36b6aae1
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-4.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 11 Sep 2019 06:43:55 -0400
+Subject: [PATCH] pass through fullPreload to libcore
+
+---
+ core/java/com/android/internal/os/ZygoteInit.java | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 1675d41580d6..87d393d97d14 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -125,7 +125,7 @@ public class ZygoteInit {
+ static void preload(TimingsTraceLog bootTimingsTraceLog, boolean fullPreload) {
+ Log.d(TAG, "begin preload");
+ bootTimingsTraceLog.traceBegin("BeginPreload");
+- beginPreload();
++ beginPreload(fullPreload);
+ bootTimingsTraceLog.traceEnd(); // BeginPreload
+ bootTimingsTraceLog.traceBegin("PreloadClasses");
+ preloadClasses();
+@@ -147,7 +147,7 @@ public class ZygoteInit {
+ // Ask the WebViewFactory to do any initialization that must run in the zygote process,
+ // for memory sharing purposes.
+ WebViewFactory.prepareWebViewInZygote();
+- endPreload();
++ endPreload(fullPreload);
+ warmUpJcaProviders();
+ Log.d(TAG, "end preload");
+
+@@ -165,14 +165,14 @@ public class ZygoteInit {
+ preload(new TimingsTraceLog("ZygoteInitTiming_lazy", Trace.TRACE_TAG_DALVIK));
+ }
+
+- private static void beginPreload() {
++ private static void beginPreload(boolean fullPreload) {
+ Log.i(TAG, "Calling ZygoteHooks.beginPreload()");
+
+- ZygoteHooks.onBeginPreload();
++ ZygoteHooks.onBeginPreload(fullPreload);
+ }
+
+- private static void endPreload() {
+- ZygoteHooks.onEndPreload();
++ private static void endPreload(boolean fullPreload) {
++ ZygoteHooks.onEndPreload(fullPreload);
+
+ Log.i(TAG, "Called ZygoteHooks.endPreload()");
+ }
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-5.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-5.patch
new file mode 100644
index 00000000..ad408e28
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-5.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 14 May 2019 14:28:27 -0400
+Subject: [PATCH] disable OpenGL preloading for exec spawning
+
+---
+ core/java/com/android/internal/os/ZygoteInit.java | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 87d393d97d14..f30e17183fca 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -139,9 +139,11 @@ public class ZygoteInit {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
+ nativePreloadAppProcessHALs();
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+- Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
+- maybePreloadGraphicsDriver();
+- Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
++ if (fullPreload) {
++ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
++ maybePreloadGraphicsDriver();
++ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
++ }
+ preloadSharedLibraries();
+ preloadTextResources();
+ // Ask the WebViewFactory to do any initialization that must run in the zygote process,
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-6.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-6.patch
new file mode 100644
index 00000000..373ed18d
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-6.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 14 May 2019 14:28:52 -0400
+Subject: [PATCH] disable resource preloading for exec spawning
+
+---
+ core/java/com/android/internal/os/ZygoteInit.java | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 87d393d97d14..5cd919d49014 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -133,9 +133,11 @@ public class ZygoteInit {
+ bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
+ cacheNonBootClasspathClassLoaders();
+ bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
+- bootTimingsTraceLog.traceBegin("PreloadResources");
+- Resources.preloadResources();
+- bootTimingsTraceLog.traceEnd(); // PreloadResources
++ if (fullPreload) {
++ bootTimingsTraceLog.traceBegin("PreloadResources");
++ Resources.preloadResources();
++ bootTimingsTraceLog.traceEnd(); // PreloadResources
++ }
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
+ nativePreloadAppProcessHALs();
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-7.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-7.patch
new file mode 100644
index 00000000..20396189
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-7.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 14 May 2019 14:30:59 -0400
+Subject: [PATCH] disable class preloading for exec spawning
+
+---
+ core/java/com/android/internal/os/ZygoteInit.java | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 5cd919d49014..21d412a3f9ec 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -127,9 +127,11 @@ public class ZygoteInit {
+ bootTimingsTraceLog.traceBegin("BeginPreload");
+ beginPreload(fullPreload);
+ bootTimingsTraceLog.traceEnd(); // BeginPreload
+- bootTimingsTraceLog.traceBegin("PreloadClasses");
+- preloadClasses();
+- bootTimingsTraceLog.traceEnd(); // PreloadClasses
++ if (fullPreload) {
++ bootTimingsTraceLog.traceBegin("PreloadClasses");
++ preloadClasses();
++ bootTimingsTraceLog.traceEnd(); // PreloadClasses
++ }
+ bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
+ cacheNonBootClasspathClassLoaders();
+ bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-8.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-8.patch
new file mode 100644
index 00000000..4e8b7382
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-8.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 14 May 2019 14:31:29 -0400
+Subject: [PATCH] disable WebView reservation for exec spawning
+
+---
+ core/java/com/android/internal/os/ZygoteInit.java | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 21d412a3f9ec..2ced52d06a17 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -148,9 +148,11 @@ public class ZygoteInit {
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ preloadSharedLibraries();
+ preloadTextResources();
+- // Ask the WebViewFactory to do any initialization that must run in the zygote process,
+- // for memory sharing purposes.
+- WebViewFactory.prepareWebViewInZygote();
++ if (fullPreload) {
++ // Ask the WebViewFactory to do any initialization that must run in the zygote process,
++ // for memory sharing purposes.
++ WebViewFactory.prepareWebViewInZygote();
++ }
+ endPreload(fullPreload);
+ warmUpJcaProviders();
+ Log.d(TAG, "end preload");
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-9.patch b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-9.patch
new file mode 100644
index 00000000..e1d7aa67
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0018-Exec_Based_Spawning-9.patch
@@ -0,0 +1,57 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Tue, 14 May 2019 14:34:32 -0400
+Subject: [PATCH] disable JCA provider warm up for exec spawning
+
+---
+ .../com/android/internal/os/ZygoteInit.java | 22 ++++++++++---------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
+index 2ced52d06a17..55c68981f919 100644
+--- a/core/java/com/android/internal/os/ZygoteInit.java
++++ b/core/java/com/android/internal/os/ZygoteInit.java
+@@ -154,7 +154,7 @@ public class ZygoteInit {
+ WebViewFactory.prepareWebViewInZygote();
+ }
+ endPreload(fullPreload);
+- warmUpJcaProviders();
++ warmUpJcaProviders(fullPreload);
+ Log.d(TAG, "end preload");
+
+ sPreloadComplete = true;
+@@ -223,7 +223,7 @@ public class ZygoteInit {
+ * By doing it here we avoid that each app does it when requesting a service from the provider
+ * for the first time.
+ */
+- private static void warmUpJcaProviders() {
++ private static void warmUpJcaProviders(boolean fullPreload) {
+ long startTime = SystemClock.uptimeMillis();
+ Trace.traceBegin(
+ Trace.TRACE_TAG_DALVIK, "Starting installation of AndroidKeyStoreProvider");
+@@ -233,15 +233,17 @@ public class ZygoteInit {
+ + (SystemClock.uptimeMillis() - startTime) + "ms.");
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+
+- startTime = SystemClock.uptimeMillis();
+- Trace.traceBegin(
+- Trace.TRACE_TAG_DALVIK, "Starting warm up of JCA providers");
+- for (Provider p : Security.getProviders()) {
+- p.warmUpServiceProvision();
++ if (fullPreload) {
++ startTime = SystemClock.uptimeMillis();
++ Trace.traceBegin(
++ Trace.TRACE_TAG_DALVIK, "Starting warm up of JCA providers");
++ for (Provider p : Security.getProviders()) {
++ p.warmUpServiceProvision();
++ }
++ Log.i(TAG, "Warmed up JCA providers in "
++ + (SystemClock.uptimeMillis() - startTime) + "ms.");
++ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
+- Log.i(TAG, "Warmed up JCA providers in "
+- + (SystemClock.uptimeMillis() - startTime) + "ms.");
+- Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
+
+ private static boolean isExperimentEnabled(String experiment) {
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0020-Location_Indicators.patch b/Patches/LineageOS-21.0/android_frameworks_base/0020-Location_Indicators.patch
new file mode 100644
index 00000000..c72d370a
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0020-Location_Indicators.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Danny Lin
+Date: Tue, 12 Oct 2021 01:03:59 +0300
+Subject: [PATCH] SystemUI: Use new privacy indicators for location
+
+Android has had location indicators for a while, but let's use the new
+privacy indicator infrastructure for displaying them. This makes them
+integrate better with the new camera and microphone indicators.
+
+Change-Id: Ie457bb2dad17bddbf9dc3a818e3ec586023ce918
+---
+ core/java/android/permission/PermissionUsageHelper.java | 2 +-
+ .../src/com/android/systemui/privacy/PrivacyItemController.kt | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
+index 1f798baf1bd6..20502cdc81c3 100644
+--- a/core/java/android/permission/PermissionUsageHelper.java
++++ b/core/java/android/permission/PermissionUsageHelper.java
+@@ -108,7 +108,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
+
+ private static boolean shouldShowLocationIndicator() {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+- PROPERTY_LOCATION_INDICATORS_ENABLED, false);
++ PROPERTY_LOCATION_INDICATORS_ENABLED, true);
+ }
+
+ private static long getRecentThreshold(Long now) {
+diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+index eb8ef9bf3e50..4b406f76300a 100644
+--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
++++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+@@ -63,7 +63,7 @@ class PrivacyItemController @Inject constructor(
+ val micCameraAvailable
+ get() = privacyConfig.micCameraAvailable
+ val locationAvailable
+- get() = privacyConfig.locationAvailable
++ get() = true
+ val allIndicatorsAvailable
+ get() = micCameraAvailable && locationAvailable && privacyConfig.mediaProjectionAvailable
+
+@@ -274,4 +274,4 @@ class PrivacyItemController @Inject constructor(
+ listeningCanceller = delegate.executeDelayed({ setListeningState() }, 0L)
+ }
+ }
+-}
+\ No newline at end of file
++}
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0022-Ignore_StatementService_ANR.patch b/Patches/LineageOS-21.0/android_frameworks_base/0022-Ignore_StatementService_ANR.patch
new file mode 100644
index 00000000..49cfca1d
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0022-Ignore_StatementService_ANR.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Micay
+Date: Wed, 20 Oct 2021 19:40:42 -0400
+Subject: [PATCH] core/config: [temporary] don't report statementservice
+ crashes
+
+There's a known issue in AOSP 12 caused by it creating overly large
+intents for the work manager. It's not caused by anything done by end
+users and they can't work around it so avoid reporting it to them since
+they get a message each time it tries again.
+---
+ core/res/res/values/config.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
+index 3bc33bac37bc..be714871ad0f 100644
+--- a/core/res/res/values/config.xml
++++ b/core/res/res/values/config.xml
+@@ -4211,7 +4211,7 @@
+
+
+-
++ com.android.statementservice
+
+
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0024-Burnin_Protection.patch b/Patches/LineageOS-21.0/android_frameworks_base/0024-Burnin_Protection.patch
new file mode 100644
index 00000000..098bbf62
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0024-Burnin_Protection.patch
@@ -0,0 +1,317 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Park Ju Hyung
+Date: Sun, 15 Jan 2017 03:33:04 +0900
+Subject: [PATCH] SystemUI: add burnIn protection
+
+Devices with AMOLED display suffer from
+status-bar's notification items and nagivation bar's software keys
+causing permanent burn-ins when used long-term.
+
+Moving all items in the area
+both horizontally and vertically workarounds this problem.
+
+jrizzoli: integrate with runtime cmsdk preference
+
+Linux4: Removed toggle from settings - the burnIn protection is always
+enabled if the corresponding AOSP overlay is set to true
+Updated for T
+
+Change-Id: I35b04d1edff86a556adb3ad349569e5d82653f16
+Signed-off-by: Park Ju Hyung
+Signed-off-by: Alex Naidis
+Signed-off-by: Thecrazyskull
+Signed-off-by: Joey Rizzoli
+---
+ .../SystemUI/res/values/lineage_dimens.xml | 3 +
+ .../navigationbar/NavigationBarView.java | 26 +++++
+ .../statusbar/phone/CentralSurfacesImpl.java | 14 +++
+ .../statusbar/phone/PhoneStatusBarView.java | 27 +++++
+ .../policy/BurnInProtectionController.java | 105 ++++++++++++++++++
+ 5 files changed, 175 insertions(+)
+ create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/BurnInProtectionController.java
+
+diff --git a/packages/SystemUI/res/values/lineage_dimens.xml b/packages/SystemUI/res/values/lineage_dimens.xml
+index ca6e7db4c5b1..c0acba502cc2 100644
+--- a/packages/SystemUI/res/values/lineage_dimens.xml
++++ b/packages/SystemUI/res/values/lineage_dimens.xml
+@@ -24,4 +24,7 @@
+
+
+ 48dp
++
++ 3dp
++ 1dp
+
+diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+index aae1aa9a6698..90bcd525b32f 100644
+--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
++++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+@@ -159,6 +159,13 @@ public class NavigationBarView extends FrameLayout {
+ private FloatingRotationButton mFloatingRotationButton;
+ private RotationButtonController mRotationButtonController;
+
++ private int mBasePaddingBottom;
++ private int mBasePaddingLeft;
++ private int mBasePaddingRight;
++ private int mBasePaddingTop;
++
++ private ViewGroup mNavigationBarContents;
++
+ /**
+ * Helper that is responsible for showing the right toast when a disallowed activity operation
+ * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
+@@ -889,12 +896,31 @@ public class NavigationBarView extends FrameLayout {
+ mContextualButtonGroup.setButtonVisibility(R.id.accessibility_button, visible);
+ }
+
++ public void shiftNavigationBarItems(int horizontalShift, int verticalShift) {
++ if (mNavigationBarContents == null) {
++ return;
++ }
++
++ mNavigationBarContents.setPaddingRelative(mBasePaddingLeft + horizontalShift,
++ mBasePaddingTop + verticalShift,
++ mBasePaddingRight + horizontalShift,
++ mBasePaddingBottom - verticalShift);
++ invalidate();
++ }
++
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ mNavigationInflaterView = findViewById(R.id.navigation_inflater);
+ mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
+
++
++ mNavigationBarContents = (ViewGroup) findViewById(R.id.nav_buttons);
++
++ mBasePaddingLeft = mNavigationBarContents.getPaddingStart();
++ mBasePaddingTop = mNavigationBarContents.getPaddingTop();
++ mBasePaddingRight = mNavigationBarContents.getPaddingEnd();
++ mBasePaddingBottom = mNavigationBarContents.getPaddingBottom();
+ updateOrientationViews();
+ reloadNavIcons();
+ }
+diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+index 73b95114b005..b943444676f6 100644
+--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+@@ -216,6 +216,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
+ import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
+ import com.android.systemui.statusbar.policy.BatteryController;
+ import com.android.systemui.statusbar.policy.BrightnessMirrorController;
++import com.android.systemui.statusbar.policy.BurnInProtectionController;
+ import com.android.systemui.statusbar.policy.ConfigurationController;
+ import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+ import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+@@ -379,6 +380,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
+ private BiometricUnlockController mBiometricUnlockController;
+ private final LightBarController mLightBarController;
+ private final AutoHideController mAutoHideController;
++ private BurnInProtectionController mBurnInProtectionController;
+
+ private final Point mCurrentDisplaySize = new Point();
+
+@@ -1223,6 +1225,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
+ mShadeSurface.updateExpansionAndVisibility();
+ setBouncerShowingForStatusBarComponents(mBouncerShowing);
+ checkBarModes();
++
++ if (mContext.getResources().getBoolean(
++ com.android.internal.R.bool.config_enableBurnInProtection)) {
++ mBurnInProtectionController = new BurnInProtectionController(mContext,
++ this, mStatusBarView);
++ }
+ });
+ mStatusBarInitializer.initializeStatusBar();
+
+@@ -2494,6 +2502,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
+
+ updateNotificationPanelTouchState();
+ getNotificationShadeWindowViewController().cancelCurrentTouch();
++ if (mBurnInProtectionController != null) {
++ mBurnInProtectionController.stopShiftTimer(true);
++ }
+ if (mLaunchCameraOnFinishedGoingToSleep) {
+ mLaunchCameraOnFinishedGoingToSleep = false;
+
+@@ -2659,6 +2670,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
+ }
+ }
+ updateScrimController();
++ if (mBurnInProtectionController != null) {
++ mBurnInProtectionController.startShiftTimer(true);
++ }
+ }
+ };
+
+diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+index 1207388b4389..3015dfa7768f 100644
+--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
++++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
+
+ import android.annotation.Nullable;
+ import android.content.Context;
++import android.content.res.Resources;
+ import android.content.res.Configuration;
+ import android.graphics.Insets;
+ import android.graphics.Rect;
+@@ -65,6 +66,13 @@ public class PhoneStatusBarView extends FrameLayout implements Callbacks {
+ private final CommandQueue mCommandQueue;
+ private final StatusBarContentInsetsProvider mContentInsetsProvider;
+
++ private int mBasePaddingBottom;
++ private int mBasePaddingLeft;
++ private int mBasePaddingRight;
++ private int mBasePaddingTop;
++
++ private ViewGroup mStatusBarContents;
++
+ private DarkReceiver mBattery;
+ private ClockController mClockController;
+ private int mRotationOrientation = -1;
+@@ -143,6 +151,18 @@ public class PhoneStatusBarView extends FrameLayout implements Callbacks {
+ StatusBarUserChipViewBinder.bind(container, viewModel);
+ }
+
++ public void shiftStatusBarItems(int horizontalShift, int verticalShift) {
++ if (mStatusBarContents == null) {
++ return;
++ }
++
++ mStatusBarContents.setPaddingRelative(mBasePaddingLeft + horizontalShift,
++ mBasePaddingTop + verticalShift,
++ mBasePaddingRight + horizontalShift,
++ mBasePaddingBottom - verticalShift);
++ invalidate();
++ }
++
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+@@ -150,6 +170,13 @@ public class PhoneStatusBarView extends FrameLayout implements Callbacks {
+ mClockController = new ClockController(getContext(), this);
+ mCutoutSpace = findViewById(R.id.cutout_space_view);
+
++ mStatusBarContents = (ViewGroup) findViewById(R.id.status_bar_contents);
++
++ mBasePaddingLeft = mStatusBarContents.getPaddingStart();
++ mBasePaddingTop = mStatusBarContents.getPaddingTop();
++ mBasePaddingRight = mStatusBarContents.getPaddingEnd();
++ mBasePaddingBottom = mStatusBarContents.getPaddingBottom();
++
+ updateResources();
+ }
+
+diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BurnInProtectionController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BurnInProtectionController.java
+new file mode 100644
+index 000000000000..864d86ffd6a3
+--- /dev/null
++++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BurnInProtectionController.java
+@@ -0,0 +1,105 @@
++/*
++ * Copyright 2017 Paranoid Android
++ * Copyright 2020 The LineageOS Project
++ *
++ * 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.systemui.statusbar.policy;
++
++import android.content.Context;
++import android.content.res.Resources;
++import android.os.Handler;
++import android.os.Looper;
++import android.util.Log;
++
++import com.android.systemui.R;
++import com.android.systemui.navigationbar.NavigationBarView;
++import com.android.systemui.statusbar.phone.PhoneStatusBarView;
++import com.android.systemui.statusbar.phone.CentralSurfacesImpl;
++
++public class BurnInProtectionController {
++ private static final String TAG = "BurnInProtectionController";
++ private static final boolean DEBUG = false;
++ private static final long INTERVAL = 60000; // Milliseconds
++
++ private int mHorizontalShift = 0;
++ private int mVerticalShift = 0;
++ private int mHorizontalDirection = 1;
++ private int mVerticalDirection = 1;
++ private int mNavigationBarHorizontalMaxShift;
++ private int mNavigationBarVerticalMaxShift;
++ private int mHorizontalMaxShift;
++ private int mVerticalMaxShift;
++ private long mShiftInterval;
++
++ private final Handler mHandler = new Handler();
++ private final Runnable mRunnable = () -> {
++ shiftItems();
++ mHandler.postDelayed(this.mRunnable, INTERVAL);
++ };
++
++ private PhoneStatusBarView mPhoneStatusBarView;
++ private CentralSurfacesImpl mStatusBar;
++
++ private Context mContext;
++
++ public BurnInProtectionController(Context context, CentralSurfacesImpl statusBar,
++ PhoneStatusBarView phoneStatusBarView) {
++ mContext = context;
++
++ mPhoneStatusBarView = phoneStatusBarView;
++ mStatusBar = statusBar;
++
++ mHorizontalMaxShift = mContext.getResources()
++ .getDimensionPixelSize(R.dimen.burnin_protection_horizontal_shift);
++ // total of ((vertical_max_shift - 1) * 2) pixels can be moved
++ mVerticalMaxShift = mContext.getResources()
++ .getDimensionPixelSize(R.dimen.burnin_protection_vertical_shift) - 1;
++ }
++
++ public void startShiftTimer(boolean enabled) {
++ if (!enabled) return;
++ mHandler.removeCallbacks(mRunnable);
++ mHandler.postDelayed(mRunnable, INTERVAL);
++ if (DEBUG) Log.d(TAG, "Started shift timer");
++ }
++
++ public void stopShiftTimer(boolean enabled) {
++ if (!enabled) return;
++ mHandler.removeCallbacks(mRunnable);
++ if (DEBUG) Log.d(TAG, "Canceled shift timer");
++ }
++
++ private void shiftItems() {
++ mHorizontalShift += mHorizontalDirection;
++ if ((mHorizontalShift >= mHorizontalMaxShift) ||
++ (mHorizontalShift <= -mHorizontalMaxShift)) {
++ mHorizontalDirection *= -1;
++ }
++
++ mVerticalShift += mVerticalDirection;
++ if ((mVerticalShift >= mVerticalMaxShift) ||
++ (mVerticalShift <= -mVerticalMaxShift)) {
++ mVerticalDirection *= -1;
++ }
++
++ mPhoneStatusBarView.shiftStatusBarItems(mHorizontalShift, mVerticalShift);
++ NavigationBarView navigationBarView = mStatusBar.getNavigationBarView();
++
++ if (navigationBarView != null) {
++ navigationBarView.shiftNavigationBarItems(mHorizontalShift, mVerticalShift);
++ }
++ if (DEBUG) Log.d(TAG, "Shifting items\u2026");
++ }
++}
diff --git a/Patches/LineageOS-21.0/android_frameworks_base/0026-Crash_Details.patch b/Patches/LineageOS-21.0/android_frameworks_base/0026-Crash_Details.patch
new file mode 100644
index 00000000..f526f42c
--- /dev/null
+++ b/Patches/LineageOS-21.0/android_frameworks_base/0026-Crash_Details.patch
@@ -0,0 +1,194 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dmitry Muhomor
+Date: Mon, 8 Aug 2022 19:03:37 +0300
+Subject: [PATCH] add an option to show the details of an application error to
+ the user
+
+Adds a "Show details" item to crash and ANR (app not responding) dialogs that takes the user to a
+SystemUI activity which shows the error details and allows to copy them to the clipboard or to
+export them via the standard sharing UI.
+---
+ .../android/app/ApplicationErrorReport.java | 29 +++++++++++++++++--
+ core/res/res/layout/app_anr_dialog.xml | 4 +--
+ core/res/res/layout/app_error_dialog.xml | 4 +--
+ core/res/res/values/strings.xml | 2 ++
+ core/res/res/values/symbols.xml | 3 ++
+ .../java/com/android/server/am/AppErrors.java | 1 +
+ 6 files changed, 37 insertions(+), 6 deletions(-)
+
+diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
+index 9cea5e8ef4cf..a8f51104d0fa 100644
+--- a/core/java/android/app/ApplicationErrorReport.java
++++ b/core/java/android/app/ApplicationErrorReport.java
+@@ -25,6 +25,8 @@ import android.content.pm.ResolveInfo;
+ import android.os.Binder;
+ import android.os.Parcel;
+ import android.os.Parcelable;
++import android.os.Process;
++import android.os.SystemClock;
+ import android.os.SystemProperties;
+ import android.provider.Settings;
+ import android.util.Printer;
+@@ -98,6 +100,9 @@ public class ApplicationErrorReport implements Parcelable {
+ */
+ public String packageName;
+
++ /** @hide */
++ public long packageVersion;
++
+ /**
+ * Package name of the application which installed the application this
+ * report pertains to.
+@@ -162,13 +167,19 @@ public class ApplicationErrorReport implements Parcelable {
+ String packageName, int appFlags) {
+ // check if error reporting is enabled in secure settings
+ int enabled = Settings.Global.getInt(context.getContentResolver(),
+- Settings.Global.SEND_ACTION_APP_ERROR, 0);
++ Settings.Global.SEND_ACTION_APP_ERROR, 1);
+ if (enabled == 0) {
+ return null;
+ }
+
+ PackageManager pm = context.getPackageManager();
+
++ ComponentName logViewerApp = getErrorReportReceiver(pm, packageName,
++ android.ext.LogViewerApp.getPackageName());
++ if (logViewerApp != null) {
++ return logViewerApp;
++ }
++
+ // look for receiver in the installer package
+ String candidate = null;
+ ComponentName result = null;
+@@ -233,6 +244,7 @@ public class ApplicationErrorReport implements Parcelable {
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(type);
+ dest.writeString(packageName);
++ dest.writeLong(packageVersion);
+ dest.writeString(installerPackageName);
+ dest.writeString(processName);
+ dest.writeLong(time);
+@@ -260,6 +272,7 @@ public class ApplicationErrorReport implements Parcelable {
+ public void readFromParcel(Parcel in) {
+ type = in.readInt();
+ packageName = in.readString();
++ packageVersion = in.readLong();
+ installerPackageName = in.readString();
+ processName = in.readString();
+ time = in.readLong();
+@@ -345,6 +358,11 @@ public class ApplicationErrorReport implements Parcelable {
+ */
+ public String crashTag;
+
++ /** @hide */
++ public long processUptimeMs;
++ /** @hide */
++ public long processStartupLatencyMs;
++
+ /**
+ * Create an uninitialized instance of CrashInfo.
+ */
+@@ -398,6 +416,9 @@ public class ApplicationErrorReport implements Parcelable {
+ }
+
+ exceptionMessage = sanitizeString(exceptionMessage);
++
++ processUptimeMs = SystemClock.elapsedRealtime() - Process.getStartElapsedRealtime();
++ processStartupLatencyMs = Process.getStartElapsedRealtime() - Process.getStartRequestedElapsedRealtime();
+ }
+
+ /** {@hide} */
+@@ -439,6 +460,8 @@ public class ApplicationErrorReport implements Parcelable {
+ throwLineNumber = in.readInt();
+ stackTrace = in.readString();
+ crashTag = in.readString();
++ processUptimeMs = in.readLong();
++ processStartupLatencyMs = in.readLong();
+ }
+
+ /**
+@@ -455,6 +478,8 @@ public class ApplicationErrorReport implements Parcelable {
+ dest.writeInt(throwLineNumber);
+ dest.writeString(stackTrace);
+ dest.writeString(crashTag);
++ dest.writeLong(processUptimeMs);
++ dest.writeLong(processStartupLatencyMs);
+ int total = dest.dataPosition()-start;
+ if (Binder.CHECK_PARCEL_SIZE && total > 20*1024) {
+ Slog.d("Error", "ERR: exHandler=" + exceptionHandlerClassName);
+@@ -704,7 +729,7 @@ public class ApplicationErrorReport implements Parcelable {
+ */
+ public void dump(Printer pw, String prefix) {
+ pw.println(prefix + "type: " + type);
+- pw.println(prefix + "packageName: " + packageName);
++ pw.println(prefix + "packageName: " + packageName + ":" + packageVersion);
+ pw.println(prefix + "installerPackageName: " + installerPackageName);
+ pw.println(prefix + "processName: " + processName);
+ pw.println(prefix + "time: " + time);
+diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml
+index 5ad0f4c0f6cc..ad3a2d2991de 100644
+--- a/core/res/res/layout/app_anr_dialog.xml
++++ b/core/res/res/layout/app_anr_dialog.xml
+@@ -41,8 +41,8 @@
+ android:id="@+id/aerr_report"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+- android:text="@string/aerr_report"
+- android:drawableStart="@drawable/ic_feedback"
++ android:text="@string/aerr_show_details"
++ android:drawableStart="@drawable/ic_info_outline_24"
+ style="@style/aerr_list_item" />
+
+
+diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
+index c3b149a1e295..a47b82018377 100644
+--- a/core/res/res/layout/app_error_dialog.xml
++++ b/core/res/res/layout/app_error_dialog.xml
+@@ -52,8 +52,8 @@
+ android:id="@+id/aerr_report"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+- android:text="@string/aerr_report"
+- android:drawableStart="@drawable/ic_feedback"
++ android:text="@string/aerr_show_details"
++ android:drawableStart="@drawable/ic_info_outline_24"
+ style="@style/aerr_list_item" />
+
+