What is in android.util.Log#println_native()? - java

Here is the android.util.Log source code.
At the very bottom (line 340), what is in the method:
public static native int println_native(int bufID,
int priority, String tag, String msg);
i guess println_native() is more or less like its println(), just with an int bufID different.
But even i got the codes of println_native(), i still lack com.android.internal.os.RuntimeInit (line 19, the import) to simulate android.util.Log in old Android version.

Just did some digging in the android source code. This function maps to
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
const char* tag = NULL;
const char* msg = NULL;
if (msgObj == NULL) {
jniThrowNullPointerException(env, "println needs a message");
return -1;
}
if (bufID < 0 || bufID >= LOG_ID_MAX) {
jniThrowNullPointerException(env, "bad bufID");
return -1;
}
if (tagObj != NULL)
tag = env->GetStringUTFChars(tagObj, NULL);
msg = env->GetStringUTFChars(msgObj, NULL);
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
if (tag != NULL)
env->ReleaseStringUTFChars(tagObj, tag);
env->ReleaseStringUTFChars(msgObj, msg);
return res;
}
Basically this then passes the arguments to the driver in the system which goes and writes to the Log buffer. Log buffer is pointed by /dev/log in the Linux kernel.

Once you have downloaded the sdk, you can use find to dig files.
Java code is linked to cpp code through jni.
In your case, you can use this command to find the related files:
find framework -type f -name "*.cpp" -exec grep "println_native" {} \; -ls
then you'll see that your java function is linked to this file : framework/base/core/jni/android_util_Log.cpp

Related

How to Set C++ variables with Java Methods?

Making a C++ program and want to receive values from a Java Api using Java method calls.
I have tried using Java Virtual Machines in C++ but it did not work so far. (New to C++ and Java)
How can I set C++ variables with the outputs from Java Methods?
--
Pseudo code of Desired Outcome:
//This example getnumber() Java Method returns back the number you give it
//C++ variables get the results from the Java getnumber() function
double Number1 = getnumber(7.00);
double Number2 = getnumber(9.00);
Code so far:
#include "C:\\Program Files\\Java\\jdk-19\\include\\win32\\jni_md.h"
#include "C:\\Program Files\\Java\\jdk-19\\include\\jni.h"
JavaVM* vm;
jsize vmCount;
if (JNI_GetCreatedJavaVMs(&vm, 1, &vmCount) != JNI_OK || vmCount == 0) {
fprintf(stderr, "Could not get active VM\n");
return NULL;
}
JNIEnv* env;
jint result = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (result == JNI_EDETACHED) {
result = vm->AttachCurrentThread((void**)&env, NULL);
}
if (result != JNI_OK) {
fprintf(stderr, "Failed to get JNIEnv\n");
return NULL;
}
jclass cls = env->FindClass("JMyService");
jmethodID ctor = env->GetMethodID(cls, "<init>", "()V");
jobject service = env->NewObject(cls, ctor);
jmethodID loadMethod = env->GetMethodID(cls, "loadContactInformation", "(I)Ljava/lang/String;");
jobject serviceResult = env->CallObjectMethod(service, loadMethod, userId);
return serviceResult;

Why Does Groovy eachDir() Give Me The Same Sort Every Time?

