Uncompress the file in the existing cpp file and create a file with a different extension.
For that reason, I call and use the cpp source with JNI. On android 11 it works fine, but on android 12 the problem occurs.
The problem is that the return of malloc in the c++ file called by JNI is null. Is there a way to use malloc in android 12?
This is part of my code.
//JAVA
String myFile = //cache memory path;
String copyFile = //cache memory path;
int res = GetFileData(myFile, copyFile);
///C++
const char* szMyFile= env->GetStringUTFChars(myFile, nullptr); //jstring -> const char*
const char* szCopyFile = env->GetStringUTFChars(copyFile, nullptr); //jstring -> const char*
///malloc
ptr_entry_info = (st_entrymodel_info *)malloc(entry_cnt * sizeof(st_entrymodel_info)); //return NULL
Edit
In the part of allocating malloc, entry_cnt indicates the number of files. entry_cnt is 1.
entry_cnt = 1;
ptr_entry_info = (st_entrymodel_info *)malloc(entry_cnt * sizeof(st_entrymodel_info)); //Not NULL
The problem is that if I initialize entry_cnt back to 1, it doesn't give me an error. But entry_cnt is already 1.
Related
I am trying to read in a large file using asset manager in Android NDK.
The problem is that the code that I have written is not reading the entire content. Rather only a portion of it. When I try to achieve the same functionality using Java, it is giving me correct results.
This is the code that I have written:
std::string file = hats::files::SOURCE_DATASET_FILENAME;
AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
AAsset *asset = AAssetManager_open(mgr, file.c_str(), AASSET_MODE_BUFFER);
size_t assetLength = AAsset_getLength(asset);
char *buffer = (char *) malloc(assetLength + 1);
int nbytes{0};
while( (nbytes = AAsset_read(asset, buffer, assetLength)) > 0) {
LOGD("%s", buffer);
AAsset_seek(asset, nbytes, SEEK_CUR);
}
AAsset_close(asset);
return env->NewStringUTF(file.c_str());
I am not able to understand why only partial file is being read. I am not able to find any proper tutorial for Android NDK also.
Please help me out.
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.
I have an Android project in pure native code. Now, I need to use a third party jar file with it. How can I build my project with the jar file added?
Here, FindClass returns NULL because my jar file is not added in the JavaVM.
ANativeActivity *activity = __state->activity;
JavaVM *jvm = __state->activity->vm;
JNIEnv *env = NULL;
jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
jint res = jvm->AttachCurrentThread(&env, NULL);
jclass cls = env->FindClass("MyJavaClass"); //cls is NULL
jvm->DetachCurrentThread();
I tried creating an another jvm but it is not supported in Android. Though it's not a good idea even if it is supported.
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
std::string str = "-Djava.class.path=res/test.jar"; //Add the jar in jvm
options[0].optionString = (char*)str.c_str();
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
How can I add my jar correctly? I'm guessing in Android.mk file but I don't know what or how.
I have some code:
AAsset* pAsset = AAssetManager_open(pAssetManager, "asset_test.txt", AASSET_MODE_STREAMING);
DebugPrint(pAsset?"pAsset not NULL\n":"pAsset NULL");
if (pAsset)
{
char buf[1024];
AAsset_read(pAsset, buf, sizeof(buf));
DebugPrint(buf);
AAsset_close(pAsset);
}
This code always prints "pAsset NULL" in logcat.
I put the asset_test.txt file in my assets directory, and I looked in the .apk to make sure it exists by renaming the .apk to .zip and opening it with 7zip.
I have some more code:
AAssetDir* pAssetDir = AAssetManager_openDir(pAssetManager, sDirectory.c_str());
if (!pAssetDir)
{
DebugPrint("pAssetDir NULL\n");
return;
}
const char* pszDir;
while ((pszDir = AAssetDir_getNextFileName(pAssetDir)) != NULL)
{
DebugPrint(pszDir);
}
AAssetDir_close(pAssetDir);
This code prints nothing. In other words, no files are ever found in the assets directory, regardless of what paths I pass into it.
Note: DebugPrint is just a prettier looking wrapper around __android_log_print().
I passed the Activity into AAssetManager_fromJava(), while I should have passed the AssetManager in. If you pass the wrong class into AAssetManager_fromJava() it will fail without printing anything to logcat.
How to get the asset manager with JNI:
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
jobject activity = (jobject)SDL_AndroidGetActivity();
jclass activity_class = env->GetObjectClass(activity);
jmethodID activity_class_getAssets = env->GetMethodID(activity_class, "getAssets", "()Landroid/content/res/AssetManager;");
jobject asset_manager = env->CallObjectMethod(activity, activity_class_getAssets); // activity.getAssets();
global_asset_manager = env->NewGlobalRef(asset_manager);
pAssetManager = AAssetManager_fromJava(env, global_asset_manager);
Stash that asset manager pointer somewhere and use it for all your AAssetManager_*() functions from now on.
I am trying to load a TGA file in Android NDK.
I open the file using AssetManager, read in the entire contents of the TGA file into a memory buffer, and then I try to extract the pixel data from it.
I can read the TGA header part of the file without any problems, but when I try to advance the memory pointer past the TGA header, the app crashes. If I don't try to advance the memory pointer, it does not crash.
Is there some sort of limitation in Android NDK for pointer arithmetic?
Here is the code:
This function opens the asset file:
char* GEAndroid::OpenAssetFile( const char* pFileName )
{
char* pBuffer = NULL;
AAssetManager* assetManager = m_pState->activity->assetManager;
AAsset* assetFile = AAssetManager_open(assetManager, pFileName, AASSET_MODE_UNKNOWN);
if (!assetFile) {
// Log error as 'error in opening the input file from apk'
LOGD( "Error opening file %s", pFileName );
}
else
{
LOGD( "File opened successfully %s", pFileName );
const void* pData = AAsset_getBuffer(assetFile);
off_t fileLength = AAsset_getLength(assetFile);
LOGD("fileLength=%d", fileLength);
pBuffer = new char[fileLength];
memcpy( pBuffer, pData, fileLength * sizeof( char ) );
}
return pBuffer;
}
And down here in my texture class I try to load it:
char* pBuffer = g_pGEAndroid->OpenAssetFile( fileNameWithPath );
TGA_HEADER textureHeader;
char *pImageData = NULL;
unsigned int bytesPerPixel = 4;
textureHeader = *reinterpret_cast<TGA_HEADER*>(pBuffer);
// I double check that the textureHeader is valid and it is.
bytesPerPixel = textureHeader.bits/8; // Divide By 8 To Get The Bytes Per Pixel
m_imageSize = textureHeader.width*textureHeader.height*bytesPerPixel; // Calculate The Memory Required For The TGA Data
pImageData = new char[m_imageSize];
// the line below causes the crash
pImageData = reinterpret_cast<char*>(pBuffer + sizeof( TGA_HEADER)); // <-- causes a crash
If I replace the line above with the following line (even though it is incorrect), the app runs, although obviously the texture is messed up.
pImageData = reinterpret_cast<char*>(pBuffer); // <-- does not crash, but obviously texture is messed up.
Anyone have any ideas?
Thanks.
Why reinterpret_cast? You're adding an integer to a char*; that operation produces a char*. No typecast necessary.
One caveat for pointer juggling on Android (and on ARM devices in general): ARM cannot read/write unaligned data from memory. If you read/write an int-sized variable, it needs to be at an address that's a multiple of 4; for short, a multiple of 2. Bytes can be at any address. This does not, as far as I can see, apply to the presented snippet. But do keep in mind. It does throw off binary format parsing occasionally, especially when ported from Intel PCs.
Simply assigning an unaligned value to a pointer does not crash. Dereferencing it might.
Sigh, I just realized the mistake. I allocate memory for pImageData, then set the point to the buffer. This does not sit well when I try to create an OpenGL texture with the pixel data. Modifying it so I memcpy the pixel data from (pBuffer + sizeof( TGA_HEADER) ) to pImageData fixes the problem.