Skip to content

Commit

Permalink
[MOBILE-1853] Fix datastore crash (#825)
Browse files Browse the repository at this point in the history
* [MOBILE-1853] Fix datastore crash

* Fixes

* Release 13.3.3

* Feedback
  • Loading branch information
rlepinski authored Aug 24, 2020
1 parent f87c069 commit 508fd65
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

[Migration Guides](https://github.com/urbanairship/android-library/tree/main/documentation/migration)

## Version 13.3.3 - August 24, 2020
Patch release to fix SQL exceptions during SDK init. Applications that are seeing any SQL crashes from Airship should update.

## Version 13.3.2 - July 28, 2020
Patch release to fix In-App Automation version triggers to only fire on app updates instead of new installs.

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ buildscript {

ext {
// Airship Version - major.minor.patch
airshipVersion = '13.3.2'
airshipVersion = '13.3.3'

// Airship Version Qualifier beta, release, etc...
// airshipVersionQualifier = "beta"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.urbanairship.util.UAStringUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -100,24 +101,122 @@ public void removeListener(@NonNull PreferenceChangeListener listener) {
* Initializes the preference data store.
*/
protected void init() {
Cursor cursor = resolver.query(UrbanAirshipProvider.getPreferencesContentUri(context), null, null, null, null);
if (cursor == null) {
loadPreferences();
}

private void loadPreferences() {
Cursor cursor = null;

try {
List<Preference> fromStore = new ArrayList<>();

cursor = resolver.query(UrbanAirshipProvider.getPreferencesContentUri(context), null, null, null, null);
if (cursor == null) {
Logger.error("Failed to load preferences. Retrying with fallback loading.");
fallbackLoad();
return;
}

int keyIndex = cursor.getColumnIndex(PreferencesDataManager.COLUMN_NAME_KEY);
int valueIndex = cursor.getColumnIndex(PreferencesDataManager.COLUMN_NAME_VALUE);

while (cursor.moveToNext()) {
String key = cursor.getString(keyIndex);
String value = cursor.getString(valueIndex);
fromStore.add(new Preference(key, value));
}

cursor.close();
finishLoad(fromStore);
} catch (Exception e) {
if (cursor != null) {
cursor.close();
}

Logger.error(e, "Failed to load preferences. Retrying with fallback loading.");
fallbackLoad();
}
}

private void fallbackLoad() {
List<String> keys = queryKeys();
if (keys.isEmpty()) {
Logger.error("Unable to load keys, deleting preference store.");
resolver.delete(UrbanAirshipProvider.getPreferencesContentUri(context), null, null);
return;
}

int keyIndex = cursor.getColumnIndex(PreferencesDataManager.COLUMN_NAME_KEY);
int valueIndex = cursor.getColumnIndex(PreferencesDataManager.COLUMN_NAME_VALUE);
List<Preference> fromStore = new ArrayList<>();

while (cursor.moveToNext()) {
String key = cursor.getString(keyIndex);
String value = cursor.getString(valueIndex);
Preference preference = new Preference(key, value);
preference.registerObserver();
for (String key : keys) {
String value = queryValue(key);
if (value == null) {
Logger.error("Unable to fetch preference value. Deleting: %s", key);
resolver.delete(UrbanAirshipProvider.getPreferencesContentUri(context), "_id == ?", new String[] { key });
} else {
fromStore.add(new Preference(key, value));
}
}

preferences.put(key, preference);
finishLoad(fromStore);
}

private String queryValue(String key) {
String[] columns = new String[] {
PreferencesDataManager.COLUMN_NAME_VALUE
};

Cursor cursor = null;
String value = null;

try {
cursor = resolver.query(UrbanAirshipProvider.getPreferencesContentUri(context), columns, "_id == ?", new String[] { key }, null);
if (cursor != null && cursor.moveToFirst()) {
value = cursor.getString(0);
}
} catch (Exception e) {
Logger.error(e, "Failed to query preference: %s", key);
} finally {
if (cursor != null) {
cursor.close();
}
}

return value;
}

@NonNull
private List<String> queryKeys() {
String[] columns = new String[] {
PreferencesDataManager.COLUMN_NAME_KEY
};

Cursor cursor = null;
try {
cursor = resolver.query(UrbanAirshipProvider.getPreferencesContentUri(context), columns, null, null, null);
if (cursor == null) {
resolver.delete(UrbanAirshipProvider.getPreferencesContentUri(context), null, null);
}
List<String> keys = new ArrayList<>();
while (cursor.moveToNext()) {
keys.add(cursor.getString(0));
}
return keys;
} catch (Exception e) {
Logger.error(e, "Failed to query keys.");
} finally {
if (cursor != null) {
cursor.close();
}
}
return Collections.emptyList();
}

cursor.close();
private void finishLoad(@NonNull List<Preference> preferences) {
for (Preference preference : preferences) {
this.preferences.put(preference.key, preference);
preference.registerObserver();
}
}

/**
Expand Down Expand Up @@ -505,7 +604,11 @@ void syncValue() {
}

if (cursor != null) {
setValue(cursor.moveToFirst() ? cursor.getString(0) : null);
try {
setValue(cursor.moveToFirst() ? cursor.getString(0) : null);
} catch (Exception e) {
Logger.error(e, "Unable to sync preference %s from database", key);
}
} else {
Logger.debug("PreferenceDataStore - Unable to get preference %s from database. Falling back to cached value.", key);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ protected void init() {
}

channelCreationDelayEnabled = getId() == null && runtimeConfig.getConfigOptions().channelCreationDelayEnabled;
attributeMutationStore.collapseAndSaveMutations();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ public ChannelRegistrationPayload.Builder extend(@NonNull ChannelRegistrationPay
if (airshipChannel.getId() != null && (!isIdUpToDate() || getId() != null)) {
dispatchNamedUserUpdateJob();
}

attributeMutationStore.collapseAndSaveMutations();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ public TagGroupRegistrar(@NonNull AirshipRuntimeConfig runtimeConfig,
this.namedUserStore = namedUserStore;
this.channelStore = channelStore;
this.client = client;

namedUserStore.collapseMutations();
channelStore.collapseMutations();
}

/**
Expand Down

0 comments on commit 508fd65

Please sign in to comment.