exception appears during reinitializing Preferences
balamyt opened this issue · 10 comments
in build.gradle:
implementation 'com.github.iamironz:binaryprefs:0.9.9'
сreate the settings as follows
return new BinaryPreferencesBuilder(MainApplication.getInstance())
.name(BuildConfig.PREFERENCE_FOLDER)
.encryption(customEncryptor)
.registerPersistable(MyEntity.KEY, MyEntity.class)
.build();//crash is here
entity class
public final class MyEntity implements Persistable, Parcelable {
private int mId;
private String mSource;
private long mLastModification;
private int mRating;
public MyEntity(int id, String source, long lastModification, int rating) {
mId = id;
mSource = source;
mLastModification = lastModification;
mRating = rating;
}
//...
@Override
public void writeExternal(DataOutput out) {
out.writeInt(mId);
out.writeString(mSource);
out.writeLong(mLastModification);
out.writeInt(mRating);
}
@Override
public void readExternal(DataInput in) {
mId = in.readInt();
mSource = in.readString();
mLastModification = in.readLong();
mRating = in.readInt();
}
@Override
public Persistable deepClone() {
return new MyEntity(mId, mSource, mLastModification, mRating);
}
//...
}
When first created Preference it's all right. But if called
mPreferences.edit().putPersistable(key, myEntityInstance).commit();
and then app is killed and removed from recents screen then during the next initialization appears exception:
com.ironz.binaryprefs.exception.FileOperationException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:44)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64)
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java:43)
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88)
at by.klepcha.app.dagger.ActivityModule.providePreferences(ActivityModule.java:53)
...
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
Caused by: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at java.util.concurrent.FutureTask.report(FutureTask.java:93)
at java.util.concurrent.FutureTask.get(FutureTask.java:163)
at com.ironz.binaryprefs.task.Completable.completeBlockingUnsafe(Completable.java:42)
at com.ironz.binaryprefs.BinaryPreferences.fetchCache(BinaryPreferences.java:64)
at com.ironz.binaryprefs.BinaryPreferences.(BinaryPreferences.java:43)
at com.ironz.binaryprefs.BinaryPreferencesBuilder.build(BinaryPreferencesBuilder.java:88)
at by.klepcha.app.dagger.ActivityModule.providePreferences(ActivityModule.java:53)
...
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
Caused by: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at com.ironz.binaryprefs.serialization.SerializerFactory.deserialize(SerializerFactory.java:54)
at com.ironz.binaryprefs.BinaryPreferences$1.run(BinaryPreferences.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Hi.
Thanks for issue submitting.
I will investigate this as soon as possible.
Regards.
@balamyt I see that you has no have default constructor for MyEntity
class. You actually don't?
Also your customEncryptor#encrypt
or recrypt
field's methods implementation returns correct encrypted result or byte[0]
?
This usually happens if you provide empty byte array into FileAdapter
for saving.
Also try to use no-op encryption to replay the situation: https://github.com/iamironz/binaryprefs/blob/master/library/src/main/java/com/ironz/binaryprefs/encryption/ByteEncryption.java#L27-L37
I see that you has no have default constructor for MyEntity class. You actually don't?
Yes, I have not default constructor.
my customEncryptor#encrypt
:
@Override
public byte[] encrypt(byte[] bytes) {
if (!hasAlias()) {
throw createExceptionForDevelopment("set aliases to keystore before encrypt");
}
try {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) mKeyStore.getEntry(mAlias, null);
RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();
Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
inCipher.init(Cipher.ENCRYPT_MODE, publicKey);
return encrypt(bytes, inCipher);
} catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException | NoSuchProviderException e) {
throw createExceptionForUser("in encrypt() something wrong at process with encryption", e, e.getLocalizedMessage());
} catch (NoSuchPaddingException | InvalidKeyException e) {
throw createExceptionForDevelopment("need check to correct alias before");
}
}
private byte[] encrypt(byte[] bytes, Cipher inCipher) throws AppKeystoreException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, inCipher);
try {
cipherOutputStream.write(bytes);
return outputStream.toByteArray();
} catch (IOException e) {
throw createExceptionForUser("in encrypt() something wrong at process with cipherOutputStream", e, e.getLocalizedMessage());
} finally {
CloseableUtils.close(cipherOutputStream);
}
}
@balamyt try create an unit test which encrypts and decrypts non-empty byte[]
value with your encryption.
Also please note that you should have default constructor because during initialization it will be called.
Thank!!
It's all right!
The problem was my encryption implementation.
Also i've added two stages byte array length checking:
iamironz@bf0ef9d
iamironz@53678f7
This checks will be in 1.0.0-ALPHA1 release.
Regards.