Monday, December 29, 2014

使用 xmllint 處理/驗證 xml



xmllint是一個很方便的處理及驗證xml的工具,linux下只要安裝libxml2就可以使用這個命令,下面整理一些常用功能
1. --format
此參數用於格式化xml,使其具有良好的可讀性。
假設有xml(person.xml)內容如下:

<person><name>ball</name><age>30</age><sex>male</sex></person>

執行:
xmllint --format person.xml  
得到易讀的xml

    <person>  
          <name>ball</name>  
          <age>30</age>  
          <sex>male</sex>  
    </person>
    2. --noblanks
    與--format相反,有時為了節省傳輸量,我們希望去掉xml中的空白,這時我們可以使用--noblanks命令。
    假設xml(person.xml)內容如下

    <?xml version="1.0"?>  
    <person>  
      <name>ball</name>  
      <age>30</age>  
      <sex>male</sex>  
    </person>
    
      執行:
      xmllint --noblanks person.xml  
      得到去掉空白後的xml

      ball30male
      



      3.--schema
      使用scheam驗證xml文件的正確性(瞭解schema的知識請猛擊這裡
      假設有xml文件(person.xml)和scheam文件(person.xsd)文件,內容分別如下
      person.xml

      <?xml version="1.0"?>  
      <person>  
        <name>ball</name>  
        <age>30</age>  
        <sex>male</sex> 
      </person>
      

      person.xsd

      <?xml version="1.0"?>  
      <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">  
        <xs:element name="name" type="xs:string"/>  
        <xs:element name="age" type="xs:integer"/>  
        <xs:element name="sex">  
          <xs:simpleType>  
            <xs:restriction base="xs:string">  
              <xs:enumeration value="male"/>  
              <xs:enumeration value="female"/>  
            </xs:restriction>  
          </xs:simpleType>  
        </xs:element>  
        <xs:element name="person">  
          <xs:complexType>  
            <xs:all>  
              <xs:element ref="name"/>  
              <xs:element ref="age"/>  
              <xs:element ref="sex"/>  
            </xs:all>  
          </xs:complexType>  
        </xs:element>  
      </xs:schema>
      
      執行:

      xmllint --schema person.xsd person.xml  
      得到

        
        ball  
        30  
        male  
        
      person.xml validates 
      
      注意,默認情況下,驗證後會輸出驗證的文件內容,可以使用 --noout選項去掉此輸出,這樣我們可以只得到最後的驗證結果。
      執行

      xmllint --noout --schema person.xsd person.xml   
      得到

      person.xml validates  

      下面我們改動person.xml
      <?xml version="1.0"?>  
      <person>  
        <name>ball</name>  
        <age>not age</age>  
        <sex>test</sex>  
      </person>
      


      顯然,這份文件age字段和sex都是不符合xsd定義的。
      執行

      xmllint --noout --schema person.xsd person.xml  
      得到:

      person.xml:4: element age: Schemas validity error : Element 'age': 'not age' is not a valid value of the atomic type 'xs:integer'.  
      person.xml:5: element sex: Schemas validity error : Element 'sex': [facet 'enumeration'] The value 'test' is not an element of the set {'male', 'female'}.  
      person.xml:5: element sex: Schemas validity error : Element 'sex': 'test' is not a valid value of the local atomic type.  
      person.xml fails to validate 
      
      good!xmllint成功的報出了錯誤!

      4. 關於--schema的輸出
      在講輸出之前先看下面一個場景,假如你想通過php執行xmllint然後拿到返回結果,你的代碼通常應該是這個樣子
      valid.php
      <?php  
      $command = "xmllint --noout --schema person.xsd person.xml";  
      exec($command, $output, $retval);  
      //出錯時返回值不為0  
      if ($retval != 0){   
              var_dump($output);      
      }  
      else{  
          echo "yeah!";  
      }
      
      我們保持上文中person.xml的錯誤。
      執行此代碼,你會發現,你拿到的output不是錯誤,而是array(0) {}, amazing!
      為什麼會這樣呢?
      因為xmllint --schema,如果驗證出錯誤,錯誤信息並不是通過標準輸出(stdout)顯示的,而是通過標準錯誤(stderr)進行顯示的。
      而exec的output參數拿到的,只能是標準輸出(stdout)顯示的內容。
      所以,為了拿到出錯信息,我們需要將標準錯誤重定向到標準輸出,對應修改代碼:
      $command = "xmllint --noout --schema person.xsd person.xml 2>&1";  

      再次執行valid.php,錯誤信息順利拿到!
      附小問題
      --noout參數關閉的是什麼輸出呢:)

      Monday, September 29, 2014

      打開Android C文件中的LOG

      資料來源: http://www.bobbog.com/archives/10

      可以一次打開LOGV,LOGI,LOGD,也可以分別打開:
      #undef NDEBUG       //打開LOGV/LOGI/LOGD
      #define LOG_NDEBUG   0  //打開LOGV
      #define LOG_NIDEBUG  0  //打開LOGI
      #define LOG_NDDEBUG 0 //打開LOGD
      

      舉例

      舉例,如果要看AndroidRuntime的LOGI和LOGD,可以有這樣2種寫法:

      方法一

      NDEBUG-LOG_NDEBUG=LOG_NIDEBUG +LOG_NIDEBUG
      #define LOG_TAG "AndroidRuntime"
      #undef NDEBUG
      #define LOG_NDEBUG 1
      #include <utils/Log.h>
      

      方法二

      LOG_NIDEBUG +LOG_NIDEBUG
      #define LOG_TAG "AndroidRuntime"
      #define LOG_NIDEBUG 0
      #define LOG_NDDEBUG 0
      #include <utils/Log.h>
      

      Wednesday, September 24, 2014

      git 打包的一个bash 函数


      資料來源: http://blog.csdn.net/free2o/article/details/3981786




      Here is my bash alias. The argument is the <branch name> to export.
      An example:
      
          cd /path/to/foo/
          _gittar master
      
      The output is (time in ISO 8601 / UTC):
      
          ../foot-YYYYMMDD.HHMM.tar.gz
      
      function _gittar ()
      {
          local name=$(pwd)
          name=${name##*/}
      
          if [ ! "$1" ]; then
              echo "[ERROR] what branch to export?"
              return 1
          fi
      
          local date=$(TZ=UTC date '+%Y%m%d.%H%M')
          local pkg="$name-$date"
          local dir=".."
          local tar="$dir/$pkg.tar.gz"
      
          git archive /
              --format=tar /
              --prefix="$pkg/" /
              "$@" |
          gzip --best > "$tar"
      
          echo $tar
      }

      Friday, April 18, 2014

      repo 的用法

      資料來源: http://blog.csdn.net/free2o/article/details/3981588

      1. 下載 repo 的地址: http://android.git.kernel.org/repo ,可以用 wget http://android.git.kernel.org/repo 或者 curl http://android.git.kernel.org/repo >~/bin/repo  來下載 repo , chmod a+x ~/bin/repo
      2. 用repo sync 在抓去 android source code 的時候,會經常出現一些錯誤導致 repo sync 中斷,每次都要手動開始。 可以用如下的命令,來自動重複:   $?=1;   while [ $? -ne 0 ] ; do  repo sync ; done
      3.  repo help [ command ] , 顯示command 的詳細的幫助信息內容
      4. repo init -u URL ,  在當前目錄安裝 repository ,會在當前目錄創建一個目錄 ".repo"  -u 參數指定一個URL, 從這個URL 中取得repository 的 manifest 文件。   repo init -u git://android.git.kernel.org/platform/manifest.git
                     可以用 -m 參數來選擇 repository 中的某一個特定的 manifest 文件,如果不具體指定,那麼表示為默認的 namifest 文件 (default.xml)    repo init -u git://android.git.kernel.org/platform/manifest.git -m dalvik-plus.xml
                    可以用 -b 參數來指定某個manifest 分支。
                     repo init -u git://android.git.kernel.org/platform/manifest.git -b release-1.0
                    可以用命令: repo help init 來獲取 repo init 的其他用法
              4. repo sync [project-list]
                  下載最新本地工作文件,更新成功,這本地文件和repository 中的代碼是一樣的。 可以指定需要更新的project , 如果不指定任何參數,會同步整個所有的項目。
                 如果是第一次運行 repo sync , 則這個命令相當於 git clone ,會把 repository 中的所有內容都拷貝到本地。 如果不是第一次運行 repo sync , 則相當於 git remote update ;  git rebase origin/branch .  repo sync 會更新 .repo 下面的文件。 如果在merge 的過程中出現衝突, 這需要手動運行  git  rebase --continue
            5. repo update[ project-list ]
            上傳修改的代碼 ,如果你本地的代碼有所修改,那麼在運行 repo sync 的時候,會提示你上傳修改的代碼,所有修改的代碼分支會上傳到 Gerrit (基於web 的代碼review 系統), Gerrit 受到上傳的代碼,會轉換為一個個變更,從而可以讓人們來review 修改的代碼。
             6. repo diff [ project-list ]
              顯示提交的代碼和當前工作目錄代碼之間的差異。
             7. repo download  target revision
              下載特定的修改版本到本地, 例如:  repo download pltform/frameworks/base 1241 下載修改版本為 1241 的代碼
             8. repo start newbranchname
              創建新的branch分支。 "." 代表當前工作的branch 分支。
             9.  repo prune [project list]
              刪除已經merge 的 project
            10. repo foreach [ project-lists] -c command
             對每一個 project 運行 command 命令
            11. repo status
             顯示 project 的狀態

      Friday, February 21, 2014

      Debug Android and Linux suspend and resume (中文)

      資料來源: http://blog.csdn.net/laojing123/article/details/7874221

      攢了一些關於調試Android和Linux下面的suspend 和 resume的經驗, 在這裡和大家分享一下。
      希望可以有些幫助, (下面沒有寫Android專用的, 就是Linux通用的)。
      1. no_console_suspend 
      在kernel啟動參數里面加上no_console_suspend, 這個是最基本的, 因為kernel在把console suspend掉以後, 不管裡面出了什麼事情, 從串口上都看不到。 大部分在suspend/resume時候的死機都可以通過串口看到kernel Panic的信息, 這樣才會知道是哪裡出了問題。因為有的時候resume出錯, 或者suspend到很後面出錯的console不加這個參數都看不到。
      2. initcall_debug
      這個也許知道的人不多, 其實有的時候你不知道哪個driver在suspend/resume的時候出錯的時候,很迷茫, 就想在哪裡加上一些調試信息來看看是哪裡的driver, 其實有些時候加的不合適的話, 會看不到很多有用的信息。其實kernel本身已經有這樣的功能了(只不過不是很人性化)。
       
      echo 1 > /sys/module/kernel/parameters/initcall_debug echo 9 > /proc/sys/kernel/printk 
      第一條命令是打開initcall_debug, 這個是所有的kernel都會有的, 也可以在啟動參數里面加initcall_debug來默認打開這個參數, 這樣可以調試系統啟動。
      因為這些信息都是KERN_DEBUG級別的, 所以需要提高printk的級別才可以看到, 要不然suspend/resume的時候死掉了,你就沒有機會看到這些信息了。
      3. suspend_test
      這個方法可以用rtc這種軟件的方式來做循環的suspend/resume, 儘管對於Android這樣並不是很足夠, (你得模擬一個POWER_KEY上去才夠), 但是對於調試Driver的穩定性, 還是有一定用處的。 不要以為suspend了幾次可以, 那麼就可以通過幾千次的測試。 這個suspend是5秒鐘用RTC喚醒, 然後對於Android, 5秒鐘又會自動睡下去, 但是對於通用Linux, 你得寫個小腳本來讓他一會再睡下去, 或許這個工具比較有用rtcwakeup(google rtcwakeup)。
      使用方法:
      編譯一個有這個功能的kernel, make menuconfig 以後選上
      CONFIG_PM_DEBBUG=y
      CONFIG_PM_TEST_SUSPEND=y
      這兩個選項
      燒寫新的kernel,然後打開你需要測試的東東, 比如WIFI,3G
      echo "core" > /sys/power/pm_test
      echo "mem" > /sys/power/state
      這樣, 它就會循環休眠和喚醒了。
      4. wakelock
      輪到Android的調試了, Android裡面和Power相關最大的就是wakelock,  有時候會碰到睡不下去,或者睡到最後彈起來的問題, 就是wakelock引起的,或者說是wakelock的使用者引起的。
      怎麼調試呢,用一下兩個:
      echo 15 > /sys/module/wakelock/parameters/debug_mask
      echo 15 > /sys/module/userwakelock/parameters/debug_mask
      15是代表16進制的F, 在wakelock裡面就是把所有的debug信息打開, 起碼現在是。如果以後不夠了,估計得輸入255.
      這樣你能看到kernel和frameworks層對於wakelock的操作, 申請和釋放。 這樣看申請和釋放成對否就可以了。注意: wakelock有一種是timeout的, 就是說多少毫秒以後, 會自動釋放, 對於這些wakelock, 申請和釋放可能是不成對的。。
      5. power.0
      有的時候你會看到系統suspend到了最後, 然後遇到power.0 suspend失敗,然後整個系統都又resume起來了。 這個是android專有的,因為power.0是android註冊到suspend最後的一個回調, 它會在CPU進入suspend之前檢查一下有沒有wakelock, 如果這時候還有沒有釋放的wakelock, 那麼它會返回-EBUSY然後導致整個suspend失敗。 調試這個問題的方法就是把上面wakelock的debug信息打開, 然後看看是哪個傢伙去申請了wakelock,然後幹掉它。
      這個錯誤的錯誤信息大概是這樣的:
      pm_noirq_op(): platform_pm_suspend_noirq+0x0/0x38 returns -11
      PM: Device power.0 failed to suspend late: error -11
      6. earlysuspend
      差點忘掉這個哥們, android裡面另外一個pm相關的大東東, 同樣可以加:
      echo 15 > /sys/module/earlysuspend/parameters/debug_mask
      來把相關的debug信息打印出來, 比如那個earlysuspend要被call之類的。
      7. suspend/resume time.
      有的時候你要調試suspend/resume的時間太慢的問題。 一種方法是用initcall_debug, 然後把printk的時間戳打上, 然後看哪個很慢。
      但是這樣會讓你的生活很枯燥:)
      我有一個patch,專門用來調試這個問題的,但是upstream不接受, 說非要用這種折磨人的方法才行, 但是如果你想用可以下下來打上去用一下。
      地址在這裡:http://www.spinics.net/lists/linux-pm/msg24063.html
      用法是, 打上這個PATCH以後, 在KERNEL裡面選擇上PM_DEBUG, SUSPEND_DEVICE_TIME_DEBUG 這兩個選項。
      然後
      echo 微秒 > /sys/power/device_suspend_time_threshold
      比如
      echo 50000  > /sys/power/device_suspend_time_threshold
      注意這裡是微秒哦。。。 它會把在suspend/resume的時候慢的那些driver打出來,然後你去幹掉它。。。