On Android catching Java exceptions is easy via UncaughtExceptionHandler. Catching NDK crashes is a bit more convoluted. Since the native stack is probably corrupted, you want the crash handler to run on a separate process. Also, since the system might be in an unstable shape, don’t send the crash report to your web server or do anything fancy. Just write the crash report to a file, and on the next restart of the app, send to your web server and delete it from the disk. I ended up using jndcrash package for this.
After I wrote my previous post, some suggested that I can cut down the image size further by using a “scratch” image. And that’s true, “scratch i”s a reserved 0-sized image with nothing in it. And utilizing a scratch binary image did cut down the size of the final Docker image from 13MB to 7.5MB. Pretty good, right? Except the image cannot do an SSL cert verification because of the missing SSL certs!!!
Failed to reach google.com: Get https://google.com: x509: certificate signed by unknown authority
60 milliseconds is when we notice something isn’t immediate. Any user interaction, that involves sending data over the network or doing heavy computation on it, usually takes way longer than 60 milliseconds. So, we end with a progress bar. There are two broad categories of progress bars, one that shows the absolute/relative progress, a determinate progress bar, and one that does not an indeterminate progress bar.
Recently, this question came up during the discussion. “How many source-code repositories should a startup have?”
There are two extreme answers, a single monorepo for all the code or repository for each library/microservice. Uber, for example, had 8000 git repositories with only 200 engineers! I think both extremes are wrong. Too many repositories make it hard to find code and one single repository makes it harder to do simple things like testing, bisecting (to find buggy commit), deciding repository owners.
We all have to make significant code changes from time to time. Most of these code changes are large. Consider the scenario that you merged one such significant change, and then other team members made a few more changes on top. Then a major bug is detected. You desperately make the fix. It makes it in. You declare a victory, and a few hours later, your colleague notices another bug/crash/performance regression. Your commit cannot be reverted. It isn’t just about you. Many others have built on top of the change you made—the code sloths along in this broken state for a few days before you eventually fix it. Everyone has faced this issue at some point or the other.
To use monorepo or not is an eternal debate. Each has its pros and cons. Let’s say you decide to go with monorepo, one major issue you will face over time is slow testing. Imagine a monorepo, consisting of an Android app, an iOS app, some backend code, some web frontend code. In only very few occasions will someone modify more than one of those simultaneously.
In 2020, the web is still the most accessible permission-less platform. For the past few months, I have been playing and building side-projects to simplify my life. I started with a Calendar Bot for scheduling events, DeckSaver for downloading decks from Docsend, AutoSnoozer for email management, and StayInTouch for maintaining follow-ups.
When I started on this journey, I had the following in my mind.
- Cost of domain ~ 12$ a year or 1$ a month
- Cost of a VM ~ 10$ a month
A basic webserver
Docker containers are small OS images in themselves which one can deploy and run without worrying about dependencies or interoperability. All the dependencies are packed in the same container file. And the docker runtime takes care of the interoperability. You are not tied to using a single language or framework. You can write code in Python, Go, Java, Node.js, or any of your favorite languages and pack it in a container.
Consider a simple example of a Go-based webserver
A single developer has to sometimes deal with 7 different consoles by the same company…
Emulator: Process finished with exit code 1
You opened AVD Manager in Android Studio and tried to start an AVD, you got
“Emulator: Process finished with exit code 1”. Following are the steps to debug
- Find out the name of the emulator.
Click the down arrow 🔽 which is to the right of play arrow ▶️, to find out the name of the AVD. Let’s say the name is “Nexus_5X_API_28_x86”.
- Try starting the AVD directly from command-line
It fails with another cryptic error, but that’s at least more actionable
$(dirname $(which android))/emulator -avd Nexus_5X_API_28_x86 ... PANIC: Broken AVD system path. Check your ANDROID_SDK_ROOT value [/opt/android_sdk]!
Let’s retry in the verbose mode to see a detailed error
$(dirname $(which android))/emulator -avd Nexus_5X_API_28_x86 -verbose ... Not a directory: /opt/android_sdk/system-images/android-28/google_apis/x86/
So, the system image is missing.
- Install system image
# List all possible system images. $(dirname $(which android))/bin/sdkmanager --list # List the images we are interested in. $(dirname $(which android))/bin/sdkmanager --list | ack google_apis | ack android-28 | ack x86 # Install the right one using $(dirname $(which android))/bin/sdkmanager --install 'system-images;android-28;google_apis;x86'
- Now try starting the AVD again.
$(dirname $(which android))/emulator -avd Nexus_5X_API_28_x86 -verbose ... emulator:Probing program: /opt/android_sdk/tools/emulator64-x86 emulator:Probing program: /opt/android_sdk/tools/emulator-x86 PANIC: Missing emulator engine program for 'x86' CPU.
Turns out there is another version of emulator installed in $(dirname $(dirname $(which android)))/emulator/emulator. And the emulator I was using is a stray one.
# This works $(dirname $(dirname $(which android)))/emulator/emulator -avd Nexus_5X_API_28_x86 -verbose