Mg Android中背光系統架構
Email:wei7758@126.com
Blog:http://blog.csdn.net/yinwei520
Author:Yww
Time:2011-9-24
Update:
(轉載請註明出處,謝謝)
不知不覺喜歡上了寫Blog,這還是一種不錯的休閑方式,所噶~~,會不會也害怕過周末呢?因為寂寞~~啥樣兒的生活才讓覺得舒適哦~單身好~哈哈。搞了兩天,還是姚哥一語驚醒夢中人啊~忽略了Linux下的許可權問題,讓我糾結了好幾個小時啊。首先說明一下,這次學習中讓我學到的東西:
最主要的莫過於是瞭解了Android中jni編程,遊盪整個Android源碼,可以看到很多直接操作底層驅動介面,封裝成so庫,供Java調用的例子哦。
這次學習,也正是出於這樣的想法,沒想到這個設想高手們早就實現了哦,菜鳥現在也只能算是驗證了。誒,菜鳥就是菜鳥,有蟲子吃,就興奮的不得了。
驅動架構略,這裡只討論jni介面的實現。
一、我的設想
其實設想很簡單,找到背光碟機動提供給上層的API介面,人家Android還不是一樣需要一層一層的抽象(HAL、Framework),高手們考慮的東東很多,所以才一層層抽象封裝,既然這樣,咱菜鳥不就一根筋,有蟲吃就是王道啊,我為什麼不能直接將這個驅動介面封裝成jni提供給Java呢?其實這想法很早就有了,只是到現在才驗證,確實可以啊。其實Android中還是有N多這樣的例子的。
背光碟機動提供的介面是:/sys/class/leds/lcd-backlight/brightness。至於這個介面是怎麼來的??那就要去看驅動結構了。驅動註冊此介面的源碼位於:
Kernel/driver/leds/led-class.c中。
這個檔案只是實現了提供上層的介面,至於真正操作硬體的驅動程式,可以給出其源碼路徑為:(硬體操作其實就是脈寬調製(PWM)),mediatek\source\kernel\drivers\leds
二、設想驗證
這裡關鍵就是要清楚jni的介面實現規則咯,不過環境搭建也比較麻煩(ndk編譯環境)。
環境搭建另外給出日誌。
Jni介面的源碼如下:
#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>//#include <dirent.h> //#include <jni.h>#include <string.h>#include <android/log.h> #include "com_yecon_CtlBL_CtlBLActivity.h" #define LOG_TAG "ctlbl.c"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)//#define DEV_PATH "/sys/class/leds/lcd-backlight/brightness"//#define DEV_PATH "/sys/devices/platform/leds-mt65xx/leds/lcd-backlight/brightness" /** * native method *///JNIEXPORT jobjectArray JNICALL Java_com_yecon_CtlBL_CtlBLActivity_ctlbl(JNIEnv * env, jobject obj)JNIEXPORT jint JNICALL Java_com_yecon_CtlBL_CtlBLActivity_ctlbl(JNIEnv * env, jobject obj){ int fd; int err; char *p; char ctl[10]={"20"}; LOGI("HELLO!\n"); //__android_log_print(""); //printf("call ctlbl function succ!\n"); fd = open("/sys/class/leds/lcd-backlight/brightness",O_RDWR); if(fd < 0) { //fprintf(stderr,"error: open %s\n",DEV_PATH); LOGI("error: open!\n"); exit(1); }#if 0 err = read(fd,ctl,1); if(err != 1) { //fprintf(stderr,"error: write %d!\n",err); exit(1); }else{ //printf("the data is %s\n",ctl[0]); }#endif err=write(fd,ctl,2); //printf("%s\n",ctl); if(err != 2) { //fprintf(stderr,"error: write %d!\n",err); LOGI("error: write !\n"); exit(1); } close(fd); return 0; //return (*env)->NewStringUTF(env, "Hello ww JNI !"); }
上層Java調用的源碼如下:(只是實現了一個Button,點擊,有一個訊息響應,將背光調到20)
package com.yecon.CtlBL; import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView; //import com.yecon.CtlBL.ctlbljni; public class CtlBLActivity extends Activity { Button b = null; // ctl = new ctlbljni(); private OnClickListener clickListener = new OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub // ctl.ctlbl(); ctlbl(); } }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); b = (Button) this.findViewById(R.id.BtnCancel); b.setOnClickListener(clickListener);// TextView tv = new TextView(this); // tv.setText( ctlbl() ); // setContentView(tv); } public native int ctlbl();//本地方法 static { System.loadLibrary("ctlbl");//載入so庫 }}
看上去,沒幾行代碼,so easy!!看看高手們的實現吧!!
三、Android中背光系統實現
以往,我經常都是從底層往上看,這次從上層往下找找吧,同樣的眼睛,不一樣的視角,會別有一番風景哦~~其實,美女也要應該這樣欣賞。
玩玩Android機子,其實知道背光調節就是在“設定”中的那個seekBar,那我們就去setting中去找源碼吧.其源碼路徑為:
packages\apps\Settings\src\com\android\settings\ BrightnessPreference.java
開啟看看吧~寬衣解帶是最讓人興奮的啊。你會看到這樣幾行注釋:
// Backlight range is from 0 - 255. Need to make sure that user
// doesn't set the backlight to 0 and get stuck
private static final intMINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;
private static final int
MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
背光的調節範圍是0-255啊~~
繼續解帶吧~會看到一個很親切的函數:
public void UpdateBrightness()
{
if(mIsActive)
{
setBrightness(mSeekBar.getProgress() +MINIMUM_BACKLIGHT);
}
}
更新背光亮度,太親切了,這不慢慢接近目標了嗎?其調用了setBrightness()函數,跳進去看看其實現哦~~
private void setBrightness(int brightness) {
try {
IPowerManager power = IPowerManager.Stub.asInterface(
ServiceManager.getService("power"));
if (power !=null) {
power.setBacklightBrightness(brightness);
}
} catch (RemoteException doe) {
}
}
這不就是韓哥給出的那幾行代碼嘛~~呵呵~終於找到要點了吧,所謂打蛇要打七寸,不就是這樣嗎?這個IPowerManager類中有個setBacklightBrightness函數啊,那它又是怎麼實現的啊?找來找去只找到了一個申明啊:
public void setBacklightBrightness(int brightness)throws android.os.RemoteException;
找不到其實現怎麼辦呢??這是個棘手的問題啊~還好Eclipse很噁心啊~~搜搜就又出來了,這個函數的實現在:
frameworks\base\services\java\com\android\server\PowerManagerService.java中。
public void setBacklightBrightness (int brightness) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); // Don't let applications turn the screen all the way off synchronized (mLocks) { brightness = Math.max(brightness, Power.BRIGHTNESS_DIM); mLcdLight.setBrightness(brightness); //We won't adjust Button/Keyboard BKL here for the time being, see CR[ALPS00132847] //mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0); //mButtonLight.setBrightness(brightness); long identity = Binder.clearCallingIdentity(); try { mBatteryStats.noteScreenBrightness(brightness); } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e); } finally { Binder.restoreCallingIdentity(identity); } // update our animation state synchronized (mLocks) { mScreenBrightness.targetValue = brightness; mScreenBrightness.jumpToTargetLocked(); } } }
看著看著又模糊啦,這裡怎麼又調用了setBrightness()哦,此setBrightness非BrightnessPreference.java中的setBrightness。其類屬於:
private LightsService.Light mLcdLight;
革命尚未成功,你說咋辦,那好吧,為了革命的勝利,再進去看看這個類中setBrightness()的實現吧。源碼路徑為:
frameworks\base\services\java\com\android\server\LightsService.java
public void setBrightness(int brightness) { setBrightness(brightness, BRIGHTNESS_MODE_USER); } public void setBrightness(int brightness, int brightnessMode) { synchronized (this) { int color = brightness & 0x000000ff; color = 0xff000000 | (color << 16) | (color << 8) | color; setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode); } }
這裡又調用了setLightLocked()
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) { if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) { mColor = color; mMode = mode; mOnMS = onMS; mOffMS = offMS; setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode); } }
革命的曙光來啦,看到沒,這裡調用了setLight_native這個本地介面,
private static native void setLight_native(int ptr,int light,int color,int mode,
int onMS,int offMS,int brightnessMode);
皇天不負有心人啊,勝利的曙光照耀著我們啊,終於就快脫光光啦~~!難以按捺住這顆激動的心啊。
可是這個setLight_native又是在哪裡呢??經過一番苦苦搜尋,它並不在燈火闌珊處,而是在:
frameworks\base\services\jni\ com_android_server_LightsService.cpp
寬衣,看看:
四、JNI層
static void setLight_native(JNIEnv *env, jobject clazz, int ptr, int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode){ Devices* devices = (Devices*)ptr; light_state_t state; if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) { return ; } memset(&state, 0, sizeof(light_state_t)); state.color = colorARGB; state.flashMode = flashMode; state.flashOnMS = onMS; state.flashOffMS = offMS; state.brightnessMode = brightnessMode; devices->lights[light]->set_light(devices->lights[light], &state);} static JNINativeMethod method_table[] = { { "init_native", "()I", (void*)init_native }, { "finalize_native", "(I)V", (void*)finalize_native }, { "setLight_native", "(IIIIIII)V", (void*)setLight_native },};
哇,高手就是高手啊。看看,一個函數人家處理的不只是backlight,還有flash,color哦。慚愧啊~
到此,一個美女就這樣被你看完啦~~當然,還有三點哦~~還想要激情的嗎??激情就在底層了哦。想單刀直入嗎?那還得看你本事了哦~~
devices->lights[light]->set_light(devices->lights[light], &state);
這句將帶你穿梭進赤裸裸的XX。
五、HAL層
太神奇啦,這裡直接給出HAL層的源碼路勁,如下:
\mediatek\source\hardware\liblights\ lights.c
\hardware\libhardware\include\hardware\ lights.h
你會看到引你越過道德邊緣的set_light的申明就在lights.h中啊。真是罪孽啊~~
/** * 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)) { set_light = set_light_backlight; } else if (0 == strcmp(LIGHT_ID_KEYBOARD, name)) { set_light = set_light_keyboard; } else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) { set_light = set_light_buttons; } else if (0 == strcmp(LIGHT_ID_BATTERY, name)) { set_light = set_light_battery; } else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) { set_light = set_light_notifications; } 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)); memset(dev, 0, sizeof(*dev)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 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;}
看看吧,其實我們需要找的就是set_light_backlight。
static intset_light_backlight(struct light_device_t* dev, struct light_state_t const* state){ int err = 0; int brightness = rgb_to_brightness(state); pthread_mutex_lock(&g_lock); LOGD("%s: brightness=%d start+++\n", __func__, brightness); g_backlight = brightness; err = write_int(LCD_FILE, brightness); if (g_haveTrackballLight) { handle_trackball_light_locked(dev); } pthread_mutex_unlock(&g_lock); return err;}
當你認真看完lights.c會發現其基本思想跟之前的設想一樣,只是人家是高手,我是菜鳥,人家看到赤裸裸的美女不是表面,而是藝術~~~~!!
通過這個分析,可以延伸瞭解到led燈的結構。