1. 程式人生 > >Android NDK Bionic API篇(三)

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