Skip to content

Instantly share code, notes, and snippets.

@DanielJette
Created April 28, 2022 20:09
Show Gist options
  • Save DanielJette/98b8f8068b4036af5c190e28ceb50b80 to your computer and use it in GitHub Desktop.
Save DanielJette/98b8f8068b4036af5c190e28ceb50b80 to your computer and use it in GitHub Desktop.
Validate the bundle
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.shopify.foundation.extensions.parceledSize
import com.shopify.foundation.util.BuildConfig
private const val BUNDLE_SIZE_WARNING_THRESHOLD = 100000
private const val LOG_TAG = "BundleValidator"
private const val BUNDLE_TAG = "INSTANCE_ID"
private const val BUNDLE_IGNORE = "BUNDLE_IGNORE"
@VisibleForTesting
class BundleTooLargeException(bundleSize: Int) : IllegalStateException(
"""\n\n
* There is too much data being saved to the Bundle.
* As a warning to developers, we have set a limit of $BUNDLE_SIZE_WARNING_THRESHOLD bytes in the bundle.
* This Bundle is currently saving approximately $bundleSize bytes.
* The Binder transaction buffer has a limited fixed size, currently 1MB, which is shared by all transactions in progress for the process.
* State must be simple and lightweight. For complex or large data you should use local persistence.
* If you are seeing this warning, please look in to using StatePersistenceHandle instead of SaveStateHandle.
* If you are seeing this warning and the activity does not use a StatePersistenceHandle instead or SaveStateHandle, override the onSaveInstanceState method and put a boolean with the key BUNDLE_IGNORE.
""".trimIndent()
)
/**
* Validate the bundle size if the bundle does not contain the BUNDLE_TAG and the BUNDLE_IGNORE.
* The BUNDLE_TAG is automatically
* set for all the activities that have a Flow Model with a StatePersistenceHandle instead of the SaveState Handle.
* The BUNDLE_IGNORE needs to be manually set on the onSavedInstanceState for the Activity if it does not use a flow model but
* still has a large bundle size due to a result sent by an external library(Merchant Login webview login is one of these cases).
*/
fun Bundle.validateBundle() {
if (BuildConfig.DEBUG && !this.containsKey(BUNDLE_TAG) && !this.containsKey(BUNDLE_IGNORE)) {
val bundleSize = this.keySet().sumBy {
try {
(this[it] as? Parcelable)?.parceledSize ?: 0
} catch (e: RuntimeException) {
// Getting the size of the net.openid.appauth.AuthorizationManagementActivity throws
// an exception since it has binder objects. Checking the size causes it to be
// unmarshalled causing this exception.
Log.e(LOG_TAG, "Unable to check size of SavedInstanceState, could not get size of key $it", e)
0
}
}
if (bundleSize > BUNDLE_SIZE_WARNING_THRESHOLD) {
throw BundleTooLargeException(bundleSize)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment