Android NDK Bionic API篇(三)
Android NDK Bionic API篇
前言
本篇重點學習一下NDK的核心開發庫Bionic API庫,通過Bionic API我們可以開發各種各樣的原生功能,真正發揮原生開發的強大功能。
Bionic基礎
Bionic是什麼
Bionic是Android平臺為了使用C/C++進行原生應用程式開發所有提供的POSIX標準C庫。它是Google為Android作業系統提供的BSD標準C庫的衍生庫。同時Bionic是專門為移動計算而精心設計的,針對移動裝置上有限的CPU週期和可用記憶體進行了裁剪以提高工作效率。
Bionic相容性怎麼樣
Bionic儘管是C標準庫,但是它不以任何方式與其它C庫二進位制相容。也就是說Bionic和其它C庫不相容,無法進行交叉編譯和相互引用。
Bionic提供什麼功能
Bionic提供了C標準庫,型別定義,函式和少數Android特有的特性。
主要功能可以概括如下:
1. 記憶體管理
2. 檔案輸入輸出
3. 字串操作
4. 數學函式
5. 日期和時間
6. 程序控制
7. 訊號處理
8. 網路套接字
9. 多執行緒
10. 使用者和組
11. 系統配置
12. 命名服務切換
Bionic還缺什麼功能
Bionic是專門為移動計算而精心設計的,所以Bionic不會支援所有C標準庫函式。也就是說它是C標準庫的一個子集。
如圖
Bionic記憶體管理
記憶體分配方式
靜態記憶體分配
適用於在程式碼中定義的靜態變數和全域性變數,靜態分配在應用程式啟動時自動發生。
自動記憶體分配
適用於函式引數和函式內的區域性變數,自動記憶體分配在函式呼叫時和函式內部有效,在函式使用完會自動釋放。
動態記憶體分配
動態分配是在程式執行時進行的,取決於當時的記憶體環境,如果需要的記憶體較大,可能會出現分配不成功的情況。
C語言記憶體管理
C語言不提供對內建動態記憶體管理的支援,不像C++,可以使用new關鍵字來動態生成一個物件。C語言必須使用C庫提供的函式來使用動態記憶體。
C語言使用記憶體管理函式,需要包括stdlib.h標頭檔案
C語言動態分配記憶體
C語言使用malloc函式來動態分配記憶體,malloc函式原型如下:
void* malloc(size_tbyte_count);
示例如下:
const char *str2="hello world"; char *str=(char*)malloc(strlen(str2)); strcpy(str,str2);
C語言調整記憶體大小
C語言使用realloc函式來調整記憶體大小,realloc函式原型如下:
void* realloc(void* p, size_t byte_count)
示例如下:
const char *str2="hello world"; int len=strlen(str2); char *str=(char*)malloc(strlen(str2)); strcpy(str,str2); str=(char*)realloc(str,len+4); str=(char*)realloc(str,len-4);
C語言動態釋放記憶體
C語言使用free函式來釋放用malloc,realloc函式分配的記憶體,不能使用free函式釋放C++通過new關鍵字分配的記憶體。
free函式原型如下:
void free(void* p);
示例如下:
const char *str2="hello world"; int len=strlen(str2); char *str=(char*)malloc(strlen(str2)); strcpy(str,str2); free(str);
C++語言記憶體管理
C++提供了對動態記憶體管理的內建支援,可以通過new和delete關鍵字來管理動態記憶體。
在C++中,強烈建議使用new和delete關鍵字來管理動態記憶體,因為new關鍵字會呼叫C++類的建構函式,delete關鍵字同樣會呼叫C++類的解構函式。而C語言的記憶體分配函式則無法實現類似的功能。
C++動態記憶體分配
std::string *str3=new std::string("hello world"); printf(str3->c_str());
C++釋放動態記憶體
std::string *str3=new std::string("hello world"); printf(str3->c_str()); delete str3; int *array=new int32_t[10]; for(int i=0;i<10;i++) { array[i]=i; } delete[] array;
Bionic I/O
需要引入stdio.h標頭檔案
Bionic提供的I/O函式
fopen |
開啟檔案流 |
fread |
從檔案流裡面讀取資料 |
fwrite |
往檔案流裡面寫入資料 |
fprintf |
把格式化的內容寫入檔案流 |
fscanf |
從檔案流裡面讀取格式化的內容 |
fgets |
從檔案流裡面讀取一行文字 |
fputs |
把以換行符結尾的文字寫入檔案流 |
fgetc |
從檔案流中讀取一個字元 |
fputc |
把一個字元寫入到檔案流 |
fseek |
移動檔案指標 |
ftell |
返回當前檔案指標的位置 |
feof |
判斷檔案指標是否已經到達檔案結尾 |
ferror |
判斷檔案流是否有錯誤 |
fflush |
把檔案流中的資料重新整理到檔案中 |
fclose |
關閉檔案流 |
一個讀取檔案的示例:
void readFile(const char * filePath){ if(filePath==NULL) return; FILE *file=fopen(filePath,"r"); fseek(file,SEEK_END); long fileSize=ftell(file); fseek(file,SEEK_SET); char *data=new char[fileSize]; fread(data, sizeof(char),fileSize/sizeof(char),file); fclose(file); }
一個寫入檔案的示例:
void writeFile(const char * filePath){ if(filePath==NULL) return; FILE *file=fopen(filePath,"w"); const char *data="hello world"; int len=strlen(data); fwrite(data, sizeof(char),len,file); fflush(file); fclose(file); }
Bionic與程序互動
Bionic允許原生程式碼啟動並與其它進行互動。原生程式碼可以執行shell命令,也可以在後臺啟動一個程序並與之通訊。
需要引入stdlib.h標頭檔案
Bionic執行shell命令
用system函式向shell傳遞命令
int result=system("mkdir /data/data/com.kgdwbb.jnidemo/files/file1"); if(result==-1 || result==127){ //shell 命令執行失敗 }
Bionic與子程序通訊
system函式不提供向程序傳送和接收命令的通道,我們需要使用popen函式,popen函式的原型如下:
FILE *popen(const char * cmd, const char * type);
第一個引數是要執行的命令,比如向shell傳遞”ls”命令
第二個引數是開啟通道的方式,比如“r”讀取,“w”寫入
示例如下:
FILE *file=popen("ls","r"); if(file==NULL) return; char *line=new char[1024]; while (fgets(line,1024,file)!=NULL){ //do something } fclose(file);
Bionic訪問系統配置
通過Bionic提供的API我們可以很方便的訪問Android系統屬性。
需要引入的標頭檔案是:#include<sys/system_properties.h>
訪問系統屬性的函式表
int __system_property_get(const char *name, char *value); |
獲取系統屬性 |
int __system_property_set(const char *key, const char *value); |
改變系統屬性 |
int __system_property_read(const prop_info *pi, char *name, char *value); |
讀取系統屬性 |
const prop_info *__system_property_find(const char *name); |
查詢系統屬性 |
示例如下:
const char *propName="ro.product.model"; char *value=new char; __system_property_get(propName,value); __system_property_set(propName,"newModel"); const prop_info *info= __system_property_find(propName); char *name=new char; char *value2=new char; __system_property_read(info,name,value2);
Bionic API訪問使用者和組陣列
需要引入的標頭檔案是:#include<unistd.h>
獲取應用程式的使用者ID和組ID
getuid函式用來獲取使用者ID
getgid函式用來獲取使用者的組ID
示例如下:
uid_t uid=getuid(); gid_t gid=getgid();
獲取安裝應用程式的使用者名稱
getlogin函式用來獲取安裝應用程式的使用者名稱
示例如下:
char *userName=getlogin();
結束語
本篇重點介紹了Bionic庫相關的基礎知識,相信大家學完這一篇,對Bionic庫應該有比較深刻的認識。當然還有一些Bionic庫的特性沒有介紹,後面幾篇文章會重點介紹。