Skip to content

Commit ad9e602

Browse files
committed
add 64bit support for UI layer:
add a cache in between native and JNI to make 64 bit pointersafe when native passes UI pointer to JNI, an ID is assigned for the UI pointer, and ID is passed to JNI/JAVA side; when JAVA notifies native side for user event, JAVA pass back the given ID to native, native do an immediate lookup to get back the UI object pointer, and our life begins from here normally as before Change-Id: I1c2d076edd626dd24ca2ec61726f1ef7d8f8e83f
1 parent 73758b7 commit ad9e602

File tree

7 files changed

+109
-16
lines changed

7 files changed

+109
-16
lines changed

samples-android/TbmpSkeletonNative/jni/TBMPSkeletonNativeActivity_Engine.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ int32_t Engine::HandleInput(android_app *app, AInputEvent *event) {
186186
*/
187187
void Engine::HandleCmd(struct android_app *app, int32_t cmd) {
188188
Engine *eng = (Engine *)app->userData;
189-
LOGI("message %d", cmd);
190189
switch (cmd) {
191190
case APP_CMD_SAVE_STATE:
192191
break;

samples-android/TbmpSkeletonNative/jni/jui_helper/JavaUI.cpp

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013 The Android Open Source Project
2+
* Copyright 2015 The Android Open Source Project
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,12 +25,79 @@ extern "C" {
2525
JNIEXPORT void Java_com_sample_helper_JUIHelper_JUICallbackHandler(
2626
JNIEnv *env, jobject thiz, int32_t id, int32_t message, int32_t param1,
2727
int32_t param2) {
28-
JUIBase *p = (JUIBase *)id;
28+
/*
29+
* id from Java is generated token from native side, which would be mapped back
30+
* into an UI pointer; so id is opaque to Java -- Java receives and returns back
31+
* the same id to native side
32+
*/
33+
JUIBase *p = JUIBase::id_factory_.getUIBase(id);
34+
if( p )
35+
p->DispatchEvent(message, param1, param2);
36+
else {
37+
LOGE("Failed to get JUIBase pointer for %d in %s", id, __FILE__);
38+
}
39+
}
40+
}
2941

30-
p->DispatchEvent(message, param1, param2);
42+
/*
43+
* IdFactory Implementation: our ID is just a simple integer starting from 1,and
44+
* keeps on counting up. There is no re-use -- even
45+
* one ID is removed from cache, we still counting up
46+
* It will take a long while to overflow a 32 bit integer
47+
* for UI ids. Even it does, it wrap back, at that time,
48+
* previous low values will long gone.
49+
*/
50+
int32_t IdFactory::cur_id_ = 0;
51+
int32_t IdFactory::getId(const JUIBase* ui_object) {
52+
auto it = ids_.find(ui_object);
53+
if (it == ids_.end()) {
54+
LOGE("IDs not inside hash for %p, patching done (%d)", ui_object, cur_id_);
55+
ids_[ui_object] = ++cur_id_;
56+
return cur_id_;
57+
}
58+
return it->second;
3159
}
60+
JUIBase* IdFactory::getUIBase(int32_t ui_id) {
61+
for (auto id: ids_) {
62+
if(id.second == ui_id) {
63+
return const_cast<JUIBase*>(id.first);
64+
}
65+
}
66+
LOGE("Unable to find object point for ID(%d, %x)", ui_id, ui_id);
67+
return nullptr;
68+
}
69+
bool IdFactory::insert(const JUIBase* ui_object) {
70+
bool status = true;
71+
auto it = ids_.find(ui_object);
72+
if (it != ids_.end()) {
73+
LOGE("Error: %p is already in = %d", it->first, it->second);
74+
LOGE("Overwriting %p with %p for it", it->first, ui_object);
75+
status = false;
76+
//return status; ---> let it fall through
77+
}
78+
ids_[ui_object] = ++cur_id_;
79+
return status;
80+
}
81+
bool IdFactory::remove(const JUIBase* ui_object) {
82+
auto it = ids_.find(ui_object);
83+
if (it == ids_.end()) {
84+
LOGE("IDs not inside hash for %p!!!", ui_object);
85+
return false;
86+
}
87+
ids_.erase(it);
88+
return true;
89+
}
90+
void IdFactory::debugDumpCurrentHashTable(void) {
91+
for (auto id: ids_) {
92+
LOGI("Cached ID (%p = %d)", id.first, id.second);
93+
}
3294
}
3395

96+
/*
97+
* Our global instance for id factory
98+
*/
99+
IdFactory JUIBase::id_factory_;
100+
34101
/*
35102
* JUIView
36103
*/
@@ -138,7 +205,11 @@ void JUIView::AddRule(const int32_t layoutParameterIndex,
138205

139206
void JUIView::AddRule(const int32_t layoutParameterIndex,
140207
const JUIView *parameter) {
141-
AddRule(layoutParameterIndex, (int32_t) parameter);
208+
209+
/*
210+
* perform pointer to id xlation
211+
*/
212+
AddRule(layoutParameterIndex, id_factory_.getId(parameter));
142213
}
143214

144215
void JUIView::SetLayoutParams(const int32_t width, const int32_t height) {

samples-android/TbmpSkeletonNative/jni/jui_helper/JavaUI_Dialog.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void JUIDialog::CreateDialog() {
9090

9191
//Notify 'id' to JNI side
9292
ndk_helper::JNIHelper::GetInstance()->CallVoidMethod(obj_, "setID", "(I)V",
93-
(int32_t) this);
93+
id_factory_.getId(this));
9494
env->DeleteLocalRef(obj);
9595
}
9696

@@ -319,7 +319,7 @@ void JUIAlertDialog::CreateDialog() {
319319

320320
//Notify 'id' to JNI side
321321
ndk_helper::JNIHelper::GetInstance()->CallVoidMethod(obj_, "setID", "(I)V",
322-
(int32_t) this);
322+
id_factory_.getId(this));
323323
env->DeleteLocalRef(obj);
324324
}
325325

samples-android/TbmpSkeletonNative/jni/jui_helper/JavaUI_View.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,33 @@ struct AttributeType {
203203
const int32_t attribute_type;
204204
};
205205

206+
/*
207+
* class IdFactory: cache UI pointers and generate an ID, send ID to Java side
208+
* when get id back from Java, retrieve the UI pointer for that
209+
* ID, and continue. Mainly purpose is for things to be called
210+
* back on UI thread
211+
*/
212+
class JUIBase;
213+
class IdFactory {
214+
public:
215+
int32_t getId(const JUIBase* ui_object);
216+
JUIBase* getUIBase(int32_t ui_id);
217+
void debugDumpCurrentHashTable(void);
218+
bool insert(const JUIBase* ui_object);
219+
bool remove(const JUIBase* ui_object);
220+
221+
private:
222+
std::unordered_map<const JUIBase*, int32_t> ids_;
223+
static int32_t cur_id_;
224+
};
225+
206226
/*
207227
* Base class of JUIView
208228
*/
209229
class JUIBase {
210230
public:
211-
JUIBase() : obj_(NULL) {}
212-
213-
virtual ~JUIBase() {}
231+
JUIBase() : obj_(NULL) { id_factory_.insert(this); }
232+
virtual ~JUIBase() { id_factory_.remove(this); }
214233

215234
/*
216235
* Dispatch Widget events. This one is called from Java code through
@@ -424,6 +443,8 @@ class JUIBase {
424443
return true;
425444
}
426445

446+
static IdFactory id_factory_;
447+
427448
protected:
428449
std::unordered_map<std::string, AttributeParameterStore>
429450
map_attribute_parameters;

samples-android/TbmpSkeletonNative/jni/jui_helper/JavaUI_Window.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace jui_helper {
2424
JUIWindow::JUIWindow()
2525
: activity_(NULL), suspended_(false), windowDestroyed_(false),
2626
jni_helper_java_ref_(NULL), jni_helper_java_class_(NULL), dialog_(NULL) {
27+
JUIBase::id_factory_.insert(reinterpret_cast<const JUIBase*>(this));
2728
views_.clear();
2829
}
2930

@@ -34,6 +35,8 @@ JUIWindow::~JUIWindow() {
3435
env->DeleteGlobalRef(jni_helper_java_ref_);
3536
env->DeleteGlobalRef(jni_helper_java_class_);
3637

38+
JUIBase::id_factory_.remove(reinterpret_cast<const JUIBase *>(this));
39+
3740
}
3841

3942
/*
@@ -251,8 +254,7 @@ jobject JUIWindow::CreateWidget(const char *strWidgetName, void *id) {
251254
}
252255
}
253256

254-
jobject obj =
255-
env->CallObjectMethod(jni_helper_java_ref_, mid, name, (int32_t) id);
257+
jobject obj = env->CallObjectMethod(jni_helper_java_ref_, mid, name, JUIBase::id_factory_.getId(reinterpret_cast<const JUIBase*>(id)));
256258
jobject objGlobal = env->NewGlobalRef(obj);
257259
env->DeleteLocalRef(name);
258260
env->DeleteLocalRef(obj);
@@ -283,9 +285,9 @@ jobject JUIWindow::CreateWidget(const char *strWidgetName, void *id,
283285
return NULL;
284286
}
285287
}
286-
287288
jobject obj = env->CallObjectMethod(jni_helper_java_ref_, mid, name,
288-
(int32_t) id, (int32_t) param);
289+
JUIBase::id_factory_.getId(reinterpret_cast<const JUIBase*>(id)), (int32_t) param);
290+
289291
jobject objGlobal = env->NewGlobalRef(obj);
290292
env->DeleteLocalRef(name);
291293
env->DeleteLocalRef(objGlobal);

samples-android/TbmpSkeletonNative/jni/ndk_helper/JNIHelper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ void JNIHelper::RunOnUiThread(std::function<void()> callback) {
596596
// This JNI function is invoked from UIThread asynchronously
597597
extern "C" {
598598
JNIEXPORT void
599-
Java_com_sample_helper_NDKHelper_RunOnUiThreadHandler(JNIEnv *env,
599+
Java_com_sample_helper_NDKHelper_RunOnUiThreadHandler(JNIEnv *env, jobject thiz,
600600
int64_t pointer) {
601601
std::function<void()> *pCallback = (std::function<void()> *)pointer;
602602
(*pCallback)();

samples-android/TbmpSkeletonNative/jni/ndk_helper/JNIHelper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ class JNIHelper {
285285

286286
extern "C" {
287287
JNIEXPORT void
288-
Java_com_sample_helper_NDKHelper_RunOnUiThreadHandler(JNIEnv *env,
288+
Java_com_sample_helper_NDKHelper_RunOnUiThreadHandler(JNIEnv *env,jobject thiz,
289289
int64_t pointer);
290290
}
291291

0 commit comments

Comments
 (0)