Rollout Swift Support - Under The Hood

Written by: Eyal Keren

How CloudBees Feature Management patches live Swift apps.

A while back I published an article on how CloudBees Feature Management works under the hood which describes how CloudBees Feature Management works for objective-c apps. Now that CloudBees Feature Management also supports Swift, I wrote this article which covers the technical details of how CloudBees Feature Management patches Swift apps using Swift "pseudo method swizzling". You just finished fixing a critical  bug in your iOS app and submitted to the App Store for approval. Congrats! The problem is that can take anywhere from a couple of days to a couple of weeks before it’s approved! If this is an urgent bugfix, even a few hours can be an unbearable amount of time to wait. That’s where CloudBees Feature Management comes in. With CloudBees Feature Management’s SDK in your app, you can instantly push code level updates, such as bug fixes or diagnostic code, to native iOS apps in production. Yes really, and totally legit by Apple’s guidelines. Rather than waiting for App Store approval to push code updates, with CloudBees Feature Management can you find and fix issues in live apps in minutes. In this article, I elaborate in detail on how CloudBees Feature Management works it’s magic under the hood (techie stuff) when patching Swift apps.

The heart of CloudBees Feature Management’s Swift patching magic lies in a technique we call Pre-SIL instrumentation.

SIL stands for Swift Intermediate Language, it is generated from the Abstract Syntax Tree. This intermediate form is used by the Swift optimizer to perform Swift language specific optimizations prior to generating the LLVM IR. CloudBees Feature Management instrumentation needs to happen before the optimization phase so it will work even if the method was inlined, the dispatching was de-virtualized and more (I’ll write more about optimizations in Swift in the near future). To add this code instrumentation CloudBees Feature Management runs the following flow:

  1. Replace the swiftc compiler with a proxy script

  2. When swiftc compiles a file, intercept the file and instrument it

  3. Identify all methods in file

  4. Instrument all methods with the patching mechanism

All of the above needs to happen without a cost in compile time, runtime and most importantly maintaining a consistent debugging experience (as if CloudBees Feature Management didn’t touch your code). 1. Replace swiftc compiler with a proxy script First thing we need to do is wrap the compiling of Swift files. This is done with the SWIFT_EXEC  environment variable (see docs). If you have already installed CloudBees Feature Management with Swift support you can see this variable set in your Xcode build settings under user-defined:

The proxy compiler is a simple bash script that captures the parameters and sets up the data for Swift files interception. 2. Intercepting the Swift file Using DYLD_INSERT_LIBRARIES  we grab the call (see open) and are able to instrument the source file. 3. Identify all methods in file  Using sourceKitten

 we get the AST tree of Swift code and method decleration location. 4. Method instrumentation Given the method:

func doSomething(a:Int, b:Int) -> Int {
    // method original body
}

We add a prefix to the method, that looks more or less like this:

func add(a:Int, b:Int) -> Int {
    if Rollout_shouldPatch(ROLLOUT_a79ee6d5a41da8daaa2fef82124dcf74) {
        let resultRollout : Int = Rollout_invokeReturn(Rollout_tweakData!,target:self, arguments:
        [a,b, origClosure: { args in return self.add(a:args[0],b:args[1]);});
        return resultRollout;
    };
//
// original method body
//
}

The above is not the exact code that is added. Some optimizations and details are missing, but the general idea is the same. The ROLLOUT_a79ee6d5a41da8daaa2fef82124dcf74  variable is the unique identifier of that method, and is set by the SDK as part of the patching mechanism The Actual Patch The method CloudBees Feature Management_invokeReturn  mentioned above activates JavaScript code that can delegate back to the original method if the user wants to run the original method, as we can see in this patch code example:

NumberTileGameViewController.scoreChanged = function (
    score // SwiftBox<Int>
) {
        self.originalImplementation(42);
};

Calling the origin method of

With the number 42. CloudBees Feature Management utilizes The JavaScriptCore Framework. The Framework allows you to evaluate JavaScript programs from within an your native app It also lets you insert custom objects to the JavaScript environment. More details here. In case you’re wondering, Apple specifically allows apps to download and execute code

using Apple’s built-in WebKit framework or JavascriptCore API.

How does the App get the update?

CloudBees Feature Management’s SDK automatically checks to see if there are any updates (1) whenever the app is launched and (2) when the app enters foreground. This is done by making an asynchronous secure HTTPS request, in order not to cause any delay when the app starts. App update files are also cached. If a user does not currently have network connectivity the cached version of the update will be applied. Furthermore, all app update files are signed using public / private key encryption. The SDK checks the update file and applies the update ONLY if it is authenticated. Another decision that we make concerns how CloudBees Feature Management’s SDK is loaded. The SDK is designed to help you solve mobile app issues as they happen. When your application starts, the SDK fetches any current configurations from CloudBees Feature Management’s end point, applying them immediately once they reach a device. This is done asynchronously to avoid any possible delays that may affect user experience. Lean more about our FAQs.

Summary

This article only scratches the surface of CloudBees Feature Management’s mechanism. I decided to focus on hot patching in order to keep things simple and provide specific use cases. The ability to apply behavior on top of an application’s code provides our customers with interesting opportunities, such as ad hoc log generation (in order to track issues, even in production environments), dynamic analytics, A/B testing, remote configuration and more. CloudBees Feature Management in Action Video If you want to see a video that shows CloudBees Feature Management in action by adding logging on the fly and actually fixing a live bug in production, check this out - it should help you understand exactly what CloudBees Feature Management can do and how it works: http://support.rollout.io/docs/video-fix-a-bug-with-rolloutio

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.