Merge "Use waitForDeclaredService to get Lights HAL" into rvc-dev am: 137f875360 am: ced1535de3 am: e7500cfb90

Change-Id: I5751eab34e238fdd86afb7b932851f657bac71e8
This commit is contained in:
TreeHugger Robot
2020-04-24 18:07:42 +00:00
committed by Automerger Merge Worker
7 changed files with 159 additions and 19 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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",

View File

@@ -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),

View 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

View File

@@ -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);
}

View File

@@ -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);