summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ravenwood/runtime-jni/ravenwood_runtime.cpp20
-rw-r--r--services/core/java/com/android/server/audio/LoudnessCodecHelper.java32
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java12
-rw-r--r--tools/systemfeatures/Android.bp1
-rw-r--r--tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt34
-rw-r--r--tools/systemfeatures/tests/src/SystemFeaturesGeneratorApiTest.java81
6 files changed, 164 insertions, 16 deletions
diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp
index 3ff08483c956..2a3c26ed3ea3 100644
--- a/ravenwood/runtime-jni/ravenwood_runtime.cpp
+++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp
@@ -173,6 +173,24 @@ static void Linux_setenv(JNIEnv* env, jobject, jstring javaName, jstring javaVal
throwIfMinusOne(env, "setenv", setenv(name.c_str(), value.c_str(), overwrite ? 1 : 0));
}
+static void maybeRedirectLog() {
+ auto ravenwoodLogOut = getenv("RAVENWOOD_LOG_OUT");
+ if (ravenwoodLogOut == NULL) {
+ return;
+ }
+ ALOGI("RAVENWOOD_LOG_OUT set. Redirecting output to %s", ravenwoodLogOut);
+
+ // Redirect stdin / stdout to /dev/tty.
+ int ttyFd = open(ravenwoodLogOut, O_WRONLY);
+ if (ttyFd == -1) {
+ ALOGW("$RAVENWOOD_LOG_OUT is set to %s, but failed to open: %s ", ravenwoodLogOut,
+ strerror(errno));
+ return;
+ }
+ dup2(ttyFd, 1);
+ dup2(ttyFd, 2);
+}
+
// ---- Registration ----
extern void register_android_system_OsConstants(JNIEnv* env);
@@ -192,6 +210,8 @@ static const JNINativeMethod sMethods[] =
};
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
+ maybeRedirectLog();
+
ALOGI("%s: JNI_OnLoad", __FILE__);
JNIEnv* env = GetJNIEnvOrDie(vm);
diff --git a/services/core/java/com/android/server/audio/LoudnessCodecHelper.java b/services/core/java/com/android/server/audio/LoudnessCodecHelper.java
index 01f770b1e89f..9fa5da47aae7 100644
--- a/services/core/java/com/android/server/audio/LoudnessCodecHelper.java
+++ b/services/core/java/com/android/server/audio/LoudnessCodecHelper.java
@@ -133,6 +133,9 @@ public class LoudnessCodecHelper {
private static final EventLogger sLogger = new EventLogger(
AudioService.LOG_NB_EVENTS_LOUDNESS_CODEC, "Loudness updates");
+ private final Object mDispatcherLock = new Object();
+
+ @GuardedBy("mDispatcherLock")
private final LoudnessRemoteCallbackList mLoudnessUpdateDispatchers =
new LoudnessRemoteCallbackList(this);
@@ -339,12 +342,16 @@ public class LoudnessCodecHelper {
}
void registerLoudnessCodecUpdatesDispatcher(ILoudnessCodecUpdatesDispatcher dispatcher) {
- mLoudnessUpdateDispatchers.register(dispatcher, Binder.getCallingPid());
+ synchronized (mDispatcherLock) {
+ mLoudnessUpdateDispatchers.register(dispatcher, Binder.getCallingPid());
+ }
}
void unregisterLoudnessCodecUpdatesDispatcher(
ILoudnessCodecUpdatesDispatcher dispatcher) {
- mLoudnessUpdateDispatchers.unregister(dispatcher);
+ synchronized (mDispatcherLock) {
+ mLoudnessUpdateDispatchers.unregister(dispatcher);
+ }
}
void startLoudnessCodecUpdates(int sessionId) {
@@ -640,17 +647,20 @@ public class LoudnessCodecHelper {
Log.d(TAG,
"dispatchNewLoudnessParameters: sessionId " + sessionId + " bundle: " + bundle);
}
- final int nbDispatchers = mLoudnessUpdateDispatchers.beginBroadcast();
- for (int i = 0; i < nbDispatchers; ++i) {
- try {
- mLoudnessUpdateDispatchers.getBroadcastItem(i)
- .dispatchLoudnessCodecParameterChange(sessionId, bundle);
- } catch (RemoteException e) {
- Log.e(TAG, "Error dispatching for sessionId " + sessionId + " bundle: " + bundle,
- e);
+ synchronized (mDispatcherLock) {
+ final int nbDispatchers = mLoudnessUpdateDispatchers.beginBroadcast();
+ for (int i = 0; i < nbDispatchers; ++i) {
+ try {
+ mLoudnessUpdateDispatchers.getBroadcastItem(i)
+ .dispatchLoudnessCodecParameterChange(sessionId, bundle);
+ } catch (RemoteException e) {
+ Log.e(TAG,
+ "Error dispatching for sessionId " + sessionId + " bundle: " + bundle,
+ e);
+ }
}
+ mLoudnessUpdateDispatchers.finishBroadcast();
}
- mLoudnessUpdateDispatchers.finishBroadcast();
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 45885f0399c4..c314ab06fbad 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -347,6 +347,8 @@ public class LockSettingsService extends ILockSettings.Stub {
private final StorageManagerInternal mStorageManagerInternal;
+ private final Object mGcWorkToken = new Object();
+
// This class manages life cycle events for encrypted users on File Based Encryption (FBE)
// devices. The most basic of these is to show/hide notifications about missing features until
// the user unlocks the account and credential-encrypted storage is available.
@@ -3632,11 +3634,19 @@ public class LockSettingsService extends ILockSettings.Stub {
* release references to the argument.
*/
private void scheduleGc() {
+ // Cancel any existing GC request first, so that GC requests don't pile up if lockscreen
+ // credential operations are happening very quickly, e.g. as sometimes happens during tests.
+ //
+ // This delays the already-requested GC, but that is fine in practice where lockscreen
+ // operations don't happen very quickly. And the precise time that the sanitization happens
+ // isn't very important; doing it within a minute can be fine, for example.
+ mHandler.removeCallbacksAndMessages(mGcWorkToken);
+
mHandler.postDelayed(() -> {
System.gc();
System.runFinalization();
System.gc();
- }, 2000);
+ }, mGcWorkToken, 2000);
}
private class DeviceProvisionedObserver extends ContentObserver {
diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp
index 590f7190881a..e6d0a3d4149f 100644
--- a/tools/systemfeatures/Android.bp
+++ b/tools/systemfeatures/Android.bp
@@ -58,6 +58,7 @@ java_test_host {
"junit",
"objenesis",
"mockito",
+ "systemfeatures-gen-lib",
"truth",
],
}
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
index 196b5e7c02ab..1abe77fd3ceb 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -71,7 +71,7 @@ object SystemFeaturesGenerator {
println("Usage: SystemFeaturesGenerator <outputClassName> [options]")
println(" Options:")
println(" --readonly=true|false Whether to encode features as build-time constants")
- println(" --feature=\$NAME:\$VER A feature+version pair, where \$VER can be:")
+ println(" --feature=\$NAME:\$VER A feature+version pair, where \$VER can be:")
println(" * blank/empty == undefined (variable API)")
println(" * valid int == enabled (constant API)")
println(" * UNAVAILABLE == disabled (constant API)")
@@ -89,6 +89,17 @@ object SystemFeaturesGenerator {
/** Main entrypoint for build-time system feature codegen. */
@JvmStatic
fun main(args: Array<String>) {
+ generate(args, System.out)
+ }
+
+ /**
+ * Simple API entrypoint for build-time system feature codegen.
+ *
+ * Note: Typically this would be implemented in terms of a proper Builder-type input argument,
+ * but it's primarily used for testing as opposed to direct production usage.
+ */
+ @JvmStatic
+ fun generate(args: Array<String>, output: Appendable) {
if (args.size < 1) {
usage()
return
@@ -155,7 +166,7 @@ object SystemFeaturesGenerator {
.addFileComment("This file is auto-generated. DO NOT MODIFY.\n")
.addFileComment("Args: ${args.joinToString(" \\\n ")}")
.build()
- .writeTo(System.out)
+ .writeTo(output)
}
/*
@@ -171,12 +182,27 @@ object SystemFeaturesGenerator {
return when (featureArgs.getOrNull(1)) {
null, "" -> FeatureInfo(name, null, readonly = false)
"UNAVAILABLE" -> FeatureInfo(name, null, readonly = true)
- else -> FeatureInfo(name, featureArgs[1].toIntOrNull(), readonly = true)
+ else -> {
+ val featureVersion =
+ featureArgs[1].toIntOrNull()
+ ?: throw IllegalArgumentException(
+ "Invalid feature version input for $name: ${featureArgs[1]}"
+ )
+ FeatureInfo(name, featureArgs[1].toInt(), readonly = true)
+ }
}
}
private fun parseFeatureName(name: String): String =
- if (name.startsWith("FEATURE_")) name else "FEATURE_$name"
+ when {
+ name.startsWith("android") ->
+ throw IllegalArgumentException(
+ "Invalid feature name input: \"android\"-namespaced features must be " +
+ "provided as PackageManager.FEATURE_* suffixes, not raw feature strings."
+ )
+ name.startsWith("FEATURE_") -> name
+ else -> "FEATURE_$name"
+ }
/*
* Adds per-feature query methods to the class with the form:
diff --git a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorApiTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorApiTest.java
new file mode 100644
index 000000000000..f8c585d60ef7
--- /dev/null
+++ b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorApiTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+package com.android.systemfeatures;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.io.IOException;
+
+// Note: This is a very simple argument test to validate certain behaviors for
+// invalid arguments. Correctness and validity is largely exercised by
+// SystemFeaturesGeneratorTest.
+@RunWith(JUnit4.class)
+public class SystemFeaturesGeneratorApiTest {
+
+ @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock private Appendable mOut;
+
+ @Test
+ public void testEmpty() throws IOException {
+ final String[] args = new String[] {};
+ // This should just print the commandline and return.
+ SystemFeaturesGenerator.generate(args, mOut);
+ verify(mOut, never()).append(any());
+ }
+
+ @Test
+ public void testBasic() throws IOException {
+ final String[] args = new String[] {
+ "com.foo.Features",
+ "--feature=TELEVISION:0",
+ };
+ SystemFeaturesGenerator.generate(args, mOut);
+ verify(mOut, atLeastOnce()).append(any());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidFeatureVersion() throws IOException {
+ final String[] args = new String[] {
+ "com.foo.Features",
+ "--feature=TELEVISION:blarg",
+ };
+ SystemFeaturesGenerator.generate(args, mOut);
+ verify(mOut, never()).append(any());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidFeatureNameFromAndroidNamespace() throws IOException {
+ final String[] args = new String[] {
+ "com.foo.Features",
+ "--feature=android.hardware.doesntexist:0",
+ };
+ SystemFeaturesGenerator.generate(args, mOut);
+ verify(mOut, never()).append(any());
+ }
+}