From d934fb43ada7876cc3a7986bbdccaa00bbbec302 Mon Sep 17 00:00:00 2001 From: Keisuke Kuroyanagi Date: Fri, 21 Feb 2014 15:09:37 +0900 Subject: [PATCH] Remove corrupted ver4 dictionaries. Bug: 12916055 Change-Id: I2c390ab1dc483915691b47a605772cbc2dfeaf09 --- .../inputmethod/latin/BinaryDictionary.java | 23 ++++++++++++++++- .../latin/ExpandableBinaryDictionary.java | 25 ++++++++++++------- ...oid_inputmethod_latin_BinaryDictionary.cpp | 13 ++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 013f9220a..c450a1d4f 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin; import android.text.TextUtils; +import android.util.Log; import android.util.SparseArray; import com.android.inputmethod.annotations.UsedForTesting; @@ -29,6 +30,7 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.JniUtils; import com.android.inputmethod.latin.utils.LanguageModelParam; import com.android.inputmethod.latin.utils.StringUtils; @@ -84,6 +86,7 @@ public final class BinaryDictionary extends Dictionary { private final Locale mLocale; private final long mDictSize; private final String mDictFilePath; + private final boolean mIsUpdatable; private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH]; private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_RESULTS]; @@ -130,6 +133,7 @@ public final class BinaryDictionary extends Dictionary { mLocale = locale; mDictSize = length; mDictFilePath = filename; + mIsUpdatable = isUpdatable; mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); loadDictionary(filename, offset, length, isUpdatable); } @@ -177,6 +181,7 @@ public final class BinaryDictionary extends Dictionary { int bigramProbability); private static native int setCurrentTimeForTestNative(int currentTime); private static native String getPropertyNative(long dict, String query); + private static native boolean isCorruptedNative(long dict); public static boolean createEmptyDictFile(final String filePath, final long dictVersion, final Locale locale, final Map attributeMap) { @@ -198,6 +203,22 @@ public final class BinaryDictionary extends Dictionary { mNativeDict = openNative(path, startOffset, length, isUpdatable); } + // TODO: Check isCorrupted() for main dictionaries. + public boolean isCorrupted() { + if (!isValidDictionary()) { + return false; + } + if (!isCorruptedNative(mNativeDict)) { + return false; + } + // TODO: Record the corruption. + Log.e(TAG, "BinaryDictionary (" + mDictFilePath + ") is corrupted."); + Log.e(TAG, "locale: " + mLocale); + Log.e(TAG, "dict size: " + mDictSize); + Log.e(TAG, "updatable: " + mIsUpdatable); + return true; + } + @UsedForTesting public DictionaryHeader getHeader() throws UnsupportedFormatException { if (mNativeDict == 0) { @@ -444,7 +465,7 @@ public final class BinaryDictionary extends Dictionary { // only be called for actual files. Right now it's only called by the flush() family of // functions, which require an updatable dictionary, so it's okay. But beware. loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, - dictFile.length(), true /* isUpdatable */); + dictFile.length(), mIsUpdatable); } public void flush() { diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 230739d6f..f9ab9419b 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -276,22 +276,26 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return attributeMap; } + private void removeBinaryDictionaryLocked() { + if (mBinaryDictionary != null) { + mBinaryDictionary.close(); + } + if (mDictFile.exists() && !FileUtils.deleteRecursively(mDictFile)) { + Log.e(TAG, "Can't remove a file: " + mDictFile.getName()); + } + mBinaryDictionary = null; + } + protected void clear() { - final File dictFile = mDictFile; getExecutor(mDictName).execute(new Runnable() { @Override public void run() { if (mDictionaryWriter == null) { - if (mBinaryDictionary != null) { - mBinaryDictionary.close(); - } - if (dictFile.exists() && !FileUtils.deleteRecursively(dictFile)) { - Log.e(TAG, "Can't remove a file: " + dictFile.getName()); - } - BinaryDictionary.createEmptyDictFile(dictFile.getAbsolutePath(), + removeBinaryDictionaryLocked(); + BinaryDictionary.createEmptyDictFile(mDictFile.getAbsolutePath(), DICTIONARY_FORMAT_VERSION, mLocale, getHeaderAttributeMap()); mBinaryDictionary = new BinaryDictionary( - dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), + mDictFile.getAbsolutePath(), 0 /* offset */, mDictFile.length(), true /* useFullEditDistance */, mLocale, mDictType, mIsUpdatable); } else { mDictionaryWriter.clear(); @@ -469,6 +473,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { proximityInfo, blockOffensiveWords, additionalFeaturesOptions, sessionId); holder.set(binarySuggestion); + if (mBinaryDictionary.isCorrupted()) { + removeBinaryDictionaryLocked(); + } } }); return holder.get(null, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS); diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 1e00cd825..bb54cbdb9 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -529,6 +529,14 @@ static int latinime_BinaryDictionary_setCurrentTimeForTest(JNIEnv *env, jclass c return TimeKeeper::peekCurrentTime(); } +static bool latinime_BinaryDictionary_isCorruptedNative(JNIEnv *env, jclass clazz, jlong dict) { + Dictionary *dictionary = reinterpret_cast(dict); + if (!dictionary) { + return false; + } + return dictionary->getDictionaryStructurePolicy()->isCorrupted(); +} + static const JNINativeMethod sMethods[] = { { const_cast("createEmptyDictFileNative"), @@ -642,6 +650,11 @@ static const JNINativeMethod sMethods[] = { const_cast("getPropertyNative"), const_cast("(JLjava/lang/String;)Ljava/lang/String;"), reinterpret_cast(latinime_BinaryDictionary_getProperty) + }, + { + const_cast("isCorruptedNative"), + const_cast("(J)Z"), + reinterpret_cast(latinime_BinaryDictionary_isCorruptedNative) } };