I am creating a file containing a list of sub-directories
task createNotes {
doLast {
def myFile = new File("my-notes.txt")
def file = new File("src/test/")
println myFile.exists()
myFile.delete()
println myFile.exists()
println myFile.absolutePath
println file.absolutePath
myFile.withWriter {
out ->
file.eachDir { dir ->
out.println dir.getName()
}
}
}
}
Apparently the sort order can't be guaranteed, but every time I run it I get the same sort order:
soft
java
calc
conc
caab
pres
If I change the "soft" dir to "sofp" the output is:
java
sofp
calc
conc
caab
pres
When I change the name back, it goes to the original order.
It doesn't appear to be sorted in any particular order - which matches the docs saying the order can't be guaranteed, but if so, why is it always giving me the same sort every time?
Let's break it down and have a look at eachDir Groovy extension method implementation first:
public static void eachDir(File self, #ClosureParams(value = SimpleType.class, options = "java.io.File") Closure closure) throws FileNotFoundException, IllegalArgumentException {
eachFile(self, FileType.DIRECTORIES, closure);
}
What does eachFile do?
public static void eachFile(final File self, final FileType fileType, #ClosureParams(value = SimpleType.class, options = "java.io.File") final Closure closure)
throws FileNotFoundException, IllegalArgumentException {
checkDir(self);
final File[] files = self.listFiles();
// null check because of http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4803836
if (files == null) return;
for (File file : files) {
if (fileType == FileType.ANY ||
(fileType != FileType.FILES && file.isDirectory()) ||
(fileType != FileType.DIRECTORIES && file.isFile())) {
closure.call(file);
}
}
}
OK, so Groovy just calls Java's File#listFiles method under the covers and then iterates the result without interfering with the existing order.
Moving to the OpenJDK implementation we can see that Files#listFiles uses FileSystem#list via the normalizedList method.
FileSystem#list is abstract. Continuing to the two most popular implementations it turns out that both UnixFileSystem#list and Win32FileSystem#list have a native implementation:
#Override
public native String[] list(File f);
Windows
Digging into the Windows implementation:
JNIEXPORT jobjectArray JNICALL
Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)
{
WCHAR *search_path;
HANDLE handle;
WIN32_FIND_DATAW find_data;
int len, maxlen;
jobjectArray rv, old;
DWORD fattr;
jstring name;
jclass str_class;
WCHAR *pathbuf;
DWORD err;
str_class = JNU_ClassString(env);
CHECK_NULL_RETURN(str_class, NULL);
pathbuf = fileToNTPath(env, file, ids.path);
if (pathbuf == NULL)
return NULL;
search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
if (search_path == 0) {
free (pathbuf);
errno = ENOMEM;
JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
return NULL;
}
wcscpy(search_path, pathbuf);
free(pathbuf);
fattr = GetFileAttributesW(search_path);
if (fattr == INVALID_FILE_ATTRIBUTES) {
free(search_path);
return NULL;
} else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
free(search_path);
return NULL;
}
/* Remove trailing space chars from directory name */
len = (int)wcslen(search_path);
while (search_path[len-1] == L' ') {
len--;
}
search_path[len] = 0;
/* Append "*", or possibly "\\*", to path */
if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||
(search_path[1] == L':'
&& (search_path[2] == L'\0'
|| (search_path[2] == L'\\' && search_path[3] == L'\0')))) {
/* No '\\' needed for cases like "\" or "Z:" or "Z:\" */
wcscat(search_path, L"*");
} else {
wcscat(search_path, L"\\*");
}
/* Open handle to the first file */
handle = FindFirstFileW(search_path, &find_data);
free(search_path);
if (handle == INVALID_HANDLE_VALUE) {
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
// error
return NULL;
} else {
// No files found - return an empty array
rv = (*env)->NewObjectArray(env, 0, str_class, NULL);
return rv;
}
}
/* Allocate an initial String array */
len = 0;
maxlen = 16;
rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
if (rv == NULL) { // Couldn't allocate an array
FindClose(handle);
return NULL;
}
/* Scan the directory */
do {
if (!wcscmp(find_data.cFileName, L".")
|| !wcscmp(find_data.cFileName, L".."))
continue;
name = (*env)->NewString(env, find_data.cFileName,
(jsize)wcslen(find_data.cFileName));
if (name == NULL) {
FindClose(handle);
return NULL; // error
}
if (len == maxlen) {
old = rv;
rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0) {
FindClose(handle);
return NULL; // error
}
(*env)->DeleteLocalRef(env, old);
}
(*env)->SetObjectArrayElement(env, rv, len++, name);
(*env)->DeleteLocalRef(env, name);
} while (FindNextFileW(handle, &find_data));
err = GetLastError();
FindClose(handle);
if (err != ERROR_NO_MORE_FILES) {
return NULL; // error
}
if (len < maxlen) {
/* Copy the final results into an appropriately-sized array */
old = rv;
rv = (*env)->NewObjectArray(env, len, str_class, NULL);
if (rv == NULL)
return NULL; /* error */
if (JNU_CopyObjectArray(env, rv, old, len) < 0)
return NULL; /* error */
}
return rv;
}
We can see a combination of FindFirstFileW, FindNextFileW and FindClose WinAPI functions used to iterate over the files. Excerpt about ordering from the documentation of FindNextFileW:
The order in which the search returns the files, such as alphabetical order, is not guaranteed, and is dependent on the file system.
(...)
The order in which this function returns the file names is dependent on the file system type. With the NTFS file system and CDFS file systems, the names are usually returned in alphabetical order. With FAT file systems, the names are usually returned in the order the files were written to the disk, which may or may not be in alphabetical order. However, as stated previously, these behaviors are not guaranteed.
So the implementation lists the files in a way that tries to be most optimal given the OS and file-system type constraints. No guarantees about a particular order.
*nix
What about *nix systems? Here's the code:
JNIEXPORT jobjectArray JNICALL
Java_java_io_UnixFileSystem_list(JNIEnv *env, jobject this,
jobject file)
{
DIR *dir = NULL;
struct dirent *ptr;
int len, maxlen;
jobjectArray rv, old;
jclass str_class;
str_class = JNU_ClassString(env);
CHECK_NULL_RETURN(str_class, NULL);
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
dir = opendir(path);
} END_PLATFORM_STRING(env, path);
if (dir == NULL) return NULL;
/* Allocate an initial String array */
len = 0;
maxlen = 16;
rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
if (rv == NULL) goto error;
/* Scan the directory */
while ((ptr = readdir(dir)) != NULL) {
jstring name;
if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
continue;
if (len == maxlen) {
old = rv;
rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
if (rv == NULL) goto error;
if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
(*env)->DeleteLocalRef(env, old);
}
#ifdef MACOSX
name = newStringPlatform(env, ptr->d_name);
#else
name = JNU_NewStringPlatform(env, ptr->d_name);
#endif
if (name == NULL) goto error;
(*env)->SetObjectArrayElement(env, rv, len++, name);
(*env)->DeleteLocalRef(env, name);
}
closedir(dir);
/* Copy the final results into an appropriately-sized array */
if (len < maxlen) {
old = rv;
rv = (*env)->NewObjectArray(env, len, str_class, NULL);
if (rv == NULL) {
return NULL;
}
if (JNU_CopyObjectArray(env, rv, old, len) < 0) {
return NULL;
}
}
return rv;
error:
closedir(dir);
return NULL;
}
This time iteration is supported by the opendir/readdir/closedir trio. The POSIX documentation of readdir only mentions this about ordering:
The type DIR, which is defined in the header <dirent.h>, represents a directory stream, which is an ordered sequence of all the directory entries in a particular directory.
Linux documentation has a bit more to say:
The order in which filenames are read by successive calls to readdir() depends on the filesystem implementation; it is unlikely that the names will be sorted in any fashion.
Close enough to Windows there is no order-guarantees apart from that there is some order.
Conclusion
'Is not guaranteed' means that a particular feature is an implementation detail and that you shouldn't rely on it. Contrary to 'guaranteed' features, which due to backward compatibility promise to stay invariant for some (usually longer) period of time. Changes to those features are called breaking changes and are usually well documented in release notes and migration guides (see Vue 3 migration guide for example). They also get announced long before they become finalized and released - see deprecation (often leaving some time to the developers to adjust their code to the new even after they go live).
The behaviour of 'unguaranteed' features on the other hand may differ between given product/library versions, environments (e.g. JVM implementations, operating systems, product versions) or even particular invocations. They sometimes show some predictable characteristics, but they should not be relied upon. You need to make sure to take care of the guarantees you expect for your piece of code to to have and implement them on your own.
Wrapping-up your issue: if you expect any specific order of files just sort them first - even if it means that the order will stay the same.

