Merge "Use waitForDeclaredService to get Lights HAL" into rvc-dev am: 137f875360 am: ced1535de3 am: e7500cfb90 am: 49e1a1c409
Change-Id: Ide4efc77c26df4f8ab98c03d9dba0d86550b8ca1
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.os;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
@@ -218,6 +219,44 @@ public final class ServiceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified service is declared.
|
||||
*
|
||||
* @return true if the service is declared somewhere (eg. VINTF manifest) and
|
||||
* waitForService should always be able to return the service.
|
||||
*/
|
||||
public static boolean isDeclared(@NonNull String name) {
|
||||
try {
|
||||
return getIServiceManager().isDeclared(name);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "error in isDeclared", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified service from the service manager.
|
||||
*
|
||||
* If the service is not running, servicemanager will attempt to start it, and this function
|
||||
* will wait for it to be ready.
|
||||
*
|
||||
* @return {@code null} only if there are permission problems or fatal errors.
|
||||
*/
|
||||
public static native IBinder waitForService(@NonNull String name);
|
||||
|
||||
/**
|
||||
* Returns the specified service from the service manager, if declared.
|
||||
*
|
||||
* If the service is not running, servicemanager will attempt to start it, and this function
|
||||
* will wait for it to be ready.
|
||||
*
|
||||
* @return {@code null} if the service is not declared in the manifest, or if there are
|
||||
* permission problems, or if there are fatal errors.
|
||||
*/
|
||||
public static IBinder waitForDeclaredService(@NonNull String name) {
|
||||
return isDeclared(name) ? waitForService(name) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all currently running services.
|
||||
* @return an array of all currently running services, or <code>null</code> in
|
||||
|
||||
@@ -87,7 +87,7 @@ class ServiceManagerProxy implements IServiceManager {
|
||||
}
|
||||
|
||||
public boolean isDeclared(String name) throws RemoteException {
|
||||
throw new RemoteException();
|
||||
return mServiceManager.isDeclared(name);
|
||||
}
|
||||
|
||||
public void registerClientCallback(String name, IBinder service, IClientCallback cb)
|
||||
|
||||
@@ -123,6 +123,7 @@ cc_library_shared {
|
||||
"android_os_MessageQueue.cpp",
|
||||
"android_os_Parcel.cpp",
|
||||
"android_os_SELinux.cpp",
|
||||
"android_os_ServiceManager.cpp",
|
||||
"android_os_SharedMemory.cpp",
|
||||
"android_os_storage_StorageManager.cpp",
|
||||
"android_os_UEventObserver.cpp",
|
||||
|
||||
@@ -136,6 +136,7 @@ extern int register_android_os_HwBlob(JNIEnv *env);
|
||||
extern int register_android_os_HwParcel(JNIEnv *env);
|
||||
extern int register_android_os_HwRemoteBinder(JNIEnv *env);
|
||||
extern int register_android_os_NativeHandle(JNIEnv *env);
|
||||
extern int register_android_os_ServiceManager(JNIEnv *env);
|
||||
extern int register_android_os_MessageQueue(JNIEnv* env);
|
||||
extern int register_android_os_Parcel(JNIEnv* env);
|
||||
extern int register_android_os_SELinux(JNIEnv* env);
|
||||
@@ -1461,6 +1462,7 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_os_HwParcel),
|
||||
REG_JNI(register_android_os_HwRemoteBinder),
|
||||
REG_JNI(register_android_os_NativeHandle),
|
||||
REG_JNI(register_android_os_ServiceManager),
|
||||
REG_JNI(register_android_os_storage_StorageManager),
|
||||
REG_JNI(register_android_os_VintfObject),
|
||||
REG_JNI(register_android_os_VintfRuntimeInfo),
|
||||
|
||||
71
core/jni/android_os_ServiceManager.cpp
Normal file
71
core/jni/android_os_ServiceManager.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 "ServiceManager"
|
||||
//#define LOG_NDEBUG 0
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
|
||||
#include "android_util_Binder.h"
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// Native because we have a client-side wait in waitForService() and we do not
|
||||
// want an unnecessary second copy of it.
|
||||
static jobject android_os_ServiceManager_waitForService(
|
||||
JNIEnv *env,
|
||||
jclass /* clazzObj */,
|
||||
jstring serviceNameObj) {
|
||||
|
||||
const jchar* serviceName = env->GetStringCritical(serviceNameObj, nullptr);
|
||||
if (!serviceName) {
|
||||
jniThrowNullPointerException(env, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
String16 nameCopy = String16(reinterpret_cast<const char16_t *>(serviceName),
|
||||
env->GetStringLength(serviceNameObj));
|
||||
env->ReleaseStringCritical(serviceNameObj, serviceName);
|
||||
|
||||
sp<IBinder> service = defaultServiceManager()->waitForService(nameCopy);
|
||||
|
||||
if (!service) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return javaObjectForIBinder(env, service);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod method_table[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{
|
||||
"waitForService",
|
||||
"(Ljava/lang/String;)Landroid/os/IBinder;",
|
||||
(void*)android_os_ServiceManager_waitForService
|
||||
},
|
||||
};
|
||||
|
||||
int register_android_os_ServiceManager(JNIEnv* env) {
|
||||
return RegisterMethodsOrDie(
|
||||
env, "android/os/ServiceManager", method_table, NELEM(method_table));
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
@@ -25,6 +25,7 @@ import android.hardware.light.ILights;
|
||||
import android.hardware.lights.ILightsManager;
|
||||
import android.hardware.lights.Light;
|
||||
import android.hardware.lights.LightState;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
@@ -37,16 +38,17 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import com.android.internal.BrightnessSynchronizer;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.BrightnessSynchronizer;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LightsService extends SystemService {
|
||||
static final String TAG = "LightsService";
|
||||
@@ -55,7 +57,8 @@ public class LightsService extends SystemService {
|
||||
private final LightImpl[] mLightsByType = new LightImpl[LightsManager.LIGHT_ID_COUNT];
|
||||
private final SparseArray<LightImpl> mLightsById = new SparseArray<>();
|
||||
|
||||
private ILights mVintfLights = null;
|
||||
@Nullable
|
||||
private final Supplier<ILights> mVintfLights;
|
||||
|
||||
@VisibleForTesting
|
||||
final LightsManagerBinderService mManagerService;
|
||||
@@ -391,7 +394,7 @@ public class LightsService extends SystemService {
|
||||
lightState.flashOnMs = onMS;
|
||||
lightState.flashOffMs = offMS;
|
||||
lightState.brightnessMode = (byte) brightnessMode;
|
||||
mVintfLights.setLightState(mHwLight.id, lightState);
|
||||
mVintfLights.get().setLightState(mHwLight.id, lightState);
|
||||
} else {
|
||||
setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
|
||||
}
|
||||
@@ -435,19 +438,17 @@ public class LightsService extends SystemService {
|
||||
}
|
||||
|
||||
public LightsService(Context context) {
|
||||
this(context,
|
||||
ILights.Stub.asInterface(
|
||||
ServiceManager.getService("android.hardware.light.ILights/default")),
|
||||
Looper.myLooper());
|
||||
this(context, new VintfHalCache(), Looper.myLooper());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
LightsService(Context context, ILights service, Looper looper) {
|
||||
LightsService(Context context, Supplier<ILights> service, Looper looper) {
|
||||
super(context);
|
||||
mH = new Handler(looper);
|
||||
mVintfLights = service;
|
||||
mManagerService = new LightsManagerBinderService();
|
||||
mVintfLights = service.get() != null ? service : null;
|
||||
|
||||
populateAvailableLights(context);
|
||||
mManagerService = new LightsManagerBinderService();
|
||||
}
|
||||
|
||||
private void populateAvailableLights(Context context) {
|
||||
@@ -467,7 +468,7 @@ public class LightsService extends SystemService {
|
||||
|
||||
private void populateAvailableLightsFromAidl(Context context) {
|
||||
try {
|
||||
for (HwLight hwLight : mVintfLights.getLights()) {
|
||||
for (HwLight hwLight : mVintfLights.get().getLights()) {
|
||||
mLightsById.put(hwLight.id, new LightImpl(context, hwLight));
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
@@ -514,6 +515,33 @@ public class LightsService extends SystemService {
|
||||
}
|
||||
};
|
||||
|
||||
private static class VintfHalCache implements Supplier<ILights>, IBinder.DeathRecipient {
|
||||
@GuardedBy("this")
|
||||
private ILights mInstance = null;
|
||||
|
||||
@Override
|
||||
public synchronized ILights get() {
|
||||
if (mInstance == null) {
|
||||
IBinder binder = Binder.allowBlocking(ServiceManager.waitForDeclaredService(
|
||||
"android.hardware.light.ILights/default"));
|
||||
if (binder != null) {
|
||||
mInstance = ILights.Stub.asInterface(binder);
|
||||
try {
|
||||
binder.linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Unable to register DeathRecipient for " + mInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void binderDied() {
|
||||
mInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
static native void setLight_native(int light, int color, int mode,
|
||||
int onMS, int offMS, int brightnessMode);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
|
||||
package com.android.server.lights;
|
||||
|
||||
import static android.hardware.lights.LightsRequest.Builder;
|
||||
|
||||
import static android.graphics.Color.BLACK;
|
||||
import static android.graphics.Color.BLUE;
|
||||
import static android.graphics.Color.GREEN;
|
||||
import static android.graphics.Color.WHITE;
|
||||
import static android.hardware.lights.LightsRequest.Builder;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -93,7 +92,7 @@ public class LightsServiceTest {
|
||||
|
||||
@Test
|
||||
public void testGetLights_filtersSystemLights() {
|
||||
LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
|
||||
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
|
||||
LightsManager manager = new LightsManager(mContext, service.mManagerService);
|
||||
|
||||
// When lights are listed, only the 4 MICROPHONE lights should be visible.
|
||||
@@ -102,7 +101,7 @@ public class LightsServiceTest {
|
||||
|
||||
@Test
|
||||
public void testControlMultipleLights() {
|
||||
LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
|
||||
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
|
||||
LightsManager manager = new LightsManager(mContext, service.mManagerService);
|
||||
|
||||
// When the session requests to turn 3/4 lights on:
|
||||
@@ -124,7 +123,7 @@ public class LightsServiceTest {
|
||||
|
||||
@Test
|
||||
public void testControlLights_onlyEffectiveForLifetimeOfClient() {
|
||||
LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
|
||||
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
|
||||
LightsManager manager = new LightsManager(mContext, service.mManagerService);
|
||||
Light micLight = manager.getLights().get(0);
|
||||
|
||||
@@ -145,7 +144,7 @@ public class LightsServiceTest {
|
||||
|
||||
@Test
|
||||
public void testControlLights_firstCallerWinsContention() {
|
||||
LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
|
||||
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
|
||||
LightsManager manager = new LightsManager(mContext, service.mManagerService);
|
||||
Light micLight = manager.getLights().get(0);
|
||||
|
||||
@@ -171,7 +170,7 @@ public class LightsServiceTest {
|
||||
|
||||
@Test
|
||||
public void testClearLight() {
|
||||
LightsService service = new LightsService(mContext, mHal, Looper.getMainLooper());
|
||||
LightsService service = new LightsService(mContext, () -> mHal, Looper.getMainLooper());
|
||||
LightsManager manager = new LightsManager(mContext, service.mManagerService);
|
||||
Light micLight = manager.getLights().get(0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user