note: Android O
/frameworks/base/services/java/com/android/server/SystemServer.java
[SystemServer.java::run()]
private void run() {
......
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
......
}
/frameworks/base/services/java/com/android/server/SystemServer.java
[SystemServer.java::startBootstrapServices()]
private void startBootstrapServices() {
Slog.i(TAG, "Reading configuration...");
final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig";
......
// Manages LEDs and display backlight so we need it to bring up the display.
traceBeginAndSlog("StartLightsService");
mSystemServiceManager.startService(LightsService.class);
traceEnd();
.....
}
/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
[SystemServiceManager.java::startService(Class serviceClass)]
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
[SystemServiceManager.java::startService(@NonNull final SystemService service)]
public void startService(@NonNull final SystemService service) {
// Register it.
/**
// Services that should receive lifecycle events.
private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
*/
mServices.add(service);
// Start it.
long time = System.currentTimeMillis();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(System.currentTimeMillis() - time, service, "onStart");
}
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java::onStart()]
@Override
public void onStart() {
publishLocalService(LightsManager.class, mService);
}
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java::mService]
private final LightsManager mService = new LightsManager() {
@Override
public Light getLight(int id) {
if (0 <= id && id < LIGHT_ID_COUNT) {
return mLights[id];
} else {
return null;
}
}
};
/frameworks/base/services/core/java/com/android/server/lights/LightsManager.java
[LightsManager.java]
package com.android.server.lights;
import android.hardware.light.V2_0.Type;
public abstract class LightsManager {
public static final int LIGHT_ID_BACKLIGHT = Type.BACKLIGHT;
public static final int LIGHT_ID_KEYBOARD = Type.KEYBOARD;
public static final int LIGHT_ID_BUTTONS = Type.BUTTONS;
public static final int LIGHT_ID_BATTERY = Type.BATTERY;
public static final int LIGHT_ID_NOTIFICATIONS = Type.NOTIFICATIONS;
public static final int LIGHT_ID_ATTENTION = Type.ATTENTION;
public static final int LIGHT_ID_BLUETOOTH = Type.BLUETOOTH;
public static final int LIGHT_ID_WIFI = Type.WIFI;
public static final int LIGHT_ID_COUNT = Type.COUNT;
public abstract Light getLight(int id);
}
/frameworks/base/services/core/java/com/android/server/SystemService.java
[SystemService.java::publishLocalService(Class type, T service)]
/**
* Publish the service so it is only accessible to the system process.
*/
protected final <T> void publishLocalService(Class<T> type, T service) {
LocalServices.addService(type, service);
}
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java]
public class LightsService extends SystemService {
......
final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
......
public LightsService(Context context) {
super(context);
for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
mLights[i] = new LightImpl(i);
}
}
}
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java::LightImpl()]
private final class LightImpl extends Light {
private LightImpl(int id) {
mId = id;
}
@Override
public void setBrightness(int brightness) {
setBrightness(brightness, BRIGHTNESS_MODE_USER);
}
@Override
public void setBrightness(int brightness, int brightnessMode) {
synchronized (this) {
// LOW_PERSISTENCE cannot be manually set
if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
": brightness=0x" + Integer.toHexString(brightness));
return;
}
int color = brightness & 0x000000ff;
color = 0xff000000 | (color << 16) | (color << 8) | color;
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
}
@Override
public void setColor(int color) {
synchronized (this) {
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
}
}
@Override
public void setFlashing(int color, int mode, int onMS, int offMS) {
synchronized (this) {
setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
}
}
@Override
public void pulse() {
pulse(0x00ffffff, 7);
}
@Override
public void pulse(int color, int onMS) {
synchronized (this) {
if (mColor == 0 && !mFlashing) {
setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000,
BRIGHTNESS_MODE_USER);
mColor = 0;
mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
}
}
}
@Override
public void turnOff() {
synchronized (this) {
setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
}
}
@Override
public void setVrMode(boolean enabled) {
synchronized (this) {
if (mVrModeEnabled != enabled) {
mVrModeEnabled = enabled;
mUseLowPersistenceForVR =
(getVrDisplayMode() == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE);
if (shouldBeInLowPersistenceMode()) {
mLastBrightnessMode = mBrightnessMode;
}
// NOTE: We do not trigger a call to setLightLocked here. We do not know the
// current brightness or other values when leaving VR so we avoid any incorrect
// jumps. The code that calls this method will immediately issue a brightness
// update which is when the change will occur.
}
}
}
private void stopFlashing() {
synchronized (this) {
setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
}
}
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
if (shouldBeInLowPersistenceMode()) {
brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
} else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
brightnessMode = mLastBrightnessMode;
}
if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
offMS != mOffMS || mBrightnessMode != brightnessMode) {
if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
+ Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
mInitialized = true;
mLastColor = mColor;
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
mBrightnessMode = brightnessMode;
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
+ Integer.toHexString(color) + ")");
try {
setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
}
private boolean shouldBeInLowPersistenceMode() {
return mVrModeEnabled && mUseLowPersistenceForVR;
}
private int mId;
private int mColor;
private int mMode;
private int mOnMS;
private int mOffMS;
private boolean mFlashing;
private int mBrightnessMode;
private int mLastBrightnessMode;
private int mLastColor;
private boolean mVrModeEnabled;
private boolean mUseLowPersistenceForVR;
private boolean mInitialized;
}
/frameworks/base/services/core/java/com/android/server/lights/Light.java
[Light.java]
package com.android.server.lights;
import android.hardware.light.V2_0.Flash;
import android.hardware.light.V2_0.Brightness;
public abstract class Light {
public static final int LIGHT_FLASH_NONE = Flash.NONE;
public static final int LIGHT_FLASH_TIMED = Flash.TIMED;
public static final int LIGHT_FLASH_HARDWARE = Flash.HARDWARE;
/**
* Light brightness is managed by a user setting.
*/
public static final int BRIGHTNESS_MODE_USER = Brightness.USER;
/**
* Light brightness is managed by a light sensor.
*/
public static final int BRIGHTNESS_MODE_SENSOR = Brightness.SENSOR;
/**
* Low-persistence light mode.
*/
public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = Brightness.LOW_PERSISTENCE;
public abstract void setBrightness(int brightness);
public abstract void setBrightness(int brightness, int brightnessMode);
public abstract void setColor(int color);
public abstract void setFlashing(int color, int mode, int onMS, int offMS);
public abstract void pulse();
public abstract void pulse(int color, int onMS);
public abstract void turnOff();
public abstract void setVrMode(boolean enabled);
}
/frameworks/base/services/core/java/com/android/server/BatteryService.java
[BatteryService.java::updateLightsLocked()]
/**
* Synchronize on BatteryService.
*/
public void updateLightsLocked() {
final int level = mBatteryProps.batteryLevel;
final int status = mBatteryProps.batteryStatus;
if (level < mLowBatteryWarningLevel) {
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
// Solid red when battery is charging
/**
设置指示灯颜色
*/
mBatteryLight.setColor(mBatteryLowARGB);
} else {
// Flash red when battery is low and not charging
/**
设置指示灯
*/
mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
mBatteryLedOn, mBatteryLedOff);
}
}
......
}
/frameworks/base/services/core/java/com/android/server/BatteryService.java
[BatteryService.java::Led ]
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
private final class Led {
private final Light mBatteryLight;
public Led(Context context, LightsManager lights) {
mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
......
}
}
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java::mService ]
private final LightsManager mService = new LightsManager() {
@Override
public Light getLight(int id) {
if (0 <= id && id < LIGHT_ID_COUNT) {
return mLights[id];
} else {
return null;
}
}
};
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java::LightImpl::setFlashing(int color, int mode, int onMS, int offMS) ]
@Override
public void setFlashing(int color, int mode, int onMS, int offMS) {
synchronized (this) {
setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
}
}
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java::LightImpl::setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) ]
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
if (shouldBeInLowPersistenceMode()) {
brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
} else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
brightnessMode = mLastBrightnessMode;
}
if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
offMS != mOffMS || mBrightnessMode != brightnessMode) {
if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
+ Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
mInitialized = true;
mLastColor = mColor;
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
mBrightnessMode = brightnessMode;
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
+ Integer.toHexString(color) + ")");
try {
setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
}
/frameworks/base/services/core/java/com/android/server/lights/LightsService.java
[LightsService.java::setLight_native]
static native void setLight_native(int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
/frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
[com_android_server_lights_LightsService.cpp::setLight_native]
static void setLight_native(
JNIEnv* /* env */,
jobject /* clazz */,
jint light,
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
jint brightnessMode) {
if (!validate(light, flashMode, brightnessMode)) {
return;
}
/**
1. 获取ILight服务
*/
sp<ILight> hal = LightHal::associate();
if (hal == nullptr) {
return;
}
Type type = static_cast<Type>(light);
/**
2. 构建lightState
*/
LightState state = constructState(
colorARGB, flashMode, onMS, offMS, brightnessMode);
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
/**
3. 调用ILight服务的setLight()函数
*/
Return<Status> ret = hal->setLight(type, state);
processReturn(ret, type, state);
}
}
/hardware/interfaces/light/2.0/ILight.hal
[ILight.hal]
package android.hardware.light@2.0;
interface ILight {
/**
* Set the provided lights to the provided values.
*
* @param type logical light to set
* @param state describes what the light should look like.
* @return status result of applying state transformation.
*/
setLight(Type type, LightState state) generates (Status status);
/**
* Discover what indicator lights are available.
*
* @return types list of available lights
*/
getSupportedTypes() generates (vec<Type> types);
};
/hardware/interfaces/light/2.0/default/Light.h
[Light.h]
struct Light : public ILight {
Light(std::map<Type, light_device_t*> &&lights);
// Methods from ::android::hardware::light::V2_0::ILight follow.
Return<Status> setLight(Type type, const LightState& state) override;
Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
private:
std::map<Type, light_device_t*> mLights;
};
/frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
[com_android_server_lights_LightsService.cpp::LightHal::associate()]
class LightHal {
private:
static sp<ILight> sLight;
static bool sLightInit;
LightHal() {}
public:
static void disassociate() {
sLightInit = false;
sLight = nullptr;
}
static sp<ILight> associate() {
if ((sLight == nullptr && !sLightInit) ||
(sLight != nullptr && !sLight->ping().isOk())) {
// will return the hal if it exists the first time.
sLight = ILight::getService();
sLightInit = true;
if (sLight == nullptr) {
ALOGE("Unable to get ILight interface.");
}
}
return sLight;
}
};
/frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
[com_android_server_lights_LightsService.cpp::constructState()]
static LightState constructState(
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
jint brightnessMode){
Flash flash = static_cast<Flash>(flashMode);
Brightness brightness = static_cast<Brightness>(brightnessMode);
LightState state{};
if (brightness == Brightness::LOW_PERSISTENCE) {
state.flashMode = Flash::NONE;
} else {
// Only set non-brightness settings when not in low-persistence mode
state.flashMode = flash;
state.flashOnMs = onMS;
state.flashOffMs = offMS;
}
state.color = colorARGB;
state.brightnessMode = brightness;
return state;
}
/hardware/interfaces/light/2.0/default/Light.cpp
[Light.cpp]
// Methods from ::android::hardware::light::V2_0::ILight follow.
Return<Status> Light::setLight(Type type, const LightState& state) {
auto it = mLights.find(type);
if (it == mLights.end()) {
return Status::LIGHT_NOT_SUPPORTED;
}
light_device_t* hwLight = it->second;
light_state_t legacyState {
.color = state.color,
.flashMode = static_cast<int>(state.flashMode),
.flashOnMS = state.flashOnMs,
.flashOffMS = state.flashOffMs,
.brightnessMode = static_cast<int>(state.brightnessMode),
};
/**
调用hwLight->set_light()
*/
int ret = hwLight->set_light(hwLight, &legacyState);
switch (ret) {
case -ENOSYS:
return Status::BRIGHTNESS_NOT_SUPPORTED;
case 0:
return Status::SUCCESS;
default:
return Status::UNKNOWN;
}
}
/hardware/libhardware/include/hardware/lights.h
[lights.h::light_device_t]
struct light_device_t {
struct hw_device_t common;
/**
* Set the provided lights to the provided values.
*
* Returns: 0 on succes, error code on failure.
*/
int (*set_light)(struct light_device_t* dev,
struct light_state_t const* state);
};
/hardware/qcom/display/liblight/lights.c
[lights.c::open_lights]
/**
* module methods
*/
/** Open a new instance of a lights device using name */
static int open_lights(const struct hw_module_t* module, char const* name,
struct hw_device_t** device)
{
int (*set_light)(struct light_device_t* dev,
struct light_state_t const* state);
if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
char property[PROPERTY_VALUE_MAX];
property_get("persist.extend.brightness", property, "0");
if(!(strncmp(property, "1", PROPERTY_VALUE_MAX)) ||
!(strncmp(property, "true", PROPERTY_VALUE_MAX))) {
property_get("persist.display.max_brightness", property, "255");
g_brightness_max = atoi(property);
set_brightness_ext_init();
set_light = set_light_backlight_ext;
} else
set_light = set_light_backlight;
} else if (0 == strcmp(LIGHT_ID_BATTERY, name))
/**
根据调用参数为电量指示灯,因此set_light对应set_light_battery
*/
set_light = set_light_battery;
else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
set_light = set_light_notifications;
else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
set_light = set_light_buttons;
else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
set_light = set_light_attention;
else
return -EINVAL;
pthread_once(&g_init, init_globals);
struct light_device_t *dev = malloc(sizeof(struct light_device_t));
if(!dev)
return -ENOMEM;
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = LIGHTS_DEVICE_API_VERSION_2_0;
dev->common.module = (struct hw_module_t*)module;
dev->common.close = (int (*)(struct hw_device_t*))close_lights;
dev->set_light = set_light;
*device = (struct hw_device_t*)dev;
return 0;
}
/hardware/qcom/display/liblight/lights.c
[lights.c::set_light_battery()]
static int
set_light_battery(struct light_device_t* dev,
struct light_state_t const* state)
{
pthread_mutex_lock(&g_lock);
g_battery = *state;
handle_speaker_battery_locked(dev);
pthread_mutex_unlock(&g_lock);
return 0;
}
/hardware/qcom/display/liblight/lights.c
[lights.c::handle_speaker_battery_locked()]
static void
handle_speaker_battery_locked(struct light_device_t* dev)
{
if (is_lit(&g_battery)) {
set_speaker_light_locked(dev, &g_battery);
} else {
set_speaker_light_locked(dev, &g_notification);
}
}
/hardware/qcom/display/liblight/lights.c
[lights.c::set_speaker_light_locked()]
static int
set_speaker_light_locked(struct light_device_t* dev,
struct light_state_t const* state)
{
int red, green, blue;
int blink;
int onMS, offMS;
unsigned int colorRGB;
if(!dev) {
return -1;
}
switch (state->flashMode) {
case LIGHT_FLASH_TIMED:
onMS = state->flashOnMS;
offMS = state->flashOffMS;
break;
case LIGHT_FLASH_NONE:
default:
onMS = 0;
offMS = 0;
break;
}
colorRGB = state->color;
#if 0
ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
state->flashMode, colorRGB, onMS, offMS);
#endif
red = (colorRGB >> 16) & 0xFF;
green = (colorRGB >> 8) & 0xFF;
blue = colorRGB & 0xFF;
if (onMS > 0 && offMS > 0) {
/*
* if ON time == OFF time
* use blink mode 2
* else
* use blink mode 1
*/
if (onMS == offMS)
blink = 2;
else
blink = 1;
} else {
blink = 0;
}
if (blink) {
if (red) {
if (write_int(RED_BLINK_FILE, blink))
write_int(RED_LED_FILE, 0);
}
if (green) {
if (write_int(GREEN_BLINK_FILE, blink))
write_int(GREEN_LED_FILE, 0);
}
if (blue) {
if (write_int(BLUE_BLINK_FILE, blink))
write_int(BLUE_LED_FILE, 0);
}
} else {
write_int(RED_LED_FILE, red);
write_int(GREEN_LED_FILE, green);
write_int(BLUE_LED_FILE, blue);
}
return 0;
}
/hardware/qcom/display/liblight/lights.c
[lights.c::write_int()]
static int
write_int(char const* path, int value)
{
int fd;
static int already_warned = 0;
fd = open(path, O_RDWR);
if (fd >= 0) {
char buffer[20];
int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
ssize_t amt = write(fd, buffer, (size_t)bytes);
close(fd);
return amt == -1 ? -errno : 0;
} else {
if (already_warned == 0) {
ALOGE("write_int failed to open %s\n", path);
already_warned = 1;
}
return -errno;
}
}
/hardware/qcom/display/liblight/lights.c
[lights.c]
static pthread_once_t g_init = PTHREAD_ONCE_INIT;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
static struct light_state_t g_notification;
static struct light_state_t g_battery;
static int g_last_backlight_mode = BRIGHTNESS_MODE_USER;
static int g_attention = 0;
static int g_brightness_max = 0;
char const*const RED_LED_FILE
= "/sys/class/leds/red/brightness";
char const*const GREEN_LED_FILE
= "/sys/class/leds/green/brightness";
char const*const BLUE_LED_FILE
= "/sys/class/leds/blue/brightness";
char const*const LCD_FILE
= "/sys/class/leds/lcd-backlight/brightness";
char const*const LCD_FILE2
= "/sys/class/backlight/panel0-backlight/brightness";
char const*const BUTTON_FILE
= "/sys/class/leds/button-backlight/brightness";
char const*const RED_BLINK_FILE
= "/sys/class/leds/red/blink";
char const*const GREEN_BLINK_FILE
= "/sys/class/leds/green/blink";
char const*const BLUE_BLINK_FILE
= "/sys/class/leds/blue/blink";
char const*const PERSISTENCE_FILE
= "/sys/class/graphics/fb0/msm_fb_persist_mode";
/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
[NotificationManagerService.java::updateLightsLocked()]
@GuardedBy("mNotificationLock")
void updateLightsLocked()
{
// handle notification lights
NotificationRecord ledNotification = null;
while (ledNotification == null && !mLights.isEmpty()) {
final String owner = mLights.get(mLights.size() - 1);
ledNotification = mNotificationsByKey.get(owner);
if (ledNotification == null) {
Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
mLights.remove(owner);
}
}
// Don't flash while we are in a call or screen is on
if (ledNotification == null || mInCall || mScreenOn) {
mNotificationLight.turnOff();
} else {
NotificationRecord.Light light = ledNotification.getLight();
if (light != null && mNotificationPulseEnabled) {
// pulse repeatedly
mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
light.onMs, light.offMs);
}
}
}
/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
[NotificationManagerService.java::init()]
// TODO: Tests should call onStart instead once the methods above are removed.
@VisibleForTesting
void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
LightsManager lightsManager, NotificationListeners notificationListeners,
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
NotificationUsageStats usageStats) {
......
mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
......
}
/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
[NotificationManagerService.java::onStart()]
public class NotificationManagerService extends SystemService {
......
@Override
public void onStart() {
SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
@Override
public void repost(int userId, NotificationRecord r) {
try {
if (DBG) {
Slog.d(TAG, "Reposting " + r.getKey());
}
enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
r.sbn.getNotification(), userId);
} catch (Exception e) {
Slog.e(TAG, "Cannot un-snooze notification", e);
}
}
}, mUserProfiles);
init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class), new NotificationListeners(),
null, snoozeHelper, new NotificationUsageStats(getContext()));
publishBinderService(Context.NOTIFICATION_SERVICE, mService);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
......
}
mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
light.onMs, light.offMs);调用流程和电源指示灯调用流程类似,区别在于使用LightsManager.getLight()传入的Id不同。
通知中指示灯的初始化在NotificationRecord中
/frameworks/base/services/core/java/com/android/server/notification/NotificationRecord.java
[NotificationRecord.java]
public final class NotificationRecord {
......
private Light mLight;
......
@VisibleForTesting
public NotificationRecord(Context context, StatusBarNotification sbn,
NotificationChannel channel)
{
this.sbn = sbn;
mOriginalFlags = sbn.getNotification().flags;
mRankingTimeMs = calculateRankingTimeMs(0L);
mCreationTimeMs = sbn.getPostTime();
mUpdateTimeMs = mCreationTimeMs;
mContext = context;
stats = new NotificationUsageStats.SingleNotificationStats();
mChannel = channel;
mPreChannelsNotification = isPreChannelsNotification();
mSound = calculateSound();
mVibration = calculateVibration();
mAttributes = calculateAttributes();
mImportance = calculateImportance();
mLight = calculateLights();
}
......
}
/frameworks/base/services/core/java/com/android/server/notification/NotificationRecord.java
[NotificationRecord.java::calculateLights()]
private Light calculateLights() {
int defaultLightColor = mContext.getResources().getColor(
com.android.internal.R.color.config_defaultNotificationColor);
int defaultLightOn = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOn);
int defaultLightOff = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOff);
int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
: defaultLightColor;
/**
判断通知是否需要指示灯
*/
Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
defaultLightOn, defaultLightOff) : null;
if (mPreChannelsNotification
&& (getChannel().getUserLockedFields()
& NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
final Notification notification = sbn.getNotification();
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
light = new Light(notification.ledARGB, notification.ledOnMS,
notification.ledOffMS);
if ((notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
light = new Light(defaultLightColor, defaultLightOn,
defaultLightOff);
}
} else {
light = null;
}
}
return light;
}
/frameworks/base/services/core/java/com/android/server/notification/NotificationRecord.java
[NotificationRecord.java::Light]
@VisibleForTesting
static final class Light {
public final int color;
public final int onMs;
public final int offMs;
public Light(int color, int onMs, int offMs) {
this.color = color;
this.onMs = onMs;
this.offMs = offMs;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Light light = (Light) o;
if (color != light.color) return false;
if (onMs != light.onMs) return false;
return offMs == light.offMs;
}
@Override
public int hashCode() {
int result = color;
result = 31 * result + onMs;
result = 31 * result + offMs;
return result;
}
@Override
public String toString() {
return "Light{" +
"color=" + color +
", onMs=" + onMs +
", offMs=" + offMs +
'}';
}
}