I have a function in c++ and I want to call it it java for android.
I write it and build its library but the problem is I can not find file in emulator.
I use adb push text.txt sdcard to copy text.txt to sdcard of emulator.
but I could not find the file with the C function.
I call Simple("hello");
This is my C file :
jint Java_X_XX_XXX_wipeActivity_Simple(JNIEnv* env, jobject javaThis,jstring jstr)
{
jboolean iscopy;
const char *address = (*env)->GetStringUTFChars(env, jstr, &iscopy);
return replaceZero("/sdcard/text.txt");
//remove(address);
}
jint replaceZero(const char *address)
{
FILE *fp;
fp = fopen(address,"r+");
if(fp == 0)
{
printf("can not find!!");
return -1;
}
else
{
//do sth with file
return 0;
}
}
and I will see -1 in main program.
I found the answer - I needed to add this to manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
I cannot open it without permission.
Related
I want to create a file in my device by using JNI program.and i created a file in the location of data/local/hello.txt by using the code
JNIEXPORT jint JNICALL
Java_com_maacrofuzzyn_acsianiac_samplelibrary_MainActivity_Register(
JNIEnv *env,
jobject ob) {
int i = 0;
FILE* file = fopen("/data/local/hello.txt","w+");
if (file != NULL)
{
fputs("HELLO WORLD!\n", file);
fflush(file);
fclose(file);
}
but, i cant create a file in the location tmp/hello.txt by using the same code. i think this is something permission problem. how can i solve this problem and create a file in that location... please help me.
I am building a forensic tool, that shall read and write from file slacks. At the moment I use JNI to call the C functions read() and write() to write a buffer to the FAT SD card (also EXT4 internal memory would be nice). I use those because you can pass the length to read/write thus ignoring EOF.
I already tried writing by using a standard write and then truncate it in order to write in the file slack, which works on ubuntu 14.04 but not on Android (API 21).
Reading more from a file than the actuall file size does not reflect the flie slack on the SD-card.
There are tools e.g. "bmap" or "slacker.exe" (for NTFS) that manage to access file slacks. I am in need of a way to ignore EOF or handle it myself. I would prefere not to change existing file system drivers.
I appreciate any suggestions.
here is some sample code (that does not work yet):
jstring
Java_com_example_hellojni_HelloJni_write(JNIEnv *env, jobject thiz, jstring path)
{
char *cpath = (*env)->GetStringUTFChars(env, path, NULL);
int raw_file_descriptor = open(cpath,O_WRONLY,0);
lseek(raw_file_descriptor,0,SEEK_END);
char block_buffer [4096] = "hidden";
int buffer_length = 6;
int wret = write(raw_file_descriptor,block_buffer,buffer_length); // increases file size and moves EOF - I don't want that
LOGD(" char written: %d", wret);
free(cpath);
return (*env)->NewStringUTF(env, "write ok ");
}
jbyteArray
Java_com_example_hellojni_HelloJni_read2(JNIEnv *env, jobject thiz, jstring path) {
char *cpath = (*env)->GetStringUTFChars(env, path, NULL);
LOGD("open %s with ", cpath);
int raw_file_descriptor = open(cpath,O_RDONLY,0);
char buffer [4096];
int readretval = read(raw_file_descriptor, buffer, 50); // stops at EOF - I want it to continue reading all 50 bytes from the SD-card - This gives me the file content until EOF and then I get some random characters from the uninitialized buffer.
LOGD("read (%d) buffer with length %d: %s", readretval, sizeof(buffer), buffer);
int i; // Debug code
for (i=0; i < 49; ++i) {
LOGD("%c",buffer[i]);
}
close(raw_file_descriptor);
free(cpath);
return NULL;
}
Apparently this way is impossible. But with root it is possible to write file slack via mounting a loop back device. Still, ignoring EOF is not possible without changing the driver or implementing your own kernel module.
This simple program to write into a file is running fine in my emulator as I am getting a text file generated inside the sdcard(text file has HELLO WORLD in it) along with the given message on emulator screen.
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
FILE* file = fopen("/sdcard/hello.txt","w+");
if (file != NULL)
{
fputs("HELLO WORLD!\n", file);
fflush(file);
fclose(file);
}
return (*env)->NewStringUTF(env, "Hello from JNI (with file io)!");
}
But when I try to read the file using this program I am facing problems. It outputs nothing on the emulator screen or on logcat. As seen from the above program there definitely is no problem with the location of sdcard or with using FILE operations. How to fix it?
JNIEXPORT jstring JNICALL Java_com_example_myproject_MainActivity_doSomething( JNIEnv* env, jobject thiz)
{
// Counts the characters inside file
char ch;
int cnt= 0;
FILE* fptr = fopen("/sdcard/hello.txt","r");
while((ch=fgetc(fptr))!=EOF)
cnt++;
fclose(fptr);
LOGE("cnt: %d",cnt);
return (*env)->NewStringUTF(env, "Hello from JNI (with file io)!");
}
Thanks
EDIT:
This above code to read file works well in linux gcc but has errors working in Android. Changing it as mentioned by Andrew solves it.
fgetc() returns int, not char, so this loop never terminates:
while((ch=fgetc(fptr))!=EOF)
cnt++;
because ch can never equal EOF.
I am trying to write a native library for my application so that i can do all file operation in the native code. I read that getExternalStorageDirectory() give the path of the external storage of directory.
My question is how can i access the same without hard-coding the location to some string? Is there any function in android ndk that can give the same function as getExternalStorageDirectory() of java in C++ code?
JNI is your friend, and this isn't too complicated, as getExternalStorageDirectory is a static method. This function gets the value, and changes the working directory to it, for good measure.
#include <jni.h>
#include <unistd.h> // chdir()
#include <sys/param.h> // MAXPATHLEN
// To call Java methods when running native code inside an Android activity,
// a reference is needed to the JavaVM.
static JavaVM *gJavaVM;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
gJavaVM = vm;
return JNI_VERSION_1_6;
}
int cdToExtStorage(void) {
// Make JNI calls to get the external storage directory, and cd to it.
// To begin, get a reference to the env and attach to it.
JNIEnv *env;
int isAttached = 0;
int ret = 0;
jthrowable exception;
if (((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6)) < 0) {
// Couldn't get JNI environment, so this thread is native.
if (((*gJavaVM)->AttachCurrentThread(gJavaVM, &env, NULL)) < 0) {
fprintf(stderr, "Error: Couldn't attach to Java VM.\n");
return (-1);
}
isAttached = 1;
}
// Get File object for the external storage directory.
jclass classEnvironment = (*env)->FindClass(env, "android/os/Environment");
if (!classEnvironment) goto bailAndroid;
jmethodID methodIDgetExternalStorageDirectory = (*env)->GetStaticMethodID(env, classEnvironment, "getExternalStorageDirectory", "()Ljava/io/File;"); // public static File getExternalStorageDirectory ()
if (!methodIDgetExternalStorageDirectory) goto bailAndroid;
jobject objectFile = (*env)->CallStaticObjectMethod(env, classEnvironment, methodIDgetExternalStorageDirectory);
exception = (*env)->ExceptionOccurred(env);
if (exception) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
// Call method on File object to retrieve String object.
jclass classFile = (*env)->GetObjectClass(env, objectFile);
if (!classFile) goto bailAndroid;
jmethodID methodIDgetAbsolutePath = (*env)->GetMethodID(env, classFile, "getAbsolutePath", "()Ljava/lang/String;");
if (!methodIDgetAbsolutePath) goto bailAndroid;
jstring stringPath = (*env)->CallObjectMethod(env, objectFile, methodIDgetAbsolutePath);
exception = (*env)->ExceptionOccurred(env);
if (exception) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
// Extract a C string from the String object, and chdir() to it.
const char *wpath3 = (*env)->GetStringUTFChars(env, stringPath, NULL);
if (chdir(wpath3) != 0) {
fprintf(stderr, "Error: Unable to change working directory to %s.\n", wpath3);
perror(NULL);
} else if (path) {
if (chdir(path) != 0) {
fprintf(stderr, "Error: Unable to change working directory to %s.\n", path);
perror(NULL);
}
}
(*env)->ReleaseStringUTFChars(env, stringPath, wpath3);
goto retAndroid;
bailAndroid:
fprintf(stderr, "Error: JNI call failure.\n");
ret = -1;
retAndroid:
if (isAttached) (*gJavaVM)->DetachCurrentThread(gJavaVM); // Clean up.
return (ret);
}
I'm not sure the existence of that function, but I think you can achieve it by reading /proc/mounts then get info of external storage,e.g /storage/sdcardx on JellyBean, mnt/sdcardx on older versions. You can check in *.rc file, maybe it can be defined a symlink for backward compatiblility. There exist another environment variable which is used to define external storage, EXTERNAL_STORAGE so you can try getenv(EXTERNAL_STORAGE) to get mount point. Hope it can help some ways.
I am developing a Native application name test.c and I want to return the arrayofByte from the native C file ,I able to compile and the .so file is generate when i run my Application
05-08 13:04:08.477: D/dalvikvm(945): No JNI_OnLoad found in /data/data/com.ssg.nativelibtest/lib/libnativelibtest.so 0x45f3da78, skipping init
getting this message with out any crash in my application so how to resolve the calling of Nativefile.
for the reference I am giveing my test.c file
this is file written in C I am calling the .so file Java appliaction
jbyteArray Java_com_ssg_nativelibtest_MainActivity_getEncryptionKey(JNIEnv * env, jobject obj)
{
unsigned char ukey[] = { 'H','A','R','D','C','O','D','E','D',' ','K','E','Y','1','2','3'};
int lengthOfArray = (*env)->GetArrayLength(env, ukey);
//jsize lengthOfArray =(*env)->GetArrayLength(env, ukey);
jbyteArray byteKey = (*env)->NewByteArray(env, lengthOfArray);
(*env)->SetByteArrayRegion(env, byteKey, 0, lengthOfArray, (jbyte *)ukey);
return byteKey;
}
See documentation:
The JNI_OnLoad function should look something like this if written in
C++:
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
// Get jclass with env->FindClass.
// Register methods with env->RegisterNatives.
return JNI_VERSION_1_6;
}