Calling Java functions from C language

I am tying to call java functions from c code.
I used the JNI as discussed in the example at http://www.ishaanguliani.com/content/calling-java-functions-c-linux-ubuntu-jni
I used the same code and followed the same steps but I am getting unable to find the class print.
I debugged but I didnt find what I did wrong.
Sharing my code here
unions#universe:~/uni_tmp/jni/vvn$ cat MyC.c
#include <stdio.h>
#include <jni.h>
#include "MyJava.h"
#include <string.h>
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
options.optionString = "-Djava.class.path=./"; //Path to the java source code
vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;
}
int main(void)
{
JNIEnv *env;
JavaVM *jvm;
jmethodID mainMethod = NULL;
jmethodID smfnMethod = NULL;
jclass clsJava=NULL;
jstring StringArg=NULL;
env = create_vm(&jvm);
if (env == NULL)
{
printf("\n Unable to create environment");
return 1;
}
clsJava = (*env)->FindClass(env,"MyJava");
if (clsJava != NULL)
{
printf("\n Able to find the requested class\n");
} else {
printf("\n Unable to find the requested class\n");
return 0;
}
mainMethod = (*env)->GetStaticMethodID(env, clsJava, "main", " ([Ljava/lang/String;)V");
smfnMethod = (*env)->GetStaticMethodID(env, clsJava,"sampleStaticFunc", "(Ljava/lang/String;)V");
if (mainMethod != NULL)
{
printf("\n Calling the Java Main method");
(*env)->CallStaticVoidMethod(env, clsJava, mainMethod, NULL);
}
StringArg = (*env)->NewStringUTF(env, "Argument from C");
if (smfnMethod != NULL)
{
printf("\n Calling the Static Function method");
(*env)->CallStaticVoidMethod(env, clsJava, smfnMethod, StringArg);
}
printf("\n End C main \n");
return 0;
}
Java code
cat unions#universe:~/uni_tmp/jni/vvn$ cat MyJava.java
public class MyJava
{
public MyJava()
{
System.out.println("\n Inside the constrcutor of Java Function \n ");
}
private void sampleFunc(String str)
{
System.out.println("\n Inside sampleFunc value of string = " + str);
}
public static void sampleStaticFunc(String str)
{
System.out.println("\n Inside static sampleFunc value of string = " + str);
}
public static void main(String[] args)
{
MyJava obj = new MyJava();
obj.sampleFunc("Ishaan is my name");
System.out.println("\n Calling Java from C function \n");
}
}
After that Ran these commands
unions#universe:~/uni_tmp/jni/vvn$ javac MyJava.java
unions#universe:~/uni_tmp/jni/vvn$ javah -jni MyJava
When I compiled and Ran I got this output
export LD_LIBRARY_PATH=/usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server
unions#universe:~/uni_tmp/jni/vvn$ gcc -I /usr/lib/jvm/java-6-openjdk-amd64/include -I /usr/lib/jvm/java-6-openjdk-amd64/include/linux -L /usr/bin/java -L /usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server MyC.c -ljvm ; ./a.out
Unable to find the requested class
Where I did wrong?
I changed the options.optionString to like this too
options.optionString = "-Djava.class.path=/home/vpraveen/uni_tmp/jni/vvn";
Even though There is no change in the output.
Any suggestions?
I solved this by making my class into my own package.
When we did not define any package it is taking as default package.
So I created my own package something like this
package com.aqu.vvn
I know its a work around but doing this worked for me.
I will let u know the exact way when I figured out.

