2010年10月27日 星期三

應用程式如何取得系統權限

在Android上執行不同的apk會跑在不同的sandbox上, 並且以不同的身份(uid)在執行, 但問題是我今天想要用system身份做某些事或是想要在不同的app分享資源時, 就會需要能對apk指定uid, 方法有兩種分別說明如下:

方法一
1.修改AndroidManifest.xml, 新增android:sharedUserId="android.uid.system"屬性(使用system身份)
2.修改Android.mk文件,加入LOCAL_CERTIFICATE := platform這一行

3.重新編譯apk

PS. LOCAL_CERTIFICATE := platform, 由於試驗的這份source code 是由客戶提供,所以"platform"這個關鍵字已經被定義好了.

方法二
1.如方法一修改AndroidManifest.xml, 新增 android:sharedUserId="android.uid.system" 屬性(使用system身份)
2.使用Eclipse編譯出apk
3.刪除該apk中META-INF目錄下的CERT.SF和CERT.RSA兩個檔案
4.以系統的public/private key重新簽署打包apk, signapk的用法為

Usage: signapk [-w] publickey.x509[.pem] privatekey.pk8 input.jar output.jar
5.實際執行命令如下.
$java -jar signapk.jar -w ./platform.x509.pem ./platform.pk8 ./input.apk ./output.apk(此為將所有檔案放於同一路徑下)

PS. signapk.jar , platform.x509.pem, platform.pk8可於source code中取得
如果想要不同的apk以相同的uid身份在執行, 則在這些不同的APK中AndroidManifest.xml的語法為

manifest xmlns:android="http://schemas.android.com/apk/res/android" android:sharedUserId="{MY.URI.FORMAT}"

在Ubuntu上安裝及設定NDK

1. 下載NDK for Ubuntu,位置可任意決定.

2. 編輯 bashrc
    1) 於終端機下command "sudo gedit ~/.bashrc", 添加下面文字.
    2) NDK_ROOT=android_ndk_path, 後面的目徑是NDK的目錄,前面的名稱可任取.
         ex: NDK_ROOT=/home/favoritepili/Android/android-ndk-r4b/
     3) export NDK_ROOT
     4)儲存,離開.
     PS.  由於是下載r4版,所以從此版開始不需要修改host-setup.sh

3. 測試
     1) 進入目標compile目錄. ex: "/home/favoritepili/Android/android-ndk-r4b/samples/hello-jni"
     2) type "$NDK_ROOT/ndk-build
     3) 如果成功會產生obj及libs兩個目錄

4. error
   1) 如果有錯誤訊息"Your APP_BUILD_SCRIPT points to an unknown file".
       確認你的路徑有沒有設錯, APP_BUILD_SCRIPT設定在project的.mk檔中.

   2)可以type command "$NDK_ROOT/ndk-build NDK_LOG=1", 來查看有何問題.

建立Windows cmd.exe 的shortcut

建立Windows cmd.exe shortcut

1. 在檔案總管任意路徑下按右鍵選"新增","捷徑".
2. 在輸入項目的位置中打"%COMSPEC%",然後按下一步.
3. 捷徑的名稱可任意取,然後按完成.
4. 點選此捷徑按右鍵.
5. 於"捷徑"此分頁中的"開始位置"輸入你想要執行cmd.exe時的預設位置. ex:"F:\Tools\AndroidNeedTools\android-sdk-windows\tools"
6. 完成.

2010年9月10日 星期五

android adb command

1. 偵測裝置
adb devices
PS. 如果在type "adb devices"後出現device offline,有可能是低電壓.也可嘗試type "adb kill-server XXXXXX",再重新type "adb devices".
2. 安裝檔案
adb install -r F:\aaa.apk
3. 取得手機資訊
adb getprop
PS.這是未出廠手機可以使用.
4. copy file to device
adb push f:\led_control.so /system/lib/led_control.so
5. 刪除檔案
adb shell rm -r /system/sd/app
6. 取得BT資料
    1) adb shell
    2) hcitool
