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庫的特性沒有介紹,後面幾篇文章會重點介紹。