2014年2月5日 星期三

[轉貼]android jni代碼編寫規則--整理總結


 JNI層的代碼其實比較簡單,難點是要掌握c++和java數據類型的轉換,明白java程序是運行在虛擬機中的,特別是函數並不是可以互相調用,jni中的內存概念並沒有暴露給java虛擬機進程等。
一.   java參數類型和jni本地參數類型對照

基本類型
Java 類型         jni本地類型                    描述
boolean             jboolean                    C/C++ unsigned 8 bits
byte                jbyte                       C/C++ signed 8 bits
char                jchar                       C/C++ unsigned 16 bits
short               jshort                      C/C++ signed 16 bits
int                 jint                        C/C++ signed 32 bits
long                jlong                       C/C++ signed 64 bits
float               jfloat                      C/C++  32位浮點型
double              jdouble                     C/C++  64位浮點型
void                void                        N/A
                    表一

對象類型
Object              jobject                     任何Java對象,或者沒有對應
java類型的對象
Class               jclass                      class對象
String              jstring                     字符串對象
                    表二

數組類型
boolean[]           jbooleanArray               布爾型數組 unsigned
byte[]              jbyteArray                  比特型數組 signed
char[]              jcharArray                  字符型數組 unsigned
short[]             jshortArray                 短整型數組 signed
int[]               jintArray                   整型數組 signed
long[]              jlongArray                  長整型數組 signed
float[]             jfloatArray                 浮點型數組
double[]            jdoubleArray                雙浮點型數組
Object[]            jobjectArray                任何對象的數組
                    表三


JNI引用類型與Java的對應關係如下樹層次圖:
1. java中的返回值void和JNI中的void是完全對應的。
 
2. java中的基本數據類型(boolean ,byte , char ,short ,int,long,float,double八種)在JNI中對應的數據類型只要在前面加上j就對應了(jboolean ,jbyte , jchar ,jshort ,jint,jlong,jfloat,jdouble)。
JNI中還有個Java中沒有的jsize,定義如下:
typedef jint jsize;
其實jsize整型是用來描述基本指標和大小。

3. java中的對象,包括類庫中定義的類、接口以及自定義的類接口,都對應於JNI中的jobject。

4. java中基本數據類型的數組對應與JNI中的jarray類型。(type就是上面說的8種基本數據類型)

5. java中對象的數組對應於JNI中的jobjectArray類型。(在java中一切對象、接口以及數組都是對象)
http://blog.csdn.net/xyz_lmn/article/details/6956003
http://www.cnblogs.com/liangwind/archive/2009/08/18/1925515.html
   
    Java基本類型的精度
java 的基本數據類型是不存在有符號和無符號這種概念的. JAVA中的基本數據類型不存在無符號的,它們的取值範圍是固定的,不會隨著機器硬件環境或者操作系統的改變而改變。
簡單類型   字節數   範圍/精度
float       4       32位IEEE754單精度
double      8       64位IEEE754雙精度
byte        1       -128到127
short       2       -32,768到32,767
int         4       -2,147,483,648到2,147,483,647
long        8       -9,223,372,036,854,775,808到9,223,372,036,854,775,807
char        2       整個Unicode字符集
boolean     1       True或者false
像byte 是範圍是 -128到127, 你想要變為 0到255 怎麼辦, 跟 0XFF 做與運算 就可以了.
如 byte bb , 如果你想賦值它值 255, 那是不行的, 就算賦值了, bb 的值也是 255 對 256 求模後的值 -1
      如果你只是想取他 0到255 的值, 還是很簡單的,
      bb & 0XFF  , 如 bb = -1,  那 bb & 0XFF 結果為 255,
      這個與運算後的結果會隱式轉換為int 類型的, 因為 byte 放不下了.
與運算 還是很快的, 比加減法還快的.
http://www.stuhack.com/biancheng/java/35169.html
   
   
二.jni層使用java的基本類型數據
對於上面八種基本的數據類型boolean ,byte , char ,short ,int,long,float,double,jni層的c++代碼可以用強制直接轉換成對於長度的c/c++類型數據。
如:unsigned char tmp = (unsigned char) m_jboolean;
    unsigned short tmp = (unsigned short)m_jchar;
    或者同長度類型的數據就可以直接賦值的,int tmp = m_jint;


