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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章