00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 /*************************************************************************** 00009 * RCS INFORMATION: 00010 * 00011 * $RCSfile: androidvmdstart.C,v $ 00012 * $Author: johns $ $Locker: $ $State: Exp $ 00013 * $Revision: 1.11 $ $Date: 2020年02月26日 06:39:27 $ 00014 * 00015 ***************************************************************************/ 00021 // only compile this file if we're building on Android 00022 #if defined(ANDROID) 00023 #include "androidvmdstart.h" 00024 #include "vmd.h" 00025 00026 // 00027 // VMD is wrapped in a JNI shared object and called by Java... 00028 // 00029 #include <stdio.h> 00030 #include <jni.h> 00031 00032 #if !defined(VMD_JNI_CLASSNAME) 00033 #define VMD_JNI_CLASSNAME "edu/uiuc/VMD/VMD" 00034 #endif 00035 #if !defined(VMD_JNI_WRAPFUNC) 00036 #define VMD_JNI_WRAPFUNC Java_edu_uiuc_VMD_VMD_nativeMain 00037 #endif 00038 00039 #define NUM_METHODS 5 00040 #define METH_logOutput 0 00041 #define METH_getNumMsgs 1 00042 #define METH_getPlatformValue 2 00043 #define METH_getMsgBlock 3 00044 #define METH_getMsgNonBlock 4 00045 00046 struct AndroidHandle { 00047 JNIEnv *env; 00048 jobject thiz; 00049 jmethodID meths[NUM_METHODS]; 00050 } global_AndHand; 00051 00052 // ---------------------------------------------------------------------- 00053 void logtojava(AndroidHandle &ah, const char *logstring) 00054 { 00055 /* this actually logs a char*, logstring */ 00056 (ah.env)->CallVoidMethod(ah.thiz, 00057 ah.meths[METH_logOutput], 00058 (ah.env)->NewStringUTF( logstring)); 00059 } 00060 00061 /* ------------------------------------------------------------ */ 00062 /* output is allocated elsewhere */ 00063 /* key: FilesDir - gets internal phone memory space for the app. The zip 00064 file from server is unzipped to this dir */ 00065 /* key: VMDDIR - gets internal phone memory space, where VMD files live 00066 (currently exactly same as FilesDir */ 00067 /* key: ExternalStorageDir - gets SDcard memory space (global, use with care)*/ 00068 char *getPlatformValue(AndroidHandle &ah, const char *key, char *output) 00069 { 00070 00071 /* NewStringUTF makes a java string from a char* */ 00072 jobject j = (ah.env)->CallObjectMethod(ah.thiz, 00073 ah.meths[METH_getPlatformValue], 00074 (ah.env)->NewStringUTF(key)); 00075 00076 const char* str = (ah.env)->GetStringUTFChars((jstring) j, NULL); 00077 00078 strcpy(output, str); 00079 00080 (ah.env)->ReleaseStringUTFChars((jstring) j, str); 00081 return output; 00082 } 00083 00084 /* ------------------------------------------------------------ */ 00085 /* Get string Message from Android frontend. Blocks until message 00086 * is actually sent. 00087 * 'output' is allocated elsewhere. 00088 * Returns pointer to 'output' as convenience. 00089 */ 00090 char *getMessage(AndroidHandle &ah, char *output) 00091 { 00092 jobject j = (ah.env)->CallObjectMethod(ah.thiz, 00093 ah.meths[METH_getMsgBlock]); 00094 00095 const char* str = (ah.env)->GetStringUTFChars((jstring) j, NULL); 00096 00097 strcpy(output, str); 00098 00099 (ah.env)->ReleaseStringUTFChars((jstring) j, str); 00100 return output; 00101 } 00102 00103 /* ------------------------------------------------------------ */ 00104 /* Get string Message from Android frontend if one is ready. 00105 * 'output' is allocated elsewhere. Returns 'output' if message 00106 * existed. Returns 0 (and doesn't modify 'output') if no 00107 * message was waiting. 00108 * XXX need think about how to use 00109 */ 00110 char *getMessageNonBlock(AndroidHandle &ah, char *output) 00111 { 00112 jobject j = (ah.env)->CallObjectMethod(ah.thiz, 00113 ah.meths[METH_getMsgNonBlock]); 00114 00115 if (!j) { 00116 return 0; 00117 } 00118 00119 const char* str = (ah.env)->GetStringUTFChars((jstring) j, NULL); 00120 00121 strcpy(output, str); 00122 00123 (ah.env)->ReleaseStringUTFChars((jstring) j, str); 00124 return output; 00125 } 00126 00127 /* ------------------------------------------------------------ */ 00128 /* Get the number of messages that the Android frontend has queued 00129 * up ready to be consumed by one of the getMessage fcts. 00130 */ 00131 jint getNumMessages(AndroidHandle &ah) 00132 { 00133 return (ah.env)->CallIntMethod(ah.thiz, 00134 ah.meths[METH_getNumMsgs]); 00135 } 00136 00137 // ---------------------------------------------------------------------- 00138 /* Internally used fct called at startup to perform expensive tasks once. 00139 */ 00140 void cacheAndroidMethodIDs(AndroidHandle &ah) 00141 { 00142 // cache method IDs. Could be done in fct, of course 00143 // these calls are expensive 00144 jclass clazz = (ah.env)->FindClass("edu/uiuc/VMD/VMD"); 00145 ah.meths[METH_logOutput] = (ah.env)->GetMethodID( 00146 clazz, "logOutput", "(Ljava/lang/String;)V"); 00147 ah.meths[METH_getNumMsgs] = (ah.env)->GetMethodID( 00148 clazz, "getNumMsgs", "()I"); 00149 ah.meths[METH_getPlatformValue] = (ah.env)->GetMethodID( 00150 clazz, "getPlatformValue", 00151 "(Ljava/lang/String;)Ljava/lang/String;"); 00152 ah.meths[METH_getMsgBlock] = (ah.env)->GetMethodID( 00153 clazz, "getMsgBlock", "()Ljava/lang/String;"); 00154 ah.meths[METH_getMsgNonBlock] = (ah.env)->GetMethodID( 00155 clazz, "getMsgNonBlock", "()Ljava/lang/String;"); 00156 } 00157 00158 extern "C" { 00159 00160 // 00161 // Wrapper function to hide use of the cached global state until 00162 // until we make appropriate changes so that the JNI launcher has 00163 // a mechanism to provide VMD with the JNI objects for use by calls 00164 // back to android APIs. 00165 // 00166 void log_android(const char *prompt, const char * msg) { 00167 char logstring[2048]; 00168 00169 strncpy(logstring, prompt, sizeof(logstring)-2); 00170 strcat(logstring, msg); 00171 strcat(logstring, "\n"); 00172 00173 logtojava(global_AndHand, logstring); 00174 } 00175 00176 00177 // 00178 // This is the main JNI wrapper function. 00179 // Contains startup code, neverending loop, shutdown code, etc... 00180 // 00181 void VMD_JNI_WRAPFUNC(JNIEnv* env, jobject thiz) { 00182 char* rargv[10]; 00183 00184 global_AndHand.env = env; // XXX this is a hack! 00185 global_AndHand.thiz = thiz; // XXX this is a hack! 00186 00187 cacheAndroidMethodIDs(global_AndHand); // XXX this caches into a hack! 00188 00189 fprintf(stderr, "--stderr fprintf---------------------------------\n"); 00190 printf("---regular printf----------------------------\n"); 00191 fflush(stdout); 00192 log_android("", "--Log event ---------------------"); 00193 00194 #if 1 00195 printf("VMD Android platform info:\n"); 00196 printf(" sizeof(char): %d\n", sizeof(char)); 00197 printf(" sizeof(int): %d\n", sizeof(int)); 00198 printf(" sizeof(long): %d\n", sizeof(long)); 00199 printf(" sizeof(void*): %d\n", sizeof(void*)); 00200 fflush(stdout); 00201 #endif 00202 00203 char tmp[8192]; 00204 const char * vmddir = NULL; 00205 00206 // set to a worst-case guess until we have something better. 00207 vmddir = "/data/data/edu.uiuc.VMD/files/vmd"; 00208 00209 #if 1 00210 // Query Android for app directories and files here... 00211 char androidappdatadir[8192]; 00212 00213 memset(androidappdatadir, 0, sizeof(androidappdatadir)); 00214 getPlatformValue(global_AndHand, "FilesDir", androidappdatadir); 00215 00216 if (strlen(androidappdatadir) > 0) { 00217 // log_android("ANDROID APP DIR: ", androidappdatadir); 00218 strcat(androidappdatadir, "/vmd"); 00219 vmddir = androidappdatadir; 00220 } 00221 #endif 00222 00223 if (vmddir == NULL) { 00224 return; // fail/exit 00225 } 00226 00227 if (!getenv("VMDDIR")) { 00228 setenv("VMDDIR", vmddir, 1); 00229 } 00230 00231 if (!getenv("TCL_LIBRARY")) { 00232 strcpy(tmp, vmddir); 00233 strcat(tmp, "/scripts/tcl"); 00234 setenv("TCL_LIBRARY", tmp, 1); 00235 } 00236 00237 if (!getenv("TK_LIBRARY")) { 00238 strcpy(tmp, vmddir); 00239 strcat(tmp, "/scripts/tk"); 00240 setenv("TK_LIBRARY", tmp, 1); 00241 } 00242 00243 if (!getenv("PYTHONPATH")) { 00244 strcpy(tmp, vmddir); 00245 strcat(tmp, "/scripts/python"); 00246 setenv("PYTHONPATH", tmp, 1); 00247 } else { 00248 strcpy(tmp, getenv("PYTHONPATH")); 00249 strcat(tmp, ":"); 00250 strcat(tmp, vmddir); 00251 strcat(tmp, "/scripts/python"); 00252 setenv("PYTHONPATH", tmp, 1); 00253 } 00254 00255 if (!getenv("STRIDE_BIN")) { 00256 strcpy(tmp, vmddir); 00257 #if defined(ARCH_ANDROIDARMV7A) 00258 strcat(tmp, "/stride_ANDROIDARMV7A"); 00259 #else 00260 #error unhandled compilation scenario 00261 #endif 00262 setenv("STRIDE_BIN", tmp, 1); 00263 } 00264 00265 if (!getenv("SURF_BIN")) { 00266 strcpy(tmp, vmddir); 00267 #if defined(ARCH_ANDROIDARMV7A) 00268 strcat(tmp, "/surf_ANDROIDARMV7A"); 00269 #else 00270 #error unhandled compilation scenario 00271 #endif 00272 setenv("SURF_BIN", tmp, 1); 00273 } 00274 00275 if (!getenv("TACHYON_BIN")) { 00276 strcpy(tmp, vmddir); 00277 #if defined(ARCH_ANDROIDARMV7A) 00278 strcat(tmp, "/tachyon_ANDROIDARMV7A"); 00279 #else 00280 #error unhandled compilation scenario 00281 #endif 00282 setenv("TACHYON_BIN", tmp, 1); 00283 } 00284 00285 rargv[0] = (char *) "VMD.so"; 00286 #if 1 00287 rargv[1] = (char *) "1e79"; 00288 #elif 1 00289 rargv[1] = (char *) "/data/data/edu.uiuc.VMD/files/alanin.pdb"; 00290 #else 00291 rargv[1] = (char *) "-h"; 00292 #endif 00293 rargv[2] = NULL; 00294 00295 VMDmain(2, rargv); /* launch VMD... */ 00296 00297 log_android("", "--Log event ---------------------"); 00298 fprintf(stderr, "--stderr fprintf---------------------------------\n"); 00299 printf("---regular printf----------------------------\n"); 00300 fflush(stdout); 00301 } 00302 00303 } // extern "C" 00304 00305 #endif 00306