1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// don't strip logging from release builds 18#define LOG_NDEBUG 0 19 20#include <android_runtime/AndroidRuntime.h> 21#include "utils/Log.h" 22#include "DMServiceMain.h" 23#include "dmt.hpp" 24#include "DMTreeManager.h" 25static jobject g_sessionObj; 26int g_cancelSession; 27 28//#define LOGV printf 29//#define LOGD printf 30 31 32#define SET_RET_STATUS_BUF \ 33 jResult = jenv->NewByteArray(5); char szResult[5]; memset(szResult, 0, 5); \ 34 ::snprintf(szResult, 5, "%4d", ret_status); \ 35 jenv->SetByteArrayRegion(jResult, 0, 5, (const jbyte*)szResult) 36 37static void Dump(const char* buf, int size, boolean isBinary) 38{ 39 if (!isBinary) { 40 // just print the string 41 char* szBuf = new char[size + 1]; 42 43 memcpy(szBuf, buf, size); 44 szBuf[size] = 0; 45 46 LOGE("The test script error text:\n\n%s\n\n", szBuf); 47 } else { 48 int nOffset = 0; 49 50 while (size > 0) { 51 int nLine = size > 16 ? 16 : size; 52 53 char s[250]; 54 int pos = 0; 55 56 pos += ::snprintf(s + pos, (250 - pos), "%04x:", nOffset); 57 58 for (int i = 0; i < nLine; i++) { 59 pos += ::snprintf(s + pos, (250 - pos), " %02x", (unsigned int)((unsigned char) buf[i]) ); 60 } 61 for (int i = nLine; i < 16; i++) { 62 pos += ::snprintf(s + pos, (250 - pos), " "); 63 } 64 65 pos += ::snprintf(s + pos, (250 - pos), " "); 66 for (int i = 0; i < nLine; i++) { 67 pos += ::snprintf(s + pos, (250 - pos), "%c", (buf[i] > 31 ? buf[i] : '.') ); 68 } 69 70 LOGE("%s\n", s); 71 buf += nLine; 72 size -= nLine; 73 nOffset += nLine; 74 } 75 } 76} 77 78/** 79 * check the input string is a a valid UTF-8 string or not 80 * 1 -- valid, 0 -- invalid 81 */ 82static jint isUtf8Valid(const char* bytes) { 83 while (*bytes != '\0') { 84 uint8_t utf8 = *(bytes++); 85 // Switch on the high four bits. 86 switch (utf8 >> 4) { 87 case 0x00: 88 case 0x01: 89 case 0x02: 90 case 0x03: 91 case 0x04: 92 case 0x05: 93 case 0x06: 94 case 0x07: 95 // Bit pattern 0xxx. No need for any extra bytes. 96 break; 97 case 0x08: 98 case 0x09: 99 case 0x0a: 100 case 0x0b: 101 case 0x0f: 102 /* 103 * Bit pattern 10xx or 1111, which are illegal start bytes. 104 * Note: 1111 is valid for normal UTF-8, but not the 105 * Modified UTF-8 used here. 106 */ 107 return 0; 108 case 0x0e: 109 // Bit pattern 1110, so there are two additional bytes. 110 utf8 = *(bytes++); 111 if ((utf8 & 0xc0) != 0x80) { 112 return 0; 113 } 114 // Fall through to take care of the final byte. 115 case 0x0c: 116 case 0x0d: 117 // Bit pattern 110x, so there is one additional byte. 118 utf8 = *(bytes++); 119 if ((utf8 & 0xc0) != 0x80) { 120 return 0; 121 } 122 break; 123 } 124 } 125 return 1; 126} 127 128 129JNIEXPORT jint 130initialize(JNIEnv* /*env*/, jobject /*jobj*/) 131{ 132 LOGD("native initialize"); 133 if (!DmtTreeFactory::Initialize()) { 134 LOGE("Failed to initialize DM\n"); 135 return static_cast<jint>(SYNCML_DM_FAIL); 136 } 137 138 return static_cast<jint>(SYNCML_DM_SUCCESS); 139} 140 141JNIEXPORT jint 142destroy(JNIEnv* /*env*/, jobject /*jobj*/) 143{ 144 LOGD("Enter destroy"); 145 if (DmtTreeFactory::Uninitialize() != SYNCML_DM_SUCCESS) { 146 LOGE("Failed to uninitialize DM\n"); 147 return static_cast<jint>(SYNCML_DM_FAIL); 148 } 149 150 LOGD("Leave destroy"); 151 return static_cast<jint>(SYNCML_DM_SUCCESS); 152} 153 154JNIEXPORT jint 155parsePkg0(JNIEnv* env, jclass, jbyteArray jPkg0, jobject jNotification) 156{ 157 LOGD("Enter parsePkg0"); 158 jclass notifClass = env->GetObjectClass(jNotification); 159 160 if (jPkg0 == NULL) { 161 return static_cast<jint>(SYNCML_DM_FAIL); 162 } 163 164 jbyte* pkg0Buf = env->GetByteArrayElements(jPkg0, NULL); 165 jsize pkg0Len = env->GetArrayLength(jPkg0); 166 167 DmtNotification notif; 168 DmtPrincipal p("localhost"); 169 170 SYNCML_DM_RET_STATUS_T ret = DmtTreeFactory::ProcessNotification(p, (UINT8*)pkg0Buf, (INT32)pkg0Len, notif); 171 172 if(ret == SYNCML_DM_FAIL) { 173 return static_cast<jint>(SYNCML_DM_FAIL); 174 } 175 176 jmethodID jSetServerID = env->GetMethodID( notifClass, "setServerID", "(Ljava/lang/String;)V"); 177 178 if(isUtf8Valid(notif.getServerID().c_str())) { 179 jstring jServerID = env->NewStringUTF(notif.getServerID().c_str()); 180 env->CallVoidMethod(jNotification, jSetServerID, jServerID); 181 } else { 182 LOGE("Invalid Server ID, not legal UTF8"); 183 return static_cast<jint>(SYNCML_DM_FAIL); 184 } 185 186 187 jmethodID jSetSessionID = env->GetMethodID( notifClass, "setSessionID", "(I)V"); 188 env->CallVoidMethod(jNotification, jSetSessionID, (jint)notif.getSessionID()); 189 190 jmethodID jSetUIMode = env->GetMethodID( notifClass, "setUIMode", "(I)V"); 191 env->CallVoidMethod(jNotification, jSetUIMode, (jint)notif.getUIMode()); 192 193 jmethodID jSetInitiator = env->GetMethodID( notifClass, "setInitiator", "(I)V"); 194 env->CallVoidMethod(jNotification, jSetInitiator, (jint)notif.getInitiator()); 195 196 jmethodID jSetAuthFlag = env->GetMethodID( notifClass, "setAuthFlag", "(I)V"); 197 env->CallVoidMethod(jNotification, jSetAuthFlag, (jint)notif.getAuthFlag()); 198 199 env->ReleaseByteArrayElements(jPkg0, pkg0Buf, 0); 200 201 LOGD("Leave parsePkg0, ret: %d", ret); 202 return static_cast<jint>(ret); 203} 204 205 206JNIEXPORT jint JNICALL startFotaClientSession(JNIEnv* jenv, jclass, 207 jstring jServerId, jstring jAlertStr, jobject jdmobj) 208{ 209 LOGV("In native startFotaClientSession\n"); 210 211 SYNCML_DM_RET_STATUS_T ret_status = SYNCML_DM_FAIL; 212 DMString serverID; 213 214 g_sessionObj = jdmobj; 215 216 const char* szDmServerId = jenv->GetStringUTFChars(jServerId, NULL); 217 const char* szDMAlertStr = NULL; 218 if (jAlertStr != NULL) { 219 szDMAlertStr = jenv->GetStringUTFChars(jAlertStr, NULL); 220 } 221 222 DmtPrincipal principal(szDmServerId); 223 224 DMString alertURI("./DevDetail/Ext/SystemUpdate"); 225 DMString strEmpty; 226 DmtFirmAlert alert(alertURI, strEmpty, szDMAlertStr, "chr", strEmpty, strEmpty); 227 DmtSessionProp prop(alert, true); 228 229 g_cancelSession = 0; 230 231 ret_status = DmtTreeFactory::StartServerSession(principal, prop); 232 233 if (jAlertStr != NULL) { 234 jenv->ReleaseStringUTFChars(jAlertStr, szDMAlertStr); 235 } 236 237 g_sessionObj = NULL; 238 if (ret_status == SYNCML_DM_SUCCESS) { 239 LOGV("Native startFotaClientSession return successfully\n"); 240 return static_cast<jint>(SYNCML_DM_SUCCESS); 241 } else { 242 LOGE("Native startFotaClientSession return error %d\n", ret_status); 243 return static_cast<jint>(ret_status); 244 } 245} 246 247JNIEXPORT jint JNICALL startClientSession(JNIEnv* jenv, jclass, 248 jstring jServerId, jobject jdmobj) 249{ 250 LOGV("In native startClientSession\n"); 251 252 SYNCML_DM_RET_STATUS_T ret_status = SYNCML_DM_FAIL; 253 DMString serverID; 254 255 g_sessionObj = jdmobj; 256 const char* szDmServerId = jenv->GetStringUTFChars(jServerId, NULL); 257 DmtPrincipal principal(szDmServerId); 258 259 DmtSessionProp prop(true); 260 261 g_cancelSession = 0; 262 263 ret_status = DmtTreeFactory::StartServerSession(principal, prop); 264 265 jenv->ReleaseStringUTFChars(jServerId, szDmServerId); 266 267 g_sessionObj = NULL; 268 if (ret_status == SYNCML_DM_SUCCESS) { 269 LOGV("Native startClientSession return successfully\n"); 270 } else { 271 LOGV("Native startClientSession return error %d\n", ret_status); 272 } 273 return static_cast<jint>(ret_status); 274} 275 276JNIEXPORT jint JNICALL startFotaServerSession(JNIEnv* jenv, jclass, 277 jstring jServerId, jint sessionID, jobject jdmobj) 278{ 279 LOGV("In native startFotaServerSession\n"); 280 281 g_sessionObj = jdmobj; 282 283 const char* szDmServerId = jenv->GetStringUTFChars(jServerId, NULL); 284 DmtPrincipal principal(szDmServerId); 285 DmtSessionProp prop(static_cast<UINT16>(sessionID), true); 286 287 g_cancelSession = 0; 288 289 SYNCML_DM_RET_STATUS_T ret_status = DmtTreeFactory::StartServerSession(principal, prop); 290 291 jenv->ReleaseStringUTFChars(jServerId, szDmServerId); 292 293 g_sessionObj = NULL; 294 295 if (ret_status == SYNCML_DM_SUCCESS) { 296 LOGV("Native startFotaServerSession return successfully\n"); 297 } else { 298 LOGV("Native startFotaServerSession return error %d\n", ret_status); 299 } 300 return static_cast<jint>(ret_status); 301} 302 303JNIEXPORT jint JNICALL startFotaNotifySession(JNIEnv* jenv, jclass, 304 jstring result, jstring pkgURI, jstring alertType, 305 jstring serverID, jstring correlator, jobject jdmobj) 306{ 307 g_sessionObj = jdmobj; 308 309 const char* szResult = jenv->GetStringUTFChars(result, NULL); 310 const char* szPkgURI = jenv->GetStringUTFChars(pkgURI, NULL); 311 const char* szAlertType = jenv->GetStringUTFChars(alertType, NULL); 312 const char* szDmServerId = jenv->GetStringUTFChars(serverID, NULL); 313 const char* szCorrelator = jenv->GetStringUTFChars(correlator, NULL); 314 315 DmtPrincipal principal(szDmServerId); 316 DmtFirmAlert alert(szPkgURI, szResult, szAlertType, "chr", NULL, szCorrelator); 317 DmtSessionProp prop(alert, true); 318 319 SYNCML_DM_RET_STATUS_T dm_result = SYNCML_DM_SUCCESS; 320 g_cancelSession = 0; 321 322 dm_result = DmtTreeFactory::StartServerSession(principal, prop); 323 324 jenv->ReleaseStringUTFChars(result, szResult); 325 jenv->ReleaseStringUTFChars(pkgURI, szPkgURI); 326 jenv->ReleaseStringUTFChars(alertType, szAlertType); 327 jenv->ReleaseStringUTFChars(serverID, szDmServerId); 328 jenv->ReleaseStringUTFChars(correlator, szCorrelator); 329 330 g_sessionObj = NULL; 331 if (dm_result == SYNCML_DM_SUCCESS) { 332 LOGV("Native startFotaNotifySession return successfully\n"); 333 } else { 334 LOGV("Native startFotaNotifySession return error %d\n", dm_result); 335 } 336 return static_cast<jint>(dm_result); 337} 338 339jobject getNetConnector() 340{ 341 JNIEnv* env = android::AndroidRuntime::getJNIEnv(); 342 343 jclass jdmSessionClz = env->GetObjectClass(g_sessionObj); 344 jmethodID jgetNet = env->GetMethodID(jdmSessionClz, 345 "getNetConnector", 346 "()Lcom/android/omadm/service/DMHttpConnector;"); 347 return env->CallObjectMethod(g_sessionObj, jgetNet); 348} 349 350jobject getDMAlert(JNIEnv* env) 351{ 352 LOGD(("DM Alert: enter getDMAlert()")); 353 if (NULL == g_sessionObj) { 354 LOGE(("DM Alert: g_sessionObj is NULL!")); 355 return NULL; 356 } 357 358 jclass jdmSessionClz = env->GetObjectClass(g_sessionObj); 359 if (NULL == jdmSessionClz) { 360 LOGE(("DM Alert: env->GetObjectClass(g_sessionObj) failed!")); 361 return NULL; 362 } 363 LOGD(("DM Alert: success env->GetObjectClass(...)")); 364 365 jmethodID jdmGetDMAlert = env->GetMethodID(jdmSessionClz, 366 "getDMAlert", 367 "()Lcom/android/omadm/service/DMAlert;"); 368 if ( NULL == jdmGetDMAlert ) { 369 LOGE(("DM Alert: env->GetMethodID(jdmSessionClz) failed!")); 370 return NULL; 371 } 372 LOGD(("DM Alert: success env->GetMethodID(...)")); 373 374 return env->CallObjectMethod(g_sessionObj, jdmGetDMAlert); 375} 376 377JNIEXPORT jint JNICALL cancelSession(JNIEnv*, jclass) 378{ 379 g_cancelSession = 1; 380 return static_cast<jint>(SYNCML_DM_SUCCESS); 381} 382 383JNIEXPORT jstring JNICALL parseBootstrapServerId(JNIEnv* jenv, jclass, jbyteArray jMsgBuf, 384 jboolean isWbxml) 385{ 386 jint retCode = 0; 387 jstring jServerId = NULL; 388 389 SYNCML_DM_RET_STATUS_T dm_ret_status; 390 391 jbyte* jBuf = jenv->GetByteArrayElements(jMsgBuf, NULL); 392 jsize jBufSize = jenv->GetArrayLength(jMsgBuf); 393 394 DmtPrincipal principal("DM_BOOTSTRAP"); 395 DMString strServerId; 396 dm_ret_status = DmtTreeFactory::Bootstrap(principal, (const UINT8*)jBuf, jBufSize, isWbxml, 397 false, strServerId); 398 399 LOGD("parseBootstrapServerId dm_ret_status: %d", dm_ret_status); 400 401 if (dm_ret_status == SYNCML_DM_SUCCESS && !strServerId.empty()) { 402 LOGD("parseBootstrapServerId returns strServerId: %s", strServerId.c_str()); 403 jServerId = jenv->NewStringUTF(strServerId.c_str()); 404 } 405 406 return jServerId; 407} 408 409JNIEXPORT jint JNICALL processBootstrapScript(JNIEnv* jenv, jclass, jbyteArray jMsgBuf, jboolean isWbxml, jstring jServerId) 410{ 411 SYNCML_DM_RET_STATUS_T dm_ret_status; 412 const char* szDmServerId = jenv->GetStringUTFChars(jServerId, NULL); 413 414 jbyte* jBuf = jenv->GetByteArrayElements(jMsgBuf, NULL); 415 jsize jBufSize = jenv->GetArrayLength(jMsgBuf); 416 417 DmtPrincipal principal("DM_BOOTSTRAP"); 418 DMString strServerId(szDmServerId); 419 dm_ret_status = DmtTreeFactory::Bootstrap( 420 principal, (const UINT8*)jBuf, jBufSize, isWbxml, true, strServerId); 421 422 LOGD("processBootstrapScript dm_ret_status: %d", static_cast<jint>(dm_ret_status)); 423 424 return static_cast<jint>(dm_ret_status); 425} 426 427 428JNIEXPORT jbyteArray JNICALL processScript(JNIEnv* jenv, jclass, jstring jServerId, 429 jstring jFileName, jboolean jIsBinary, jint /*jRetCode*/, jobject jdmobj) 430{ 431 LOGV("In native processScript\n"); 432 g_sessionObj = jdmobj; 433 434 jbyteArray jResult = NULL; 435 SYNCML_DM_RET_STATUS_T ret_status; 436 437 const char* szDmServerId = jenv->GetStringUTFChars(jServerId, NULL); 438 439 if (szDmServerId == NULL) { 440 ret_status = SYNCML_DM_DEVICE_FULL; 441 SET_RET_STATUS_BUF; 442 return jResult; 443 } 444 445 const char* szFileName = jenv->GetStringUTFChars(jFileName, NULL); 446 if (szFileName == NULL) { 447 jenv->ReleaseStringUTFChars(jServerId, szDmServerId); 448 ret_status = SYNCML_DM_DEVICE_FULL; 449 SET_RET_STATUS_BUF; 450 return jResult; 451 } 452 453 LOGV("native processScript reading file <%s>\n", szFileName); 454 455 FILE *fd = fopen(szFileName, "r"); 456 if (!fd) { 457 LOGV("native processScript can't open file %s", szFileName); 458 ret_status = SYNCML_DM_FILE_NOT_FOUND; 459 SET_RET_STATUS_BUF; 460 return jResult; 461 } 462 463 // assume 100k is enough 464 const int c_nSize = 100 * 1024; 465 char* szBuf = new char[c_nSize]; 466 467 if (szBuf == NULL) { 468 ret_status = SYNCML_DM_DEVICE_FULL; 469 SET_RET_STATUS_BUF; 470 return jResult; 471 } 472 473 int buf_size = fread(szBuf, 1, c_nSize, fd ); 474 LOGE("native processScript read %d bytes, jIsBinary=%d\n", buf_size, jIsBinary); 475 476 477 if (buf_size > 0) { 478 DmtPrincipal principal(szDmServerId); 479 DMVector<UINT8> bResult; 480 481 ret_status = DmtTreeFactory::ProcessScript(principal, (const UINT8*)szBuf, buf_size, jIsBinary, bResult); 482 483 // copy bResult to jResult 484 int resultSize = bResult.size(); 485 486 if (resultSize > 0) { 487 //Dump((const char*)&bResult.front(), resultSize, jIsBinary); 488 Dump((const char*)bResult.get_data(), resultSize, jIsBinary); 489 490 jResult = jenv->NewByteArray(resultSize); 491 492 //jenv->SetByteArrayRegion(jResult, 0, resultSize, (const jbyte*)&bResult.front()); 493 jenv->SetByteArrayRegion(jResult, 0, resultSize, (const jbyte*)bResult.get_data()); 494 } 495 else { 496 SET_RET_STATUS_BUF; 497 } 498 } 499 else { 500 // read 0 bytes from script file 501 ret_status = SYNCML_DM_IO_FAILURE; 502 SET_RET_STATUS_BUF; 503 } 504 505 // release memory allocated from GetStringUTFChars 506 jenv->ReleaseStringUTFChars(jServerId, szDmServerId); 507 jenv->ReleaseStringUTFChars(jFileName, szFileName); 508 509 510 LOGV("Native processScript return code %d\n", static_cast<jint>(ret_status)); 511 g_sessionObj = NULL; 512 513 return jResult; 514} 515 516 517static JNINativeMethod gMethods[] = { 518 {"initialize", "()I", (void*)initialize}, 519 {"destroy", "()I", (void*)destroy}, 520 {"parsePkg0", "([BLcom/android/omadm/service/DMPkg0Notification;)I", (void*)parsePkg0}, 521 {"startFotaClientSession", 522 "(Ljava/lang/String;Ljava/lang/String;Lcom/android/omadm/service/DMSession;)I", 523 (void*)startFotaClientSession}, 524 {"startFotaServerSession", "(Ljava/lang/String;ILcom/android/omadm/service/DMSession;)I", 525 (void*)startFotaServerSession}, 526 {"startClientSession", "(Ljava/lang/String;Lcom/android/omadm/service/DMSession;)I", 527 (void*)startClientSession}, 528 529 {"startFotaNotifySession", 530 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/android/omadm/service/DMSession;)I", 531 (void*)startFotaNotifySession}, 532 533 {"cancelSession", "()I", (void*)cancelSession}, 534 535 {"processScript", 536 "(Ljava/lang/String;Ljava/lang/String;ZILcom/android/omadm/service/DMSession;)[B", 537 (void*)processScript}, 538}; 539 540int registerNatives(JNIEnv* env) 541{ 542 jclass clazz = env->FindClass(javaDMEnginePackage); 543 if (clazz == NULL) 544 return JNI_FALSE; 545 546 if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) { 547 LOGE("registerNatives return ERROR"); 548 return JNI_FALSE; 549 } 550 551 registerDMTreeNatives(env); 552 return JNI_TRUE; 553} 554 555JNIEXPORT jint JNICALL 556JNI_OnLoad(JavaVM* /*vm*/, void* /*reserved*/) 557{ 558 LOGD("In JNI_OnLoad"); 559 JNIEnv* env = android::AndroidRuntime::getJNIEnv(); 560 561 if (env == NULL) { 562 LOGE("Get Environment Error"); 563 return -1; 564 } 565 566 return (registerNatives(env) == JNI_TRUE) ? JNI_VERSION_1_6 : -1; 567} 568