cocos2dx: Multithreading with pthread and JNI calls crashs with “native thread exited without detaching”

in my cross-platform cocos2dx game I want to async load some images from web and save them to the local storage. For the Android part I use JNI calls to download and save the image to storage with native java code. It works perfect. But when I try to do this in a seperated pthread to prevent my game from freezing I get the error: "native thread exited without detaching" after "ThreadFunction(void *arg)" is finished.
here is my c++ code:
//c++ code
void MyClass::loadImages(){
pthread_t thread;
SimpleStructure* args = new SimpleStructure();
args->s_url = url;
args->s_savename = savename;
pthread_create(&thread, NULL, &ThreadFunction, args);
}
void* ThreadFunction(void * arg) {
SimpleStructure * args = (SimpleStructure * ) arg;
std::string localImagePath;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
localImagePath = getImageFilePathJNI(args->s_url.c_str(),
args->s_savename.c_str());
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
localImagePath = URLSpriteHelper::getUrlSprite(args->s_url,
args->s_savename);
#endif
pthread_mutex_lock(&mutex);
loadedImages.push_back(localImagePath);
pthread_mutex_unlock(&mutex);
return NULL;
}
here is my JNI code:
extern "C"
{
std::string getImageFilePathJNI(const char* urlStr, const char* saveName)
{
std::string ret;
JniMethodInfo t;
if (JniHelper::getStaticMethodInfo(t,
"org/cocos2dx/cpp/AppActivity",
"saveImageFromURLtoInternalStorage",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) {
jstring StringArg1 = t.env->NewStringUTF(urlStr);
jstring StringArg2 = t.env->NewStringUTF(saveName);
jstring retFromJava = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID, StringArg1, StringArg2);
const char* str = t.env->GetStringUTFChars(retFromJava, 0);
ret = str;
t.env->ReleaseStringUTFChars(retFromJava, str);
t.env->DeleteLocalRef(StringArg1);
t.env->DeleteLocalRef(StringArg2);
t.env->DeleteLocalRef(t.classID);
}
return ret;
}
}
Any ideas what I'm doing wrong?
Thank you very much!
Question answered in the cocos2dx forum.
http://discuss.cocos2d-x.org/t/multithreading-with-pthread-and-jni-calls-crashs-with-native-thread-exited-without-detaching/15625

