Commit 1511962d authored by pedroGitt's avatar pedroGitt
Browse files

Add serialization feature to OlmAccount

- new JNI API: serializeDataWithKeyJni() and initWithSerializedDataJni()
- update account unit test
- modify OlmAccount constructor API: an exception may be thrown
parent 8b050e5e
...@@ -42,6 +42,7 @@ public class OlmAccountTest { ...@@ -42,6 +42,7 @@ public class OlmAccountTest {
private static OlmAccount mOlmAccount; private static OlmAccount mOlmAccount;
private static OlmManager mOlmManager; private static OlmManager mOlmManager;
private boolean mIsAccountCreated; private boolean mIsAccountCreated;
final String FILE_NAME = "SerialTestFile";
@BeforeClass @BeforeClass
public static void setUpClass(){ public static void setUpClass(){
...@@ -72,7 +73,11 @@ public class OlmAccountTest { ...@@ -72,7 +73,11 @@ public class OlmAccountTest {
@Test @Test
public void test01CreateReleaseAccount() { public void test01CreateReleaseAccount() {
mOlmAccount = new OlmAccount(); try {
mOlmAccount = new OlmAccount();
} catch (OlmException e) {
e.printStackTrace();
}
assertNotNull(mOlmAccount); assertNotNull(mOlmAccount);
mOlmAccount.releaseAccount(); mOlmAccount.releaseAccount();
...@@ -81,7 +86,11 @@ public class OlmAccountTest { ...@@ -81,7 +86,11 @@ public class OlmAccountTest {
@Test @Test
public void test02CreateAccount() { public void test02CreateAccount() {
mOlmAccount = new OlmAccount(); try {
mOlmAccount = new OlmAccount();
} catch (OlmException e) {
e.printStackTrace();
}
assertNotNull(mOlmAccount); assertNotNull(mOlmAccount);
mIsAccountCreated = true; mIsAccountCreated = true;
} }
...@@ -198,16 +207,21 @@ public class OlmAccountTest { ...@@ -198,16 +207,21 @@ public class OlmAccountTest {
public void test13Serialization() { public void test13Serialization() {
FileOutputStream fileOutput = null; FileOutputStream fileOutput = null;
ObjectOutputStream objectOutput = null; ObjectOutputStream objectOutput = null;
OlmAccount accountRef = new OlmAccount(); OlmAccount accountRef = null;
OlmAccount accountDeserial = null; OlmAccount accountDeserial = null;
OlmException exception;
try {
accountRef = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
int retValue = accountRef.generateOneTimeKeys(GENERATION_ONE_TIME_KEYS_NUMBER); int retValue = accountRef.generateOneTimeKeys(GENERATION_ONE_TIME_KEYS_NUMBER);
assertTrue(0==retValue); assertTrue(0==retValue);
// get keys references
JSONObject identityKeysRef = accountRef.identityKeys(); JSONObject identityKeysRef = accountRef.identityKeys();
JSONObject oneTimeKeysRef = accountRef.oneTimeKeys(); JSONObject oneTimeKeysRef = accountRef.oneTimeKeys();
final String FILE_NAME = "testfile";
/*Context context = getInstrumentation().getContext(); /*Context context = getInstrumentation().getContext();
SharedPreferences sharedPref = context.getSharedPreferences("TestPref",Context.MODE_PRIVATE); SharedPreferences sharedPref = context.getSharedPreferences("TestPref",Context.MODE_PRIVATE);
...@@ -217,16 +231,15 @@ public class OlmAccountTest { ...@@ -217,16 +231,15 @@ public class OlmAccountTest {
try { try {
Context context = getInstrumentation().getContext(); Context context = getInstrumentation().getContext();
context.getFilesDir(); context.getFilesDir();
//File serialFile = new File(FILE_NAME);
//fileOutput = new FileOutputStream(serialFile);
fileOutput = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE); fileOutput = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
// serialize
objectOutput = new ObjectOutputStream(fileOutput); objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(accountRef); objectOutput.writeObject(accountRef);
objectOutput.flush(); objectOutput.flush();
objectOutput.close(); objectOutput.close();
//FileInputStream fileInput = new FileInputStream(serialFile); // deserialize
FileInputStream fileInput = context.openFileInput(FILE_NAME); FileInputStream fileInput = context.openFileInput(FILE_NAME);
ObjectInputStream objectInput = new ObjectInputStream(fileInput); ObjectInputStream objectInput = new ObjectInputStream(fileInput);
accountDeserial = (OlmAccount) objectInput.readObject(); accountDeserial = (OlmAccount) objectInput.readObject();
...@@ -234,14 +247,20 @@ public class OlmAccountTest { ...@@ -234,14 +247,20 @@ public class OlmAccountTest {
assertNotNull(accountDeserial); assertNotNull(accountDeserial);
// get de-serialized keys
JSONObject identityKeys2 = accountDeserial.identityKeys(); JSONObject identityKeys2 = accountDeserial.identityKeys();
assertNotNull(identityKeys2);
JSONObject oneTimeKeys2 = accountDeserial.oneTimeKeys(); JSONObject oneTimeKeys2 = accountDeserial.oneTimeKeys();
assertEquals(identityKeysRef, identityKeys2); assertNotNull(oneTimeKeys2);
assertEquals(oneTimeKeysRef, oneTimeKeys2);
// compare identity keys
assertTrue(identityKeys2.toString().equals(identityKeysRef.toString()));
// compare onetime keys
assertTrue(oneTimeKeys2.toString().equals(oneTimeKeysRef.toString()));
accountRef.releaseAccount(); accountRef.releaseAccount();
accountDeserial.releaseAccount(); accountDeserial.releaseAccount();
} }
catch (FileNotFoundException e) { catch (FileNotFoundException e) {
......
...@@ -47,10 +47,16 @@ public class OlmSessionTest { ...@@ -47,10 +47,16 @@ public class OlmSessionTest {
final int ONE_TIME_KEYS_NUMBER = 5; final int ONE_TIME_KEYS_NUMBER = 5;
String bobIdentityKey = null; String bobIdentityKey = null;
String bobOneTimeKey=null; String bobOneTimeKey=null;
OlmAccount bobAccount = null;
OlmAccount aliceAccount = null;
// creates alice & bob accounts // creates alice & bob accounts
OlmAccount aliceAccount = new OlmAccount();
OlmAccount bobAccount = new OlmAccount(); try {
aliceAccount = new OlmAccount();
bobAccount = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
// test accounts creation // test accounts creation
assertTrue(0!=bobAccount.getOlmAccountId()); assertTrue(0!=bobAccount.getOlmAccountId());
...@@ -132,10 +138,16 @@ public class OlmSessionTest { ...@@ -132,10 +138,16 @@ public class OlmSessionTest {
final int ONE_TIME_KEYS_NUMBER = 1; final int ONE_TIME_KEYS_NUMBER = 1;
String bobIdentityKey = null; String bobIdentityKey = null;
String bobOneTimeKey=null; String bobOneTimeKey=null;
OlmAccount aliceAccount = null;
OlmAccount bobAccount = null;
// creates alice & bob accounts // creates alice & bob accounts
OlmAccount aliceAccount = new OlmAccount(); try {
OlmAccount bobAccount = new OlmAccount(); aliceAccount = new OlmAccount();
bobAccount = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
// test accounts creation // test accounts creation
assertTrue(0!=bobAccount.getOlmAccountId()); assertTrue(0!=bobAccount.getOlmAccountId());
...@@ -226,8 +238,14 @@ public class OlmSessionTest { ...@@ -226,8 +238,14 @@ public class OlmSessionTest {
@Test @Test
public void test03AliceBobSessionId() { public void test03AliceBobSessionId() {
// creates alice & bob accounts // creates alice & bob accounts
OlmAccount aliceAccount = new OlmAccount(); OlmAccount aliceAccount = null;
OlmAccount bobAccount = new OlmAccount(); OlmAccount bobAccount = null;
try {
aliceAccount = new OlmAccount();
bobAccount = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
// test accounts creation // test accounts creation
assertTrue(0!=bobAccount.getOlmAccountId()); assertTrue(0!=bobAccount.getOlmAccountId());
......
...@@ -47,9 +47,14 @@ public class OlmUtilityTest { ...@@ -47,9 +47,14 @@ public class OlmUtilityTest {
String fingerPrintKey = null; String fingerPrintKey = null;
StringBuffer errorMsg = new StringBuffer(); StringBuffer errorMsg = new StringBuffer();
String message = "{\"key1\":\"value1\",\"key2\":\"value2\"};"; String message = "{\"key1\":\"value1\",\"key2\":\"value2\"};";
OlmAccount account = null;
// create account // create account
OlmAccount account = new OlmAccount(); try {
account = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
assertNotNull(account); assertNotNull(account);
// sign message // sign message
......
...@@ -26,17 +26,13 @@ import java.io.IOException; ...@@ -26,17 +26,13 @@ import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random; import java.util.Random;
public class OlmAccount implements Serializable { public class OlmAccount implements Serializable {
private static final long serialVersionUID = 3497486121598434824L; private static final long serialVersionUID = 3497486121598434824L;
private static final String LOG_TAG = "OlmAccount"; private static final String LOG_TAG = "OlmAccount";
private static final int MAX_BITS_LENGTH = 128; private static final int RANDOM_KEY_SIZE = 32;
private static final int RANDOM_TAB_SIZE = 32; private static final int RANDOM_RANGE = 256;
private static final int RANDOM_MAX = 256;
// JSON keys used in the JSON objects returned by JNI // JSON keys used in the JSON objects returned by JNI
/** As well as the identity key, each device creates a number of Curve25519 key pairs which are /** As well as the identity key, each device creates a number of Curve25519 key pairs which are
...@@ -60,24 +56,22 @@ public class OlmAccount implements Serializable { ...@@ -60,24 +56,22 @@ public class OlmAccount implements Serializable {
*/ */
private transient long mNativeOlmAccountId; private transient long mNativeOlmAccountId;
private transient SecureRandom mSecureRandom;
public OlmAccount() { public OlmAccount() throws OlmException {
initNewAccount(); if(!initNewAccount()) {
mSecureRandom = new SecureRandom(); throw new OlmException(OlmException.EXCEPTION_CODE_INIT_ACCOUNT_CREATION,OlmException.EXCEPTION_MSG_INIT_ACCOUNT_CREATION);
}
} }
private String getRandomKey() { private String getRandomKey() {
//String keyRetValue = new BigInteger(MAX_BITS_LENGTH, mSecureRandom).toString(RANDOM_TAB_SIZE);
String keyRetValue; String keyRetValue;
Random rand = new Random(); Random rand = new Random();
StringBuilder strBuilder = new StringBuilder(); StringBuilder strBuilder = new StringBuilder();
for(int i=0;i<RANDOM_TAB_SIZE;i++) { for(int i = 0; i< OlmAccount.RANDOM_KEY_SIZE; i++) {
strBuilder.append(rand.nextInt(RANDOM_MAX)); strBuilder.append(rand.nextInt(RANDOM_RANGE));
} }
keyRetValue = "1234567890";//strBuilder.toString(); keyRetValue = strBuilder.toString();
return keyRetValue; return keyRetValue;
} }
...@@ -113,7 +107,7 @@ public class OlmAccount implements Serializable { ...@@ -113,7 +107,7 @@ public class OlmAccount implements Serializable {
} else if(TextUtils.isEmpty(pickledData)) { } else if(TextUtils.isEmpty(pickledData)) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_DESERIALIZATION, OlmException.EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION+" pickle"); throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_DESERIALIZATION, OlmException.EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION+" pickle");
} else if(!initNewAccount()) { } else if(!createNewAccount()) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_DESERIALIZATION, OlmException.EXCEPTION_MSG_INIT_NEW_ACCOUNT_DESERIALIZATION); throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_DESERIALIZATION, OlmException.EXCEPTION_MSG_INIT_NEW_ACCOUNT_DESERIALIZATION);
} else if(!initWithSerializedData(pickledData, key, errorMsg)) { } else if(!initWithSerializedData(pickledData, key, errorMsg)) {
...@@ -190,6 +184,16 @@ public class OlmAccount implements Serializable { ...@@ -190,6 +184,16 @@ public class OlmAccount implements Serializable {
return mNativeOlmAccountId; return mNativeOlmAccountId;
} }
/**
* Release native account and invalid its JAVA reference counter part.<br>
* Public API for {@link #releaseAccountJni()}.
*/
public void releaseAccount(){
releaseAccountJni();
mNativeOlmAccountId = 0;
}
/** /**
* Destroy the corresponding OLM account native object.<br> * Destroy the corresponding OLM account native object.<br>
* This method must ALWAYS be called when this JAVA instance * This method must ALWAYS be called when this JAVA instance
...@@ -199,36 +203,48 @@ public class OlmAccount implements Serializable { ...@@ -199,36 +203,48 @@ public class OlmAccount implements Serializable {
private native void releaseAccountJni(); private native void releaseAccountJni();
/** /**
* Release native account and invalid its JAVA reference counter part.<br> * Create and initialize a native account instance.<br>
* Public API for {@link #releaseAccountJni()}. * Wrapper for {@link #initNewAccountJni()}.
* To be called before any other API call.
* @return true if init succeed, false otherwise.
*/ */
public void releaseAccount(){ private boolean initNewAccount() {
releaseAccountJni(); boolean retCode = false;
if(0 != (mNativeOlmAccountId = initNewAccountJni())){
mNativeOlmAccountId = 0; retCode = true;
}
return retCode;
} }
/** /**
* Create the corresponding OLM account in native side.<br> * Create and initialize an OLM account in native side.<br>
* Do not forget to call {@link #releaseAccount()} when JAVA side is done. * Do not forget to call {@link #releaseAccount()} when JAVA side is done.
* @return native account instance identifier (see {@link #mNativeOlmAccountId}) * @return native account instance identifier (see {@link #mNativeOlmAccountId})
*/ */
private native long initNewAccountJni(); private native long initNewAccountJni();
/** /**
* Create and initialize a new native account instance.<br> * Create a native account instance without any initialization.<br>
* Wrapper for {@link #initNewAccountJni()}. * Since the account is left uninitialized, this
* To be called before any other API call. * method is intended to be used in the serialization mechanism (see {@link #readObject(ObjectInputStream)}).<br>
* Public wrapper for {@link #createNewAccountJni()}.
* @return true if init succeed, false otherwise. * @return true if init succeed, false otherwise.
*/ */
private boolean initNewAccount() { private boolean createNewAccount() {
boolean retCode = false; boolean retCode = false;
if(0 != (mNativeOlmAccountId = initNewAccountJni())){ if(0 != (mNativeOlmAccountId = createNewAccountJni())){
retCode = true; retCode = true;
} }
return retCode; return retCode;
} }
/**
* Create an OLM account in native side.<br>
* Do not forget to call {@link #releaseAccount()} when JAVA side is done.
* @return native account instance identifier (see {@link #mNativeOlmAccountId})
*/
private native long createNewAccountJni();
/** /**
* Return the identity keys (identity &amp fingerprint keys) in a JSON array.<br> * Return the identity keys (identity &amp fingerprint keys) in a JSON array.<br>
* Public API for {@link #identityKeysJni()}.<br> * Public API for {@link #identityKeysJni()}.<br>
......
...@@ -29,6 +29,7 @@ public class OlmException extends Exception { ...@@ -29,6 +29,7 @@ public class OlmException extends Exception {
public static final int EXCEPTION_CODE_ACCOUNT_DESERIALIZATION = 5; public static final int EXCEPTION_CODE_ACCOUNT_DESERIALIZATION = 5;
public static final int EXCEPTION_CODE_SESSION_SERIALIZATION = 6; public static final int EXCEPTION_CODE_SESSION_SERIALIZATION = 6;
public static final int EXCEPTION_CODE_SESSION_DESERIALIZATION = 7; public static final int EXCEPTION_CODE_SESSION_DESERIALIZATION = 7;
public static final int EXCEPTION_CODE_INIT_ACCOUNT_CREATION = 8;
// exception human readable messages // exception human readable messages
public static final String EXCEPTION_MSG_NEW_OUTBOUND_GROUP_SESSION = "failed to create a new outbound group Session"; public static final String EXCEPTION_MSG_NEW_OUTBOUND_GROUP_SESSION = "failed to create a new outbound group Session";
...@@ -38,6 +39,7 @@ public class OlmException extends Exception { ...@@ -38,6 +39,7 @@ public class OlmException extends Exception {
public static final String EXCEPTION_MSG_INIT_NEW_ACCOUNT_DESERIALIZATION = "initNewAccount() failure"; public static final String EXCEPTION_MSG_INIT_NEW_ACCOUNT_DESERIALIZATION = "initNewAccount() failure";
public static final String EXCEPTION_MSG_INIT_ACCOUNT_DESERIALIZATION = "initWithSerializedData() failure"; public static final String EXCEPTION_MSG_INIT_ACCOUNT_DESERIALIZATION = "initWithSerializedData() failure";
public static final String EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION = "invalid deserialized parameters"; public static final String EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION = "invalid deserialized parameters";
public static final String EXCEPTION_MSG_INIT_ACCOUNT_CREATION = "Account constructor failure";
/** exception code to be taken from: {@link #EXCEPTION_CODE_CREATE_OUTBOUND_GROUP_SESSION} {@link #EXCEPTION_CODE_CREATE_INBOUND_GROUP_SESSION} /** exception code to be taken from: {@link #EXCEPTION_CODE_CREATE_OUTBOUND_GROUP_SESSION} {@link #EXCEPTION_CODE_CREATE_INBOUND_GROUP_SESSION}
* {@link #EXCEPTION_CODE_INIT_OUTBOUND_GROUP_SESSION} {@link #EXCEPTION_CODE_INIT_INBOUND_GROUP_SESSION}**/ * {@link #EXCEPTION_CODE_INIT_OUTBOUND_GROUP_SESSION} {@link #EXCEPTION_CODE_INIT_INBOUND_GROUP_SESSION}**/
......
...@@ -40,6 +40,17 @@ OlmAccount* initializeAccountMemory() ...@@ -40,6 +40,17 @@ OlmAccount* initializeAccountMemory()
return accountPtr; return accountPtr;
} }
JNIEXPORT jlong OLM_ACCOUNT_FUNC_DEF(createNewAccountJni)(JNIEnv *env, jobject thiz)
{
LOGD("## createNewAccountJni(): IN");
OlmAccount* accountPtr = initializeAccountMemory();
LOGD(" ## createNewAccountJni(): success - accountPtr=%p (jlong)(intptr_t)accountPtr=%lld",accountPtr,(jlong)(intptr_t)accountPtr);
return (jlong)(intptr_t)accountPtr;
}
/** /**
* Release the account allocation made by initializeAccountMemory().<br> * Release the account allocation made by initializeAccountMemory().<br>
* This method MUST be called when java counter part account instance is done. * This method MUST be called when java counter part account instance is done.
...@@ -49,20 +60,21 @@ JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(releaseAccountJni)(JNIEnv *env, jobject thiz ...@@ -49,20 +60,21 @@ JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(releaseAccountJni)(JNIEnv *env, jobject thiz
{ {
OlmAccount* accountPtr = NULL; OlmAccount* accountPtr = NULL;
LOGD("## releaseAccountJni(): accountPtr=%p",accountPtr); LOGD("## releaseAccountJni(): IN");
if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz))) if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
{ {
LOGE("## releaseAccountJni(): failure - invalid Account ptr=NULL"); LOGE(" ## releaseAccountJni(): failure - invalid Account ptr=NULL");
} }
else else
{ {
LOGD(" ## releaseAccountJni(): accountPtr=%p",accountPtr);
olm_clear_account(accountPtr); olm_clear_account(accountPtr);
LOGD("## releaseAccountJni(): IN"); LOGD(" ## releaseAccountJni(): IN");
// even if free(NULL) does not crash, logs are performed for debug purpose // even if free(NULL) does not crash, logs are performed for debug purpose
free(accountPtr); free(accountPtr);
LOGD("## releaseAccountJni(): OUT"); LOGD(" ## releaseAccountJni(): OUT");
} }
} }
...@@ -467,4 +479,167 @@ JNIEXPORT jstring OLM_MANAGER_FUNC_DEF(getOlmLibVersion)(JNIEnv* env, jobject th ...@@ -467,4 +479,167 @@ JNIEXPORT jstring OLM_MANAGER_FUNC_DEF(getOlmLibVersion)(JNIEnv* env, jobject th
return returnValueStr; return returnValueStr;
} }
/**
* Serialize and encrypt account instance into a base64 string.<br>
* @param aKey key used to encrypt the serialized account data
* @param[out] aErrorMsg error message set if operation failed
* @return a base64 string if operation succeed, null otherwise
**/
JNIEXPORT jstring OLM_ACCOUNT_FUNC_DEF(serializeDataWithKeyJni)(JNIEnv *env, jobject thiz, jstring aKey, jobject aErrorMsg)
{
jstring pickledDataRetValue = 0;
jclass errorMsgJClass = 0;
jmethodID errorMsgMethodId = 0;
jstring errorJstring = 0;
const char *keyPtr = NULL;
void *pickledPtr = NULL;
OlmAccount* accountPtr = NULL;
LOGD("## serializeDataWithKeyJni(): IN");
if(NULL == (accountPtr = (OlmAccount*)getAccountInstanceId(env,thiz)))
{
LOGE(" ## serializeDataWithKeyJni(): failure - invalid account ptr");
}
else if(0 == aKey)
{
LOGE(" ## serializeDataWithKeyJni(): failure - invalid key");
}
else if(0 == aErrorMsg)
{
LOGE(" ## serializeDataWithKeyJni(): failure - invalid error object");
}
else if(0 == (errorMsgJClass = env->GetObjectClass(aErrorMsg)))
{
LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error class");
}
else if(0 == (errorMsgMethodId = env->GetMethodID(errorMsgJClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")))
{
LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error method ID");
}
else if(NULL == (keyPtr = env->GetStringUTFChars(aKey, 0)))
{
LOGE(" ## serializeDataWithKeyJni(): failure - keyPtr JNI allocation OOM");
}
else
{
size_t pickledLength = olm_pickle_account_length(accountPtr);
size_t keyLength = (size_t)env->GetStringUTFLength(aKey);
LOGD(" ## serializeDataWithKeyJni(): pickledLength=%lu keyLength=%lu",pickledLength, keyLength);
LOGD(" ## serializeDataWithKeyJni(): key=%s",(char const *)keyPtr);
if(NULL == (pickledPtr = (void*)malloc((pickledLength+1)*sizeof(uint8_t))))
{
LOGE(" ## serializeDataWithKeyJni(): failure - pickledPtr buffer OOM");
}
else
{
size_t result = olm_pickle_account(accountPtr,
(void const *)keyPtr,
keyLength,
(void*)pickledPtr,
pickledLength);
if(result == olm_error())
{
const char *errorMsgPtr = olm_account_last_error(accountPtr);
LOGE(" ## serializeDataWithKeyJni(): failure - olm_pickle_account() Msg=%s",errorMsgPtr);
if(0 != (errorJstring = env->NewStringUTF(errorMsgPtr)))