Fix Emoji crashes when downloaded bitmap files cannot be found.

This commit is contained in:
Alex Hart 2021-05-07 13:56:14 -03:00 committed by GitHub
parent 276b757e2d
commit 1f3e131690
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 15 deletions

View file

@ -156,7 +156,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
.addNonBlocking(StorageSyncHelper::scheduleRoutineSync)
.addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop())
.addNonBlocking(EmojiSource::refresh)
.addNonBlocking(DownloadLatestEmojiDataJob::scheduleIfNecessary)
.addNonBlocking(() -> DownloadLatestEmojiDataJob.scheduleIfNecessary(this))
.addPostRender(() -> RateLimitUtil.retryAllRateLimitedMessages(this))
.addPostRender(this::initializeExpiringMessageManager)
.execute();

View file

@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import okio.HashingSink
import okio.Okio
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
@ -96,8 +97,12 @@ object EmojiFiles {
val file = version.getFile(context, uuid)
try {
getInputStream(context, file).use {
return Okio.buffer(Okio.source(it)).buffer.md5().toByteArray()
HashingSink.md5(Okio.blackhole()).use { hashingSink ->
Okio.buffer(Okio.source(getInputStream(context, file))).use { source ->
source.readAll(hashingSink)
return hashingSink.hash().toByteArray()
}
}
} catch (e: Exception) {
Log.i(TAG, "Could not read emoji data file md5", e)
@ -129,18 +134,21 @@ object EmojiFiles {
private val objectMapper = ObjectMapper().registerKotlinModule()
@JvmStatic
fun exists(context: Context): Boolean = context.getVersionFile().exists()
@JvmStatic
fun readVersion(context: Context): Version? {
try {
val version = try {
getInputStream(context, context.getVersionFile()).use {
return objectMapper.readValue(it, Version::class.java)
objectMapper.readValue(it, Version::class.java)
}
} catch (e: Exception) {
Log.w(TAG, "Could not read current emoji version from disk.")
return null
null
}
return if (isVersionValid(context, version)) {
version
} else {
null
}
}
@ -160,6 +168,30 @@ object EmojiFiles {
Log.w(TAG, "Could not write current emoji version from disk.")
}
}
@JvmStatic
fun isVersionValid(context: Context, version: Version?): Boolean {
if (version == null) {
Log.d(TAG, "Version does not exist.")
return false
}
val nameCollection = NameCollection.read(context, version)
return if (nameCollection.names.isEmpty()) {
Log.d(TAG, "NameCollection file is empty.")
false
} else {
Log.d(TAG, "Verifying all name files exist.")
val allNamesExist = nameCollection.names
.map { version.getFile(context, it.uuid) }
.all { it.exists() }
Log.d(TAG, "All names exist? $allNamesExist")
allNamesExist
}
}
}
}

View file

@ -45,7 +45,12 @@ object EmojiPageCache {
SimpleTask.run(newTask::run) {
try {
cache[emojiPageRequest] = newTask.get()
val newBitmap: Bitmap? = newTask.get()
if (newBitmap == null) {
Log.w(TAG, "Failed to load emoji bitmap for request $emojiPageRequest")
} else {
cache[emojiPageRequest] = newBitmap
}
} finally {
tasks.remove(emojiPageRequest)
}

View file

@ -41,6 +41,7 @@ import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.HashingSink;
import okio.Okio;
import okio.Sink;
import okio.Source;
/**
@ -62,15 +63,17 @@ public class DownloadLatestEmojiDataJob extends BaseJob {
private EmojiFiles.Version targetVersion;
public static void scheduleIfNecessary() {
public static void scheduleIfNecessary(@NonNull Context context) {
long nextScheduledCheck = SignalStore.emojiValues().getNextScheduledCheck();
if (nextScheduledCheck <= System.currentTimeMillis()) {
Log.i(TAG, "Scheduling DownloadLatestEmojiDataJob.");
ApplicationDependencies.getJobManager().add(new DownloadLatestEmojiDataJob(false));
EmojiFiles.Version version = EmojiFiles.Version.readVersion(context);
long interval;
if (EmojiFiles.Version.exists(ApplicationDependencies.getApplication())) {
if (EmojiFiles.Version.isVersionValid(context, version)) {
interval = INTERVAL_WITH_REMOTE_DOWNLOAD;
} else {
interval = INTERVAL_WITHOUT_REMOTE_DOWNLOAD;
@ -364,12 +367,16 @@ public class DownloadLatestEmojiDataJob extends BaseJob {
byte[] savedMd5;
try (OutputStream outputStream = EmojiFiles.openForWriting(context, version, name.getUuid())) {
Source source = response.body().source();
HashingSink sink = HashingSink.md5(Okio.sink(outputStream));
Source source = response.body().source();
Sink sink = Okio.sink(outputStream);
Okio.buffer(source).readAll(sink);
outputStream.flush();
savedMd5 = sink.hash().toByteArray();
source.close();
sink.close();
savedMd5 = EmojiFiles.getMd5(context, version, name.getUuid());
}
if (!Arrays.equals(savedMd5, Hex.toByteArray(responseMD5))) {