Undefined Reference Trying to invoke Java from C++

I am trying to create a Java virtual machine from C++ and invoke the main method passing a String argument to the main method of the Java program. I am following this example found on Sun's website: http://java.sun.com/docs/books/jni/html/invoke.html#11202
Here is the simple Java Program:
public class TestJNIInvoke
{
public static void main(String[] args)
{
System.out.println(args[0]);
}
}
Here is the C++ program I am using to (try to) invoke the JVM:
#include <jni.h>
#include <cstdlib>
using namespace std;
int main()
{
JNIEnv *env;
JavaVM *jvm;
jint res;
jclass cls;
jmethodID mid;
jstring jstr;
jclass stringClass;
jobjectArray args;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1]; //LINE 18 ERROR
options[0].optionString =
(char*)&"-Djava.class.path=C:\\Program Files\\Java\\jdk1.7.0\\bin";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); //LINE 26 ERROR
if (res < 0)
{
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
cls = env->FindClass("TestJNIInvoke");
if (cls == NULL)
{
goto destroy;
}
mid = env->GetStaticMethodID(cls, "main",
"([Ljava/lang/String;)V");
if (mid == NULL)
{
goto destroy;
}
jstr = env->NewStringUTF(" from CPP!");
if (jstr == NULL)
{
goto destroy;
}
stringClass = env->FindClass("java/lang/String");
args = env->NewObjectArray(1, stringClass, jstr);
if (args == NULL)
{
goto destroy;
}
env->CallStaticVoidMethod(cls, mid, args);
destroy:
if (env->ExceptionOccurred())
{
env->ExceptionDescribe();
}
jvm->DestroyJavaVM();
}
Anyway If I just compile the file with:
gcc -I"c:\Program Files\Java\jdk1.7.0\include"
-I"c:\Program Files\Java\jdk1.7.0\include\win32" -c TestJNIInvoke.cpp
It compiles fine, but when I try to compile and link:
gcc -I"c:\Program Files\Java\jdk1.7.0\include"
-I"c:\Program Files\Java\jdk1.7.0\include\win32" -g TestJNIInvoke.cpp
I get two weird errors that I don't understand:
TestJNIInvoke.cpp:18: undefined reference to `operator new[](unsigned int)'
TestJNIInvoke.cpp:26: undefined reference to `_imp__JNI_CreateJavaVM#12'
collect2: ld returned 1 exit status
I marked the lines in the above code where the error is occuring, has anyone encountered this problem before?
Any ideas/links would be great
Thanks
First, don't use gcc. By default, it assumes the code it's handling is written in C. When you want it to compile or link C++ code, you should run g++. This will bring in the C++ standard headers and libraries.
Second, you need to include the java libraries. Section 7.2.1 in the page you linked discusses this.
Your command line should look more like this:
g++ -I"C:\Program Files\Java\jdk1.7.0\include" -L"C:\Program Files\Java\jdk1.7.0\lib" -lthread -ljava TestJNIInvoke.cpp
Note that you might have to add additional include (-I) or linker (-L) directories.

Categories