From 90cb1c925a486cee825362c67f769e34255cf99b Mon Sep 17 00:00:00 2001 From: Mis012 Date: Wed, 6 Sep 2023 17:42:24 +0200 Subject: [PATCH] api-impl: use liblog for android.util.Log; use Log.v for debugging prints and Log.w for stub tracing --- meson.build | 1 + src/api-impl-jni/android_graphics_Bitmap.c | 2 +- src/api-impl-jni/android_util_Log.c | 51 +++++++++++++++++++ .../generated_headers/android_util_Log.h | 8 +-- src/api-impl-jni/util.c | 50 ++++++++++++++++++ src/api-impl-jni/util.h | 28 ++++++++++ .../android/app/SharedPreferencesImpl.java | 28 +++++----- src/api-impl/android/content/Context.java | 24 ++++----- src/api-impl/android/util/Log.java | 8 +-- src/api-impl/android/view/LayoutInflater.java | 20 ++++---- src/api-impl/android/view/View.java | 15 +++--- 11 files changed, 181 insertions(+), 54 deletions(-) create mode 100644 src/api-impl-jni/android_util_Log.c diff --git a/meson.build b/meson.build index 50d70214..d77ce9ae 100644 --- a/meson.build +++ b/meson.build @@ -68,6 +68,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ 'src/api-impl-jni/util.c', 'src/api-impl-jni/android_graphics_Canvas.c', 'src/api-impl-jni/android_graphics_Paint.c', + 'src/api-impl-jni/android_util_Log.c', 'src/api-impl-jni/database/android_database_SQLiteCommon.c', 'src/api-impl-jni/database/android_database_SQLiteConnection.c', 'src/api-impl-jni/drawables/ninepatch.c', diff --git a/src/api-impl-jni/android_graphics_Bitmap.c b/src/api-impl-jni/android_graphics_Bitmap.c index 6cb3f97d..d4cad64d 100644 --- a/src/api-impl-jni/android_graphics_Bitmap.c +++ b/src/api-impl-jni/android_graphics_Bitmap.c @@ -16,7 +16,7 @@ JNIEXPORT jlong JNICALL Java_android_graphics_Bitmap_native_1bitmap_1from_1path(JNIEnv *env, jobject this, jobject path) { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(_CSTRING(path), NULL); - printf(">>> made pixbuf from path: >%s<, >%p<\n", _CSTRING(path), pixbuf); + android_log_printf(ANDROID_LOG_VERBOSE, "["__FILE__"]", ">>> made pixbuf from path: >%s<, >%p<\n", _CSTRING(path), pixbuf); sk_imageinfo_t info = { .width = gdk_pixbuf_get_width(pixbuf), diff --git a/src/api-impl-jni/android_util_Log.c b/src/api-impl-jni/android_util_Log.c new file mode 100644 index 00000000..96dc4378 --- /dev/null +++ b/src/api-impl-jni/android_util_Log.c @@ -0,0 +1,51 @@ +#include + +#include "defines.h" +#include "util.h" + +/* copied from AOSP: +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +JNIEXPORT jint JNICALL Java_android_util_Log_println_1native(JNIEnv* env, jobject this, 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"); + fprintf(stderr, "Log.println_native: println needs a message\n"); + return -1; + } + + if (bufID < 0 || bufID >= LOG_ID_MAX) { +// jniThrowNullPointerException(env, "bad bufID"); + fprintf(stderr, "Log.println_native: bad bufID\n"); + return -1; + } + + if (tagObj != NULL) + tag = (*env)->GetStringUTFChars(env, tagObj, NULL); + msg = (*env)->GetStringUTFChars(env, msgObj, NULL); + + int res = __android_log_buf_write(bufID, priority, tag, msg); + + if (tag != NULL) + (*env)->ReleaseStringUTFChars(env, tagObj, tag); + (*env)->ReleaseStringUTFChars(env, msgObj, msg); + + return res; +} diff --git a/src/api-impl-jni/generated_headers/android_util_Log.h b/src/api-impl-jni/generated_headers/android_util_Log.h index 1ea3fcf7..ae98c844 100644 --- a/src/api-impl-jni/generated_headers/android_util_Log.h +++ b/src/api-impl-jni/generated_headers/android_util_Log.h @@ -29,11 +29,11 @@ extern "C" { #define android_util_Log_LOG_ID_SYSTEM 3L /* * Class: android_util_Log - * Method: isLoggable - * Signature: (Ljava/lang/String;I)Z + * Method: println_native + * Signature: (IILjava/lang/String;Ljava/lang/String;)I */ -JNIEXPORT jboolean JNICALL Java_android_util_Log_isLoggable - (JNIEnv *, jclass, jstring, jint); +JNIEXPORT jint JNICALL Java_android_util_Log_println_1native + (JNIEnv *, jclass, jint, jint, jstring, jstring); #ifdef __cplusplus } diff --git a/src/api-impl-jni/util.c b/src/api-impl-jni/util.c index 9d97a3e7..df408039 100644 --- a/src/api-impl-jni/util.c +++ b/src/api-impl-jni/util.c @@ -1,3 +1,6 @@ +#include +#include + #include "util.h" struct handle_cache handle_cache = {0}; @@ -140,3 +143,50 @@ void extract_from_apk(const char *path, const char *target) { JNIEnv *env = get_jni_env(); (*env)->CallStaticObjectMethod(env, handle_cache.asset_manager.class, handle_cache.asset_manager.extractFromAPK, _JSTRING(path), _JSTRING(target)); } + +/* logging with fallback to stderr */ + +typedef int __android_log_vprint_type(int prio, const char *tag, const char *fmt, va_list ap); + +static int fallback_verbose_log(int prio, const char *tag, const char *fmt, va_list ap) +{ + int ret; + + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&mutex); + static char buf[1024]; + ret = vsnprintf(buf, sizeof(buf), fmt, ap); + fprintf(stderr, "%lu: %s\n", pthread_self(), buf); + pthread_mutex_unlock(&mutex); + + return ret; +} + +static int android_log_vprintf(int prio, const char *tag, const char *fmt, va_list ap) +{ + + static __android_log_vprint_type *_android_log_vprintf = NULL; + if(!_android_log_vprintf) { + _android_log_vprintf = dlsym(RTLD_DEFAULT, "__android_log_vprint"); + + if(!_android_log_vprintf) { + _android_log_vprintf = &fallback_verbose_log; + } + } + + return _android_log_vprintf(prio, tag, fmt, ap); +} + +int android_log_printf(android_LogPriority prio, const char *tag, const char *fmt, ...) +{ + int ret; + + va_list ap; + va_start(ap, fmt); + + ret = android_log_vprintf(prio, tag, fmt, ap); + + va_end(ap); + + return ret; +} diff --git a/src/api-impl-jni/util.h b/src/api-impl-jni/util.h index 06041ee0..be45544d 100644 --- a/src/api-impl-jni/util.h +++ b/src/api-impl-jni/util.h @@ -107,4 +107,32 @@ void extract_from_apk(const char *path, const char *target); void prepare_main_looper(JNIEnv* env); +/* we don't (currently?) install the headers for liblog */ +typedef enum { + LOG_ID_MAIN = 0, + LOG_ID_RADIO = 1, + LOG_ID_EVENTS = 2, + LOG_ID_SYSTEM = 3, + + LOG_ID_MAX +} log_id_t; + +typedef enum android_LogPriority { + ANDROID_LOG_UNKNOWN = 0, + ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ + ANDROID_LOG_VERBOSE, + ANDROID_LOG_DEBUG, + ANDROID_LOG_INFO, + ANDROID_LOG_WARN, + ANDROID_LOG_ERROR, + ANDROID_LOG_FATAL, + ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */ +} android_LogPriority; + +/* TODO: do we really need the bufID, or can we use our function below which has a stderr fallback */ +int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); + +/* defined in util.c */ +int android_log_printf(android_LogPriority prio, const char *tag, const char *fmt, ...); + #endif diff --git a/src/api-impl/android/app/SharedPreferencesImpl.java b/src/api-impl/android/app/SharedPreferencesImpl.java index 485910a0..929c2b14 100644 --- a/src/api-impl/android/app/SharedPreferencesImpl.java +++ b/src/api-impl/android/app/SharedPreferencesImpl.java @@ -22,7 +22,7 @@ import android.system.ErrnoException; // import android.os.Looper; import android.system.Os; import android.system.StructStat; -import android.util.Log; +import android.util.Slog; // import com.google.android.collect.Maps; import com.android.internal.util.XmlUtils; import dalvik.system.BlockGuard; @@ -99,7 +99,7 @@ public final class SharedPreferencesImpl implements SharedPreferences { } // Debugging if (mFile.exists() && !mFile.canRead()) { - Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission"); + Slog.w(TAG, "Attempt to read preferences file " + mFile + " without permission"); } Map map = null; StructStat stat = null; @@ -112,11 +112,11 @@ public final class SharedPreferencesImpl implements SharedPreferences { new FileInputStream(mFile), 16 * 1024); map = XmlUtils.readMapXml(str); } catch (XmlPullParserException e) { - Log.w(TAG, "getSharedPreferences", e); + Slog.w(TAG, "getSharedPreferences", e); } catch (FileNotFoundException e) { - Log.w(TAG, "getSharedPreferences", e); + Slog.w(TAG, "getSharedPreferences", e); } catch (IOException e) { - Log.w(TAG, "getSharedPreferences", e); + Slog.w(TAG, "getSharedPreferences", e); } finally { IoUtils.closeQuietly(str); } @@ -155,7 +155,7 @@ public final class SharedPreferencesImpl implements SharedPreferences { if (mDiskWritesInFlight > 0) { // If we know we caused it, it's not unexpected. if (DEBUG) - Log.d(TAG, "disk write in flight, not unexpected."); + Slog.d(TAG, "disk write in flight, not unexpected."); return false; } } @@ -203,7 +203,7 @@ public final class SharedPreferencesImpl implements SharedPreferences { } public Map getAll() { - System.out.println("\n\n...> getAll()\n\n"); + Slog.v(TAG, "\n\n...> getAll()\n\n"); synchronized (this) { awaitLoadedLocked(); // noinspection unchecked @@ -250,7 +250,7 @@ public final class SharedPreferencesImpl implements SharedPreferences { } public boolean getBoolean(String key, boolean defValue) { synchronized (this) { - System.out.println("android.app.SharedPreferencesImpl.getBoolean("+key+", "+defValue+")"); + Slog.v(TAG, "android.app.SharedPreferencesImpl.getBoolean("+key+", "+defValue+")"); awaitLoadedLocked(); Boolean v = (Boolean)mMap.get(key); return v != null ? v : defValue; @@ -542,7 +542,7 @@ public final class SharedPreferencesImpl implements SharedPreferences { } catch (FileNotFoundException e) { File parent = file.getParentFile(); if (!parent.mkdir()) { - Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file); + Slog.e(TAG, "Couldn't create directory for SharedPreferences file " + file); return null; } /* FileUtils.setPermissions( @@ -552,7 +552,7 @@ public final class SharedPreferencesImpl implements SharedPreferences { try { str = new FileOutputStream(file); } catch (FileNotFoundException e2) { - Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2); + Slog.e(TAG, "Couldn't create SharedPreferences file " + file, e2); } } return str; @@ -572,7 +572,7 @@ public final class SharedPreferencesImpl implements SharedPreferences { } if (!mBackupFile.exists()) { if (!mFile.renameTo(mBackupFile)) { - Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile); + Slog.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile); mcr.setDiskWriteResult(false); return; } @@ -607,14 +607,14 @@ public final class SharedPreferencesImpl implements SharedPreferences { mcr.setDiskWriteResult(true); return; } catch (XmlPullParserException e) { - Log.w(TAG, "writeToFile: Got exception:", e); + Slog.w(TAG, "writeToFile: Got exception:", e); } catch (IOException e) { - Log.w(TAG, "writeToFile: Got exception:", e); + Slog.w(TAG, "writeToFile: Got exception:", e); } // Clean up an unsuccessfully written file if (mFile.exists()) { if (!mFile.delete()) { - Log.e(TAG, "Couldn't clean up partially-written file " + mFile); + Slog.e(TAG, "Couldn't clean up partially-written file " + mFile); } } mcr.setDiskWriteResult(false); diff --git a/src/api-impl/android/content/Context.java b/src/api-impl/android/content/Context.java index 1385ab8c..b012e0ce 100644 --- a/src/api-impl/android/content/Context.java +++ b/src/api-impl/android/content/Context.java @@ -27,7 +27,7 @@ import android.os.Vibrator; import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.util.DisplayMetrics; -import android.util.Log; +import android.util.Slog; import android.view.WindowManagerImpl; import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.InputMethodManager; @@ -106,7 +106,7 @@ public class Context extends Object { } public Context() { - System.out.println("new Context! this one is: " + this); + Slog.v(TAG, "new Context! this one is: " + this); } public int checkPermission(String permission, int pid, int uid) { @@ -174,7 +174,7 @@ public class Context extends Object { case "accessibility": return new AccessibilityManager(); default: - System.out.println("!!!!!!! getSystemService: case >" + name + "< is not implemented yet"); + Slog.e(TAG, "!!!!!!! getSystemService: case >" + name + "< is not implemented yet"); return null; } } @@ -247,7 +247,7 @@ public class Context extends Object { // spurious failure; probably racing with another process for this app return files_dir; } - Log.w(TAG, "Unable to create files directory " + files_dir.getPath()); + Slog.w(TAG, "Unable to create files directory " + files_dir.getPath()); return null; } } @@ -293,7 +293,7 @@ public class Context extends Object { } public SharedPreferences getSharedPreferences(String name, int mode) { - System.out.println("\n\n...> getSharedPreferences(" + name + ")\n\n"); + Slog.v(TAG, "\n\n...> getSharedPreferences(" + name + ")\n\n"); File prefsFile = getSharedPrefsFile(name); return new SharedPreferencesImpl(prefsFile, mode); } @@ -309,19 +309,19 @@ public class Context extends Object { // TODO: do these both work? make them look more alike public FileInputStream openFileInput(String name) throws FileNotFoundException { - System.out.println("openFileInput called for: '" + name + "'"); + Slog.v(TAG, "openFileInput called for: '" + name + "'"); File file = new File(getFilesDir(), name); return new FileInputStream(file); } public FileOutputStream openFileOutput(String name, int mode) throws java.io.FileNotFoundException { - System.out.println("openFileOutput called for: '" + name + "'"); + Slog.v(TAG, "openFileOutput called for: '" + name + "'"); return new FileOutputStream(android.os.Environment.getExternalStorageDirectory().getPath() + "/files/" + name); } public int checkCallingOrSelfPermission(String permission) { - System.out.println("!!! app wants to know if it has a permission: >" + permission + "<"); + Slog.w(TAG, "!!! app wants to know if it has a permission: >" + permission + "< (returning PREMISSION_DENIED)"); return -1; // PackageManager.PERMISSION_DENIED } @@ -329,15 +329,15 @@ public class Context extends Object { public void registerComponentCallbacks(ComponentCallbacks callbacks) {} public boolean bindService(Intent dummy, ServiceConnection dummy2, int dummy3) { - System.out.println("bindService("+dummy+", "+dummy2+", "+dummy3+")"); + Slog.w(TAG, "bindService("+dummy+", "+dummy2+", "+dummy3+")"); return false; // maybe? } public void startActivity(Intent intent) { - System.out.println("------------------"); - System.out.println("app wants to startActivity("+intent+"), but we don't support that... :/"); + Slog.w(TAG, "------------------"); + Slog.w(TAG, "app wants to startActivity("+intent+"), but we don't support that... :/"); try { throw new java.lang.Exception(); } catch (java.lang.Exception e) { e.printStackTrace(); } - System.out.println("------------------"); + Slog.w(TAG, "------------------"); } public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) { diff --git a/src/api-impl/android/util/Log.java b/src/api-impl/android/util/Log.java index 4ea8db5d..4a83d98c 100644 --- a/src/api-impl/android/util/Log.java +++ b/src/api-impl/android/util/Log.java @@ -364,11 +364,5 @@ public final class Log { /** * @hide */ - public static /*native*/ int - println_native(int bufID, - int priority, String tag, String msg) { - String out = String.format("`¯´[%d][%d] [%s] : %s", bufID, priority, tag, msg); - System.out.println(out); - return out.getBytes().length; - } + public static native int println_native(int bufID, int priority, String tag, String msg); } diff --git a/src/api-impl/android/view/LayoutInflater.java b/src/api-impl/android/view/LayoutInflater.java index 538306c9..93baea45 100644 --- a/src/api-impl/android/view/LayoutInflater.java +++ b/src/api-impl/android/view/LayoutInflater.java @@ -3,6 +3,7 @@ package android.view; import android.content.Context; import android.content.res.XmlResourceParser; import android.util.AttributeSet; +import android.util.Slog; import android.util.Xml; import java.io.FileReader; import java.lang.reflect.Constructor; @@ -11,6 +12,7 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; public class LayoutInflater { + private static final String TAG = "LayoutInflater"; public interface Factory { } @@ -33,7 +35,7 @@ public class LayoutInflater { } public final View createView(String name, String prefix, AttributeSet attrs) throws Exception { - System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> createView(" + name + ", " + prefix + ", " + attrs + ");"); + Slog.v(TAG, ">>>>>>>>>>>>>>>>>>>>>>>>> createView(" + name + ", " + prefix + ", " + attrs + ");"); String view_class_name = prefix!=null ? prefix + name : name; Class view_class = Class.forName(view_class_name); @@ -68,7 +70,7 @@ public class LayoutInflater { name = attrs.getAttributeValue(null, "class"); } - System.out.println("******** Creating view: " + name); + Slog.v(TAG, "******** Creating view: " + name); View view; @@ -78,7 +80,7 @@ public class LayoutInflater { view = createView(name, null, attrs); } - System.out.println("Created view is: " + view); + Slog.v(TAG, "Created view is: " + view); return view; } @@ -116,9 +118,9 @@ public class LayoutInflater { final String name = parser.getName(); - System.out.println("**************************"); - System.out.println("Creating root view: " + name); - System.out.println("**************************"); + Slog.v(TAG, "**************************"); + Slog.v(TAG, "Creating root view: " + name); + Slog.v(TAG, "**************************"); if (name.equals("merge")) { if (root == null || !attachToRoot) { @@ -139,7 +141,7 @@ public class LayoutInflater { ViewGroup.LayoutParams params = null; if (root != null) { - System.out.println("Creating params from root: " + root); + Slog.v(TAG, "Creating params from root: " + root); // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); @@ -150,12 +152,12 @@ public class LayoutInflater { } } - System.out.println("-----> start inflating children"); + Slog.v(TAG, "-----> start inflating children"); // Inflate all children under temp rInflate(parser, temp, attrs, true); - System.out.println("-----> done inflating children"); + Slog.v(TAG, "-----> done inflating children"); // We are supposed to attach all the views we found (int temp) // to root. Do that now. diff --git a/src/api-impl/android/view/View.java b/src/api-impl/android/view/View.java index dad706b5..7dc723da 100644 --- a/src/api-impl/android/view/View.java +++ b/src/api-impl/android/view/View.java @@ -12,6 +12,7 @@ import android.os.Looper; import android.os.Parcelable; import android.util.AttributeSet; import android.util.LayoutDirection; +import android.util.Slog; import android.util.SparseArray; import android.view.animation.Animation; @@ -26,7 +27,7 @@ public class View extends Object { /** * The logging tag used by this class with android.util.Log. */ - protected static final String VIEW_LOG_TAG = "View"; + protected static final String TAG = "View"; /** * When set to true, apps will draw debugging information about their layouts. @@ -882,7 +883,7 @@ public class View extends Object { // --- stubs public void setContentDescription(CharSequence contentDescription) { - System.out.println("setContentDescription called with: >" + contentDescription + "<"); + Slog.w(TAG, "setContentDescription called with: >" + contentDescription + "<"); } public void setId(int id) { @@ -916,11 +917,11 @@ public class View extends Object { } public void setPressed(boolean pressed) { - System.out.println("calling setPressed on " + this + " with value: " + pressed); + Slog.w(TAG, "calling setPressed on " + this + " with value: " + pressed); } public void setSelected(boolean selected) { - System.out.println("calling setSelected on " + this + " with value: " + selected); + Slog.w(TAG, "calling setSelected on " + this + " with value: " + selected); } public ViewTreeObserver getViewTreeObserver() { @@ -940,7 +941,7 @@ public class View extends Object { public native void setVisibility(int visibility); public void setPadding(int left, int top, int right, int bottom) {} public void setBackgroundResource(int resid) { - // System.out.println("*** setBackgroundResource: " + getString(resid)); +// Slog.w(TAG, "*** setBackgroundResource: " + getString(resid)); } public void getHitRect(Rect outRect) {} @@ -970,7 +971,7 @@ public class View extends Object { } public boolean performHapticFeedback(int feedbackConstant, int flags) { - System.out.println("vibration motor go burrrr"); + Slog.v(TAG, "vibration motor go burrrr"); return true; // FIXME why is it not void } @@ -1000,7 +1001,7 @@ public class View extends Object { } public void postInvalidate(int left, int top, int right, int bottom) { - System.out.println("postInvalidate(" + left + "," + top + "," + right + "," + bottom + ") called"); + Slog.w(TAG, "postInvalidate(" + left + "," + top + "," + right + "," + bottom + ") called"); } public void setOnGenericMotionListener(View.OnGenericMotionListener l) {}