Debugging a device issue

The other day I spent the entire day trying to debug a strange issue with the Samsung Internet 4 browser. I thought I’d write a post describing some of the techniques we used to find the problem.

TL;DR

  • Make sure you can reproduce the error using a code build you control. Even if it is really hard to get this right, it’ll make the rest of your debugging infinitely easier.
  • Get someone to help you. No matter how clever you are, a second pair of eyes can always help.
  • If you can’t find someone to help, talk to a duck.
  • Promises and Polyfills are often red herrings. Try to find the problem they’re masking.

The problem I’m dealing with is this: on the Samsung Internet 4 browser, on a Samsung Galaxy S7, my site was not loading. Other Samsung phones had no problem, Chrome had no problem, but this one wouldn’t load at all.

My first task is to get some sort of debugging attached to the device. It’s an Android, so Chrome Dev Tools will attach to the device, and to the Samsung Internet browser as well as Chrome. Great. Took me about an hour to get the dev tools to actually find the device and browser, though. Everything I read up about it told me it should just work, but it doesn’t. Eventually, I used the [ADB Driver Tool] program, and everything just started to work. Yay!

Now I can see my code, and see the error in console: “Invalid Invocation”, with a location. Great. Of course, my code is all bundled and minified, so it’s very difficult to read, but I found the line throwing the error in the polyfills for the Promise library.

Just to note, the Samsung Internet 4 browser is the only browser apart from all the Internet Explorers I have found so far that does not support ES6. Just my luck.

I tracked the code up and down the call stack trying to find the root cause, but ultimately ended up going around in circles. Turns out, with the Promise polyfills, the execution that actually invokes the error is run as a different message in the event loop from the code that causes the error. I’m stumped.

Next step is to control the code. Create a build of the code that is not bundled and minified, and has sourcemaps to my original Typescript. This makes my life infinitely easier because now I can not only read the code properly, but I can make changes and rebuild – I can try things. You never know what clues you might get from this.

Turns out nothing. I got a number of clues, but they all fizzled into nothing. Stumped again. So I call on a colleague for help. Like many developers, I like to think I know everything, and can do it all myself, but I’ve learned through painful experience that I don’t, and I can’t. Also, fresh eyes on a problem see things we miss a surprising number of times.

In this case, our first clue came with a simple question: “what does the console say?”. “It just tells me the error”, I replied. “Ok,” he says, “but why isn’t it telling you anything else? You have logging set to debug level”.

Long story short, the problem ended up being in my console logging module.  I had a little method to write console logs out prettily (in nice colours and things), and I would pass that function a reference to the particular console logging function I wanted to use. Turns out, for the Samsung Internet 4 browser, you aren’t allowed to delegate any of the console logging functions.

// Code works fine on every other browser
// But not in Samsung Internet 4 browser
function log(loggingFunction, message){
  loggingFunction(message, prettyColourStyle);
}

function debug(message){
  log(console.debug, message);
}

So to sum up, it took me a whole day to debug this rather sticky little issue. It was important for me to move the code into a place I could completely control it, but the real breakthroughs came when I asked for help. Two minds are really much better than one.

And just as an aside, if you find yourself in a position where you’re stuck, and you don’t have anyone you can ask for help, try talking to a rubber duck. Well, technically, it doesn’t have to be a duck – it could be anything really. The key thing is to try to explain the situation to your chosen poultry as if you were explaining it to someone about to help you. You’d be amazed how often this cracks the case. In my team, many of us have a little rubber duck sitting on our desks, and “rubber ducking” is considered one of our most important development techniques.