7. 取得wifi, power, connectivity...
    svc wifi [enable | disable]
    svc wifi prefer (set wifi as the preferred data network)
    svc power [ ]
    svc data [ ]
    svc help
8. 同時看adb logcat並同時存下logcat
    adb logcat | tee logcat.txt
9. Run CTS test
start --planCTS -P android.security.cts.package in [ \build\core\Makefile.in$(PACKAGE)]
如果要測細項.
10. Launcher application
      adb shell am start -n packagename/.Intent
      ex: adb shell am start -n com.example/.Welcome

2010年3月6日 星期六

How to read XML file

Parsing XML
/********************Code****************************/

#include

#include
TCHAR szCountryName[MAX_LOADSTRING];
int nCurMCC;
int nProc;
int nCountryPos = -1, nCountryIndex = -1, nOldPos = -1;
int nOperatorPos = -1, nOperatorIndex = -1;
COperatorLinkList *OperatorList;

void ProcessNode(IXMLDOMNode *lpNode)
{
IXMLDOMNamedNodeMap *pAttr; // xml 的屬性列表
IXMLDOMNodeList *pNodeList; // xml節點列表接口
IXMLDOMNode *pNode; // xml節點接口
BSTR name, bstrAttrName;
VARIANT value, varAttrValue;
TCHAR szText[MAX_LOADSTRING], szText1[MAX_LOADSTRING];
LPWSTR lpStr;
long len;
int nCurMNC;
TypeConfigInfo *pTempConfigList;
COperatorLinkList *OperatorListTmp = new COperatorLinkList;

lpNode->get_nodeName(&name); // 得到節點名稱,也就是TAG
lpNode->get_nodeValue(&value); // 得到節點值
lpNode->get_attributes(&pAttr); // 得到節點屬性列表
pAttr->get_length(&len);
for(int i = 0; i <>get_item(i, &pNode); // 得到屬性列表中的一個屬性節點
pNode->get_nodeName(&bstrAttrName); // 得到屬性名
pNode->get_nodeValue(&varAttrValue); // 得到屬性值
lpStr = (LPWSTR)name;

if((wcscmp(lpStr, TEXT("entry"))) == 0)
{
nProc = 2;
switch (i)
{
case 0:
lpStr = (LPWSTR)varAttrValue.bstrVal;
nCurMNC = _wtoi(lpStr);
nOperatorPos++;
nOperatorIndex++;
break;
case 1:
lpStr = (LPWSTR)varAttrValue.bstrVal;
wcscpy(szText, lpStr);
break;
case 2:
lpStr = (LPWSTR)varAttrValue.bstrVal;
wcscpy(szText1, lpStr);
break;
}
}
else if(wcscmp(lpStr, TEXT("country")) == 0)
{
nProc = 1;
switch (i)
{
case 0:
lpStr = (LPWSTR)varAttrValue.bstrVal;
wcscpy(szCountryName, lpStr);
nCountryPos++;
nCountryIndex++;
break;
case 1:
lpStr = (LPWSTR)varAttrValue.bstrVal;
nCurMCC = _wtoi(lpStr);
nOperatorPos = -1;
nOperatorIndex = -1;
break;
}
}

}

if(nProc == 2) //先確定有Operator了才新增,
{
if(nOperatorPos != 0)
{
if(OperatorListTmp)
delete OperatorListTmp; //不是新的國家就刪除,延用舊的,一筆一筆接下去

if((wcscmp(szText1, TEXT(""))) == 0)
nOperatorIndex--;

OperatorList->Add(nOperatorPos, nOperatorIndex, nCurMCC, nCurMNC, szText, szText1);
}
else
{
if(OperatorListTmp != NULL)
{
OperatorList = OperatorListTmp; //是新的國家
pTempConfigList = OperatorList->Add(nOperatorPos, nOperatorIndex, nCurMCC, nCurMNC, szText, szText1);
if(nCountryPos != nOldPos)
{
CountryList.Add(nCountryPos, nCountryIndex, szCountryName, pTempConfigList);
nOldPos = nCountryPos;
}
}
}
}

lpNode->get_childNodes(&pNodeList); // 得到節點的字節點列表
pNodeList->get_length(&len);
for(int j = 0; j <>get_item(j, &pNode);
ProcessNode(pNode); // 遞回處理下層節點
}
}