三.jni層對數組的使用
JNI通過JNIEnv提供的操作Java數組的功能。它提供了兩個函數:一個是操作java的簡單型數組的,另一個是操作對象類型數組的。
1.     操作java的簡單型數組
因為速度的原因,簡單類型的數組作為指向本地類型的指針暴露給本地代碼。因此,它們能作為常規的數組存取。這個指針是指向實際的Java數組或者Java數組的拷貝的指針。另外,數組的佈置保證匹配本地類型。
為了存取Java簡單類型的數組,你就要要使用GetXXXArrayElements函數(見表三),XXX代表了數組的類型。這個函數把Java數組看成參數,返回一個指向對應的本地類型的數組的指針。
        完整的函數族見下表:
函數                         Java 數組類型  本地類型
GetBooleanArrayElements     jbooleanArray   jboolean
GetByteArrayElements         jbyteArray      jbyte
GetCharArrayElements         jcharArray      jchar
GetShortArrayElements        jshortArray     jshort
GetIntArrayElements          jintArray       jint
GetLongArrayElements         jlongArray      jlong
GetFloatArrayElements        jfloatArray     jfloat
GetDoubleArrayElements       jdoubleArray    jdouble

當你對數組的存取完成後,要確保調用相應的ReleaseXXXArrayElements函數,參數是對應Java數組和 GetXXXArrayElements返回的指針。如果必要的話,這個釋放函數會複製你做的任何變化(這樣它們就反射到java數組),然後釋放所有相 關的資源。
例如:
static jint com_ginwave_fs_com_HWRC_GetRecogRange(JNIEnv* env, jclass clazz, jintArray Handle)
{
unsigned long *pHandle = NULL;
int ret = 0;
jint *tmpHandle = env->GetIntArrayElements(Handle, 0);
pHandle = (unsigned long *)tmpHandle;
ret = (int)HWRC_GetRecogRange(pHandle);
env->ReleaseIntArrayElements(Handle, tmpHandle, 0);
return r
}

獲取數組的長度:
jint theArrayLength = env->GetArrayLength(Frame);
       
        創建一個新的函數數組簇如下:
NewBooleanArray
NewByteArray
NewCharArray
NewShortArray
NewIntArray
NewLongArray
NewFloatArray
NewDoubleArray
        參數為數組長度,如:
        jbyte *list;
        jbyteArray byteArray = NULL;
        byteArray = env->NewByteArray(len);
        if (byteArray)
            env->SetByteArrayRegion(byteArray, 0, len, list);
       
        關於函數簇GetXXXArrayRegion和SetXXXArrayRegion,其中XXX為基本類型。
        例如:
        env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset);
        Setxxx的方向是從JNI層往java層傳遞;
        env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset);
        而Getxxx的方向則是數據從java層向jni層傳遞。
       
        這裡是獲取簡單型數組中的數據供jni或者下層使用,如果需要在jni層設置java
中對於的簡單型數組的話,就需要使用到接下來講到的對象類型的一些操作。
    總結下,有以下幾簇函數:
    GetArrayLength
    NewXXXArray
    GetXXXArrayElements
    ReleaseXXXArrayElements
    GetXXXArrayRegion
    SetXXXArrayRegion
    對於數據,暫時遇到這些函數了。。。
   


2.     操作java對象類型數據
Java對象做為引用被傳遞到本地方法中,所有這些Java對象的引用都有一個共同的父類型jobject(相當於java中的Object類是所有類的父類一樣)。

1). string對象
從java程序中傳過去的String對象在本地方法中對應的是jstring類型,jstring類型和c中的char*不同,所以如果你直接當 做char*使用的話,就會出錯。因此在使用之前需要將jstring轉換成為c/c++中的char*,這裡使用JNIEnv的方法轉換。
static jstring  com_prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const char *str = (*env)->GetStringUTFChars(env, prompt, 0);
printf("%s", str);
env->ReleaseStringUTFChars(prompt, str);
...
        
}
這裡使用GetStringUTFChars方法將傳進來的prompt(jstring類型)轉換成為UTF-8的格式,就能夠在本地方法中使用了。
注意:在使用完你所轉換之後的對象之後,需要顯示調用ReleaseStringUTFChars方法,讓JVM釋放轉換成UTF-8的string的對象的空間,如果不顯示的調用的話,JVM中會一直保存該對象,不會被垃圾回收器回收,因此就會導致內存溢出。

下面是訪問String的一些方法:
GetStringUTFChars        將jstring轉換成為UTF-8格式的char*
GetStringChars           將jstring轉換成為Unicode格式的char*
ReleaseStringUTFChars    釋放指向UTF-8格式的char*的指針
ReleaseStringChars       釋放指向Unicode格式的char*的指針
NewStringUTF             創建一個UTF-8格式的String對象
NewString                創建一個Unicode格式的String對象
GetStringUTFLength       獲取UTF-8格式的char*的長度
GetStringLength          獲取Unicode格式的char*的長度

提供給兩個jstring和char *互相轉換的函數:
/* c/c++ string turn to java jstring */
static jstring strTojstring(JNIEnv* env, const unsigned char* pStr)
{
    int        strLen    = strlen((const char*)pStr);
    jclass     jstrObj   = env->FindClass("java/lang/String");
    jmethodID  methodId  = env->GetMethodID(jstrObj, "", "([BLjava/lang/String;)V");
    jbyteArray byteArray = env->NewByteArray(strLen);
    jstring    encode    = env->NewStringUTF("utf-8");

    env->SetByteArrayRegion(byteArray, 0, strLen, (jbyte*)pStr);
   
    return (jstring)env->NewObject(jstrObj, methodId, byteArray, encode);
}
//check ok!


/* java jstring turn to c/c++ string */
static char* jstringTostr(JNIEnv* env, jstring jstr)
{       
    char* pStr = NULL;

    jclass     jstrObj   = env->FindClass("java/lang/String");
    jstring    encode    = env->NewStringUTF("utf-8");
    jmethodID  methodId  = env->GetMethodID(jstrObj, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray byteArray = (jbyteArray)env->CallObjectMethod(jstr, methodId, encode);
    jsize      strLen    = env->GetArrayLength(byteArray);
    jbyte      *jBuf     = env->GetByteArrayElements(byteArray, JNI_FALSE);

    if (jBuf > 0)
    {
        pStr = (char*)malloc(strLen + 1);

        if (!pStr)
        {
            return NULL;
        }

        memcpy(pStr, jBuf, strLen);

        pStr[strLen] = 0;
    }

    env->ReleaseByteArrayElements(byteArray, jBuf, 0);

    return pStr;
}
// check ok!
       
        2) 訪問java對象
    JNI提供的另外一個功能是在本地代碼中使用Java對象。通過使用合適的JNI函數,你可以創建Java對象,get、set 靜態(static)和 實例(instance)的域,調用靜態(static)和實例(instance)函數。JNI通過ID識別域和方法,一個域或方法的ID是任何處理域 和方法的函數的必須參數。
下表列出了用以得到靜態(static)和實例(instance)的域與方法的JNI函數。每個函數接受(作為參數)域或方法的類,它們的名稱,符號和它們對應返回的jfieldID或jmethodID。
       
        函數                    描述
GetFieldID              得到一個實例的域的ID
GetStaticFieldID        得到一個靜態的域的ID
GetMethodID             得到一個實例的方法的ID
GetStaticMethodID       得到一個靜態方法的ID
       
        下面以一個例子來說明用法:上下層之間需要傳遞一個或者多個結構體值。
        c/c++結構體定義:
        typedef struct tagTHWFrame{
            short left;
            short top;
            short width;
            short height;
} THWFrame;
當然在java層也需要定義一個匹配的類出來:
public class THWFrame{
    public short left;
    public short top;
    public short width;
    public short height;   
}
注意貌似這裡只能定義成public的。
下面是jni層相關的代碼,主要思想是對java對應類對象的屬性域獲得ID值後一個一個訪問。
/* int HWRC_SetInputBox( unsigned long *pHandle, const THWFrame *pFrame ); */
static void ObjectTOTHWFrameStruct(JNIEnv* env, jobjectArray Frame, THWFrame *pFrame, int index)
{
    jobject obj = env->GetObjectArrayElement(Frame, index);
    jclass cls = env->GetObjectClass(obj);
    jfieldID left = env->GetFieldID(cls, "left", "S");
    pFrame[index].left = (short)env->GetShortField(obj, left);
       
    jfieldID top = env->GetFieldID(cls, "top", "S");
    pFrame[index].top = (short)env->GetShortField(obj, top);
       
    jfieldID width = env->GetFieldID(cls, "width", "S");
    pFrame[index].width = (short)env->GetShortField(obj, width);
       
    jfieldID height = env->GetFieldID(cls, "height", "S");
    pFrame[index].height = (short)env->GetShortField(obj, height); 
   
}
static jint com_ginwave_fs_com_HWRC_SetInputBox(JNIEnv* env, jclass clazz,
            jintArray Handle, jobjectArray Frame)
{
    unsigned long *pHandle = NULL;
    THWFrame *pFrame = NULL;
    int frame_len = 0;
    int ret = 0;
   
    jint *tmpHandle = env->GetIntArrayElements(Handle, 0);
    pHandle = (unsigned long *)tmpHandle;
   
    jint theArrayLength = env->GetArrayLength(Frame);
    frame_len = theArrayLength;
    pFrame = (THWFrame *)malloc( sizeof(THWFrame) * frame_len );
   
    for( int i = 0; i < frame_len; i++ ){
        ObjectTOTHWFrameStruct(env, Frame, pFrame, i);
    }
   
    ret = HWRC_SetInputBox(pHandle, (const THWFrame *)pFrame);
   
    env->ReleaseIntArrayElements(Handle, tmpHandle, 0);
    free(pFrame);
    frame_len = NULL;
   
    return ret;
}
// {"HWRC_SetInputBox", "([I[Ljava/com/ginwave/fs/com/THWFrame)I" , (void *)com_ginwave_fs_com_HWRC_SetInputBox },
// check ok!


/* int HWRC_GetInputBox( unsigned long *pHandle, THWFrame *pFrame ); */
static void THWFrameStructTOObject(JNIEnv* env, jobjectArray Frame, THWFrame *pFrame, int index)
{
    jobject obj = env->GetObjectArrayElement(Frame, index);
    jclass cls = env->GetObjectClass(obj);
    jfieldID left = env->GetFieldID(cls, "left", "S");
    env->SetShortField(obj, left, (short)pFrame[index].left);
       
    jfieldID top = env->GetFieldID(cls, "top", "S");
    env->SetShortField(obj, top, (short)pFrame[index].top);
       
    jfieldID width = env->GetFieldID(cls, "width", "S");
    env->SetShortField(obj, width, (short)pFrame[index].width);
       
    jfieldID height = env->GetFieldID(cls, "height", "S");
    env->SetShortField(obj, height, (short)pFrame[index].height);
}
static jint com_ginwave_fs_com_HWRC_GetInputBox(JNIEnv* env, jclass clazz,
            jintArray Handle, jobjectArray Frame)
{
    unsigned long *pHandle = NULL;
    THWFrame *pFrame = NULL;
    int frame_len = 0;
    int ret = 0;
   
    jint *tmpHandle = env->GetIntArrayElements(Handle, 0);
    pHandle = (unsigned long *)tmpHandle;
   
    jint theArrayLength = env->GetArrayLength(Frame);
    frame_len = theArrayLength;
    pFrame = (THWFrame *)malloc( sizeof(THWFrame) * frame_len );
   
    ret = HWRC_GetInputBox(pHandle, pFrame);
   
    for( int i = 0; i < frame_len; i++ ){
        THWFrameStructTOObject(env, Frame, pFrame, i);
    }
   
    env->ReleaseIntArrayElements(Handle, tmpHandle, 0);
    free(pFrame);
    frame_len = NULL;
   
    return ret;
}
// {"HWRC_GetInputBox", "([I[Ljava/com/ginwave/fs/com/THWFrame)I" , (void *)com_ginwave_fs_com_HWRC_GetInputBox },
// check ok!

其中,比較難理解的應該是函數的簽名了,下面是他們的一些規則:
這個數組的類型是JNINativeMethod,定義如下:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
             
第一個變量name是Java中函數的名字。
第二個變量signature,用字符串是描述了函數的參數和返回值
第三個變量fnPtr是函數指針,指向C函數。

其中比較難以理解的是第二個參數,例如
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"
             
實際上這些字符是與函數的參數類型一一對應的。
"()" 中的字符表示參數,後面的則代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
具體的每一個字符的對應關係如下
             
字符             Java類型      C類型
V              void              void
Z              jboolean     boolean
I              jint         int
J                     jlong             long
D              jdouble           double
F               jfloat              float
B              jbyte             byte
C              jchar                     char
S               jshort             short
             
數組則以"["開始,用兩個字符表示
[I       jintArray          int[]
[F       jfloatArray         float[]
[B       jbyteArray          byte[]
[C        jcharArray          char[]
[S        jshortArray          short[]
[D       jdoubleArray         double[]
[J        jlongArray         long[]
[Z        jbooleanArray      boolean[]

objects對象          Lfully-qualified-class-name;         L類名
Arrays數組          [array-type                                 [數組類型

方法參數或者返回值為java中的對象時,必須以「L」加上其路徑,不過此路徑必須以「/」分開,自定義的對象也使用本規則,不在包中時直接「L」 加上類名稱。比如說 java.lang.String為「java/lang/String」,com.nedu.jni.helloword.Student為"com /nedu/jni/helloword/Student"

方法參數或者返回值為數組時類型前加上[,例如[I表示 int[],[[[D表示 double[][][],即幾維數組就加幾個[。
 
JNI函數中始終包含兩個必要的參數:JNIEnv* env, jclass clazz
JNIEnv *──它是一個接口指針,用於定位函數表中的函數!
在JNI規範中一般稱  為   「Interface Pointer」。看到這兒好像和過程調用很類似了!是的,JNI中的操作過程,就是面向過程的!後面的jobject是  一個指向該類的指針,類似與C語言中的this。這個第二個參數是變化的,當該方法為類的實例方法時該參數為jobject;當該方法為類方法 (即靜態方法)時該參數為jclass,指向該類的class。
通過ndk編程來得到jni層頭文件的時候,這第二個參數對於staic方法,生成出來的就是jclass,而對於非staic方法,生成出來的就是jobject。
             
從上圖可知,jobject包含了其實概括了所有的java類型,也就是說,像上圖中的非jobject類型的數據,在傳遞參數的時候都可以以 jobject類型傳遞下去。比如說,如果要java中要傳遞一個二(多)維int數組下去,就可以包裝成jobjectArray傳下去,只不過對應的 簽名要弄成[[I了。

對於訪問java對象的方法
在本地方法中調用Java對象的方法的步驟:
①.獲取你需要訪問的Java對象的類:
jclass cls = (*env)->GetObjectClass(env, obj);   // FindClass(「android/util/log」)
使用GetObjectClass方法獲取obj對應的jclass。 // 直接搜索類名,需要是static修飾的類。
②.獲取MethodID:
jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V");
// GetStaticMethodID(…)  , 獲取靜態方法的ID
使用GetMethdoID方法獲取你要使用的方法的MethdoID。其參數的意義:
env-->JNIEnv
cls-->第一步獲取的jclass
"callback"-->要調用的方法名
"(I)V"-->方法的Signature, 簽名同前面的JNI規則。
③.調用方法:
(*env)->CallVoidMethod(env, obj, mid, depth);
// CallStaticIntMethod(….) , 調用靜態方法
使用CallVoidMethod方法調用方法。參數的意義:
env-->JNIEnv
obj-->通過本地方法穿過來的jobject
mid-->要調用的MethodID(即第二步獲得的MethodID)
depth-->方法需要的參數(對應方法的需求,添加相應的參數)
註:這裡使用的是CallVoidMethod方法調用,因為沒有返回值,如果有返回值的話使用對應的方法,在後面會提到。
CallVoidMethod               CallStaticVoidMethod
CallIntMethod                     CallStaticVoidMethod
CallBooleanMethod              CallStaticVoidMethod
CallByteMethod                   CallStaticVoidMethod

其實jni中還有很多很多的接口函數這裡沒有列舉,可以直接參考源碼:
$ find  frameworks/base  type d  -name  jni
./voip/jni
./rfid/jni
./freestylus/jni
./native/graphics/jni
./drm/jni
./tests/BrowserTestPlugin/jni
./services/jni
./packages/TtsService/jni
./media/jni
./media/libdrm/mobile1/include/jni
./media/libdrm/mobile1/src/jni
./graphics/jni
./core/jni
./opengl/tests/gl_jni/jni
./opengl/tests/gl2_jni/jni
./opengl/tests/gldual/jni
這麼多jni目錄都可以參考,其中主要是core/jni目錄了。
四、關於異常
異常接口有:
jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
env->ThrowNew(env->FindClass("java/io/IOException"),"CWJLog Error, IOException");
doThrow(env, "java/lang/IllegalStateException", msg);
使用Throw,自己構造(沒用過)
jclass clazz = env->FindClass("java/io/IOException");
jmethodID methodId = env->GetMethodID(clazz, "", "()V");
jthrowable throwable = env->NewObject(clazz, methodId);
env->Throwthrowable);


參考網址:
http://blog.csdn.net/xyz_lmn/article/details/6959545
 Android JNI入門第三篇——jni頭文件分析 
http://blog.csdn.net/xyz_lmn/article/details/6966259
 Android JNI入門第四篇——Android.mk文件分析
http://blog.csdn.net/xyz_lmn/article/details/7017420
 Android JNI開發提高篇 
http://blog.csdn.net/xyz_lmn/article/details/6956003
 Android JNI入門第二篇——Java參數類型與本地參數類型對照

http://wenku.baidu.com/view/e9e28ca1b0717fd5360cdc18.html
JNI入門
http://www.ibm.com/developerworks/cn/java/j-jni/
使用 Java Native Interface 的最佳實踐
http://helloxuweifu.iteye.com/blog/1168647
http://blog.csdn.net/kangyaping/article/details/6584027
JNI函數調用大全

http://newfaction.net/2010/11/30/java-jni-getfieldid-and-getmethodid-and-parameter-description.html
java jni GetFieldID 和 GetMethodID 以及參數的說明
http://hi.baidu.com/spmno/blog/item/7d4d764ea78a6809b3de0588.html
jni中使用數組的幾個方法
http://xxw8393.blog.163.com/blog/static/3725683420107109411366/
JNI 返回結構體參數 
http://www.cnblogs.com/nicholas_f/archive/2010/11/30/1892124.html
JNI中java類型與C/C++類型對應關係
http://blog.csdn.net/sunny09290/article/details/6884994
JNI數據類型
http://www.cnblogs.com/liangwind/archive/2009/08/18/1925515.html
jni --c/c++ 數據類型、數組、對象
http://www.cnblogs.com/diyunpeng/archive/2009/09/24/1573296.html
Java有符號數與無符號數
http://www.stuhack.com/biancheng/java/35169.html
Java的基本數據類型是無符號的

JNI错误之:error: base operand of '->' has non-pointer type '_JNIEnv'

第一次使用JNI的时候,我是用C实现的,但是我实现的方法写成了C++的格式,比如:
jstring Java_com_unistron_barcode_getBarcode(JNIEnv *env, jobject jthis, int cmd){
return env->NewStringUTF((char *) "Hello from JNI !");
}
这个方法在调用的时候就会报这个错误,因为c和c++对JNIEnv的定义是不同的,从jni.h下面代码看得出来:

if defined(__cplusplus)

typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;

else

typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;

endif

c++是由struct _JNIEnv实现的
所以正确的返回应该是:
jstring Java_com_unistron_barcode_getBarcode(JNIEnv *env, jobject jthis, int cmd){
//return (*env)->NewStringUTF(env, "Hello from JNI !");//如果是用C语言格式就用这种方式
//return env->NewStringUTF((char *)"Hello from JNI !");//C++用这种格式
}
声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息
原文作者: LakeSide
原文地址: http://my.eoe.cn/lakeside/archive/3198.html

2013年6月6日 星期四

Use command to send mail with Gmail

// install pkg
# sudo apt-get install mutt

// setup configure
# sudo gvim /etc/Muttrc


set from = "yourmailaccount@gmail.com"
set realname = "yourname"
set imap_user = "yourmailaccount@gmail.com"
set imap_pass = "yourmailpassword"
set folder = "imaps://imap.gmail.com:993"
set spoolfile = "+INBOX"
set postponed ="+[Gmail]/Drafts"
set header_cache =~/.mutt/cache/headers
set message_cachedir =~/.mutt/cache/bodies
set certificate_file =~/.mutt/certificates
set smtp_url = "smtp://yourmailaccount@smtp.gmail.com:587/"
set smtp_pass = "yourmailpassword"
set move = no
set imap_keepalive = 900

//create cache folder
mkdir -r .mutt/
mkdir -r .mutt/cache/


Synergy in Ubuntu

// install synergy
# sudo apt-get install quicksynergy

// setup configure
# gvim .quicksynergy/synergy.conf

section: screens
    terry-desktop:
    TWTPEN1107043:
end
section: links
    terry-desktop:
        left = TWTPEN1107043
    TWTPEN1107043:
        right = terry-desktop
end


// run command
# /usr/bin/synergys -f --config .quicksynergy/synergy.conf


2011年7月25日 星期一

Ubuntu auto mount SMB folder

First you have to install smbfs:

sudo apt-get install smbfs

Then create a folder inside of the /media directory to mount the share on:

sudo mkdir /media/Storage

then you can run the following command to mount a share manually:

sudo mount -t smbfs //fileserver/Storage /media/Storage -o uid=USER,gid=users

Note: Change USER to your linux username. The uid=USER,gid=users is important because if you dont use that, only root will have access to write files to the mounted share.

Or you can edit the mount list in /etc/fstab to have the drive mount on boot

sudo gedit /etc/fstab

And add this line to the bottom of the fstab file, but change //fileserver/Storage to the path to your share on your server.

//fileserver/Storage /media/Storage smbfs credentials=/.smbcredentials,uid=USER,gid=users 0 0

In the above line change USER to your user account in both spots. Before this will work you also have to create the .smbcredentials file in the above users home directory.

sudo gedit ~/.smbcredentials

Add the following information to the file, but change Guest to your SMB username and add your SMB password.

username=Guest
password=

If you have a permission problem , you can add "noperm" .

Now you got it.

2010年11月18日 星期四

「轉貼來源-http://xy0811.spaces.live.com/default.aspx」xserver

任何一個X應用程序,包括WM在內都是XClient; XClient不負責任何圖形相關的具體操作,只和xserver交互,由xserver負責完成其圖形顯示任務,這種交互一般來說是通過在底層調用xlib實現的; Xclient的核心任務是計算和數據處理。

對XServer的理解

1. XServer/XClient通過X協議交互, 而X協議就是一套基於socket的通信
2. XServer啟動時初始化socket, 並進入Select循環,
等socket連接(多個連接時形成client隊列), 鍵鼠等
3. XClient啟動時連接該socket, 與XServer建立起一個通道,
然後任何圖形相關的操作都通過XServer實現
4. 好處在於: 多個XClient同時運行時, 在XServer之上可做互斥, 共享, 疊加等


linux的一個瀏覽器是這樣實現的:
1. XServer: 圖形顯示, 根據XClient的控制顯示(見nano-X)
2. Xlib: 對XServer提供功能的封裝, 供XClient調用,
底層通過socket和XServer交互(見xcblib)
3. WindowManager: 控制各應用窗口之間關係
4. gtk庫: 控件, 及消息處理
5. 瀏覽器程序

2010年11月17日 星期三

「轉貼來源-http://xy0811.spaces.live.com/default.aspx」Linux的X窗口系統結構說明

一、說明
X Server為中心,簡要地分為四層,如圖所示

二、X方式與Framebuffer方式的差異

1. X方式

1) 什麼是X
我們常說的X WindowXX11(X協議的11版本)一般指X協議,或指是基於X協議的X服務端程序(X Server)

2) X ServerX Client

a) X協議指X ServerX Client組成的c/s架構,及其通訊協議的實現

b) X Server有主事件循環,由它來處理用戶輸入、顯示及與X Client通訊

c) X Client即X桌面上運行的普通應用程序
應用程序如果想顯示數據,需要利用X Lib庫建立X窗口(X Client),它通過X協議與X Server通訊,讓X Server完成顯示;X Server會把接到鍵盤鼠標事件,傳給焦點所在的X Client處理

2. Framebuffer方式
Framebuffer
方式相對簡單,它由內核直接支持,通常用於嵌入式系統。應用程序可以得到屏幕顯示區域的指針,然後對其寫數據來進行顯示,其中窗口的概念不強,它自身不帶窗口管理,需要應用軟件自己管理窗口。比如qtopia基本於framebuffer顯示時,qtopia自身實現了窗口管理功能

3. 應用程序的顯示方式
很多應用程序同時支持XFramebuffer兩種模式顯示,如gtkqt等,以下我們只討論它基本於X實現的部分

三、分層

1. 應用層(Application)
指X Window上運行所有帶圖形界面的應用程序,每個窗口都是一個X Client

1) X Lib app
直接使用X函數的應用程序,這種程序一般界面簡單,比較底層,比如很多窗口管理器直接寫在這層

2) Gtk app
gtk
又分為gtkgdk兩層,

gtk
為控件及主循環的實現
gdk
相對底層,控制底層繪圖部分,它支持framebufferX11DirectFb
應用程序可調用gtk函數,也可直接調用gdk函數
gtk
常和cairo一起實現二維特效

3) Qt app
Qt
也通過調用X Lib實現圖形界面

Qt
的優勢在於它是C++實現的,使用起來程序結構更好,也有較成熟的嵌入式版本

4) SDL app
SDL
也通過調用X Lib實現圖形界面

SDL
更底層,代碼少,沒有控件,但做特殊效果很好用

2. 窗口管理器層(Window manager簡稱wm)
Window manager
是特殊的X Client,也通過X Lib庫與X Server交互,與一般應用不同的是:它負責控制各個窗口的動作,及操作主窗口

WM
的功能分為管理(manager)和工具(tools)

1) Manager
負責各個窗口的建立銷毀/顯示隱藏/最大最小化/移動縮放,管理窗口隊列,設置焦點窗口,窗口切換效果等

2) Tools
實現桌面工具條,桌面菜單等基本界面及小工具

3) 具體實現
實現通常有兩種方式:一種是managertools在一個程序中實現,一種是分開兩個程序實現,使用時可以隨意組合

a) qvwm, blackbox等較早期的wm,都是managertools在一個程序中實現的

b) xfcemetacity等是分開的,例如:xfce包含toolsmanager,但不在一個程序中實現,它的managerxfwm,我們可在使用xfce時把xfwm替成metacity(metacity是一個manager,不帶tools)

3. X服務器層(X Server)
主循環控制顯示,讀取設備數據,與X Client通訊,事件循環,並把事件送給焦點窗口

1) 普通X Server
功能完整的X Server,代碼量大,支持全,常見的如XFree86,Xorg

2) Tiny X Server
一般用於嵌入式系統,資源佔用小,代碼少,功能及邏輯相對簡單,如KDriveXvesa/Xchips/Xfbdev/Xi810……

4. 系統底層(System)

1) Kernel
與硬件交互,獲得輸入設備的數據,向顯示設備輸出

2) Dev
文件系統中的設備文件,程序通過對它的讀寫和操作與kernel交互,控制硬件

3) 中間層
在程序和Dev層之間,有時還需要庫或程序處理設備數據,比如觸摸屏就使用libts去除噪點,過濾出更有效的數據