VARIANT VariantString(BSTR str)
{
VARIANT var;
VariantInit(&var);
V_BSTR(&var) = SysAllocString(str);
V_VT(&var) = VT_BSTR;
return var;
}

BOOL LoadCountries()
{
IXMLDOMDocument *pXMLDom = NULL;
IXMLDOMNodeList *pNodes = NULL;
IXMLDOMNode *pNode = NULL;
BSTR bstr = NULL;
VARIANT_BOOL status;
VARIANT var;
HRESULT hr;
long length;

CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void **) &pXMLDom);
hr = pXMLDom->put_async(VARIANT_FALSE);
hr = pXMLDom->put_validateOnParse(VARIANT_FALSE);
hr = pXMLDom->put_resolveExternals(VARIANT_FALSE);

if (!pXMLDom)
goto clean;

VariantInit(&var);
var = VariantString(XML_PATH);
hr = pXMLDom->load(var, &status);

if (status != VARIANT_TRUE)
goto clean;


IXMLDOMElement *pElem; // xml元素接口
IXMLDOMNodeList *pNodeList; // xml節點列表接口

pXMLDom->get_documentElement(&pElem); // 得到xml文檔的根,就是上面的xml的Root節點
pElem->get_childNodes(&pNodeList); // 得到root的子節點列表
pNodeList->get_length(&length); // 得到root的子節點數量
for(int i = 0; i <>get_item(i, &pNode); // 得到一個字節點
ProcessNode(pNode); // 調用處理函數處理
}

return TRUE;

clean:
if (bstr)
SysFreeString(bstr);
if (&var)
VariantClear(&var);
if (pXMLDom)
pXMLDom->Release();
if (pNodes)
pNodes->Release();
if (pNode)
pNode->Release();

CoUninitialize();
return FALSE;
}
/********************Code****************************/



XML sample
/********************XML sample**********************/



/********************XML sample**********************/

2010年3月4日 星期四

ListView sort item at anytime

ListView_SortItems可以用來排序,但只能在按在column時進來排序, 在其它時間點即便call ListView_SortItems(hwnd, CompareFunc, lParamSort), 在CompareFunc callback function中的lParam1, lParam2也會是NULL.
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

所以,你如果想利用ListView的ListView_SortItems來進行排序卻又不想受限,就模擬OS的message loop,模擬按下ListView的clomun,就能在任何時間點進行sort.

//------------------------------Code-----------------------------------
int nColumnWidth[3]; //假設有3個column
for(int i = 0 ; i < 3; i++)
nColumnWidth[i] = ListView_GetColumnWidth(g_hwndLV, i);

DWORD dwPos = 0;

for(int i = 0; i < g_nSortColumn; i++)
dwPos = dwPos + nColumnWidth[i];

dwPos = dwPos + (nColumnWidth[g_nSortColumn] / 2) + SORT_POS_Y; // SORT_POS_Y的值為0x00140000

HWND hWndListViewHeader = ListView_GetHeader(g_hwndLV);
PostMessage(hWndListViewHeader, WM_SETCURSOR, (WPARAM)hWndListViewHeader, 0x02010001); //lParam固定為0x02010001
PostMessage(hWndListViewHeader, WM_LBUTTONDOWN, 0X00000001, dwPos); // wParam 固定為0X00000001
PostMessage(hWndListViewHeader, WM_LBUTTONUP, 0X00000001, dwPos);


//------------------------------Code-----------------------------------

dwPos 的算法為4個bit一個數字,前4個bit代表Y,後4個bit代表X, 0X0014006A代表座標X:106, Y:20