Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The (not so) hidden cost of sharing code betwee...

Avatar for Eyal Guthmann Eyal Guthmann
November 26, 2019

The (not so) hidden cost of sharing code between iOS and Android

Until very recently, Dropbox had a technical strategy on mobile of sharing code between iOS and Android via C++. The idea behind this strategy was simple—write the code once in C++ instead of twice in Java and Objective C (Swift and Kotlin weren't around yet when we adopted this strategy).

We have now backed off from this strategy in favor of using each platforms’ native languages. This decision was due to the (not so) hidden cost associated with code sharing.

Come with me on a journey of how dropbox set about to share code via C++. What went well, what went wrong, what are the main lessons we learned and what this means for how we write code going forward.

Based on https://blogs.dropbox.com/tech/2019/08/the-not-so-hidden-cost-of-sharing-code-between-ios-and-android.

Avatar for Eyal Guthmann

Eyal Guthmann

November 26, 2019
Tweet

Other Decks in Technology

Transcript

  1. "main" tid=1 Blocked at MyManagerJNI.addListener (MyManagerJNI.java:384) - waiting to lock

    <0x01183147> (a com.dropbox.MyManagerJNI) held by thread 66 at MyLoader.onStartLoading (MyLoader.java:72) at android.support.v4.content.Loader.startLoading (Loader.java:283) at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onActive (LoaderManagerImpl.java:76) ANRs from C++ :-(
  2. ANRs from C++ Next step - look at thread 66

    Thread 66 where are you? (Not in the thread dump) "main" tid=1 Blocked at MyManagerJNI.addListener (MyManagerJNI.java:384) - waiting to lock <0x01183147> (a com.dropbox.MyManagerJNI) held by thread 66 at MyLoader.onStartLoading (MyLoader.java:72) at android.support.v4.content.Loader.startLoading (Loader.java:283) at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onActive (LoaderManagerImpl.java:76)
  3. Had to pull in 3 senior tech leads at various

    stages, including one of the original architects ANRs from C++
  4. Fell back to eliminating deadlocks from C++ by staring at

    the code really hard. So what was it?
  5. Best guess: A previous cleanup was blocking the app when

    it was foregrounded So what was it?
  6. Useless stack traces *** Terminating app due to uncaught exception

    'DBException', reason: 'DBException: std::length_error: vector {-[DBThreadFunc run]}’ CoreFoundation __exceptionPreprocess (__offset:228) libobjc.A.dylib objc_exception_throw (__offset:56) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox -[DBThreadFunc run] (__offset:84) Foundation __NSThread__start__ (__offset:1040) libsystem_pthread.dylib _pthread_body (__offset:272) libsystem_pthread.dylib _pthread_body (__offset:0) libsystem_pthread.dylib thread_start (__offset:4) Warning: iOS stack trace ahead!
  7. Useless iOS stack traces *** Terminating app due to uncaught

    exception 'DBException', reason: 'DBException: std::length_error: vector {-[DBThreadFunc run]}’ CoreFoundation __exceptionPreprocess (__offset:228) libobjc.A.dylib objc_exception_throw (__offset:56) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox -[DBThreadFunc run] (__offset:84) Foundation __NSThread__start__ (__offset:1040) libsystem_pthread.dylib _pthread_body (__offset:272) libsystem_pthread.dylib _pthread_body (__offset:0) libsystem_pthread.dylib thread_start (__offset:4) Useless system frames
  8. *** Terminating app due to uncaught exception 'DBException', reason: 'DBException:

    std::length_error: vector {-[DBThreadFunc run]}’ CoreFoundation __exceptionPreprocess (__offset:228) libobjc.A.dylib objc_exception_throw (__offset:56) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox -[DBThreadFunc run] (__offset:84) Foundation __NSThread__start__ (__offset:1040) libsystem_pthread.dylib _pthread_body (__offset:272) libsystem_pthread.dylib _pthread_body (__offset:0) libsystem_pthread.dylib thread_start (__offset:4) Useless Framework frames Useless iOS stack traces
  9. *** Terminating app due to uncaught exception 'DBException', reason: 'DBException:

    std::length_error: vector {-[DBThreadFunc run]}’ CoreFoundation __exceptionPreprocess (__offset:228) libobjc.A.dylib objc_exception_throw (__offset:56) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox -[DBThreadFunc run] (__offset:84) Foundation __NSThread__start__ (__offset:1040) libsystem_pthread.dylib _pthread_body (__offset:272) libsystem_pthread.dylib _pthread_body (__offset:0) libsystem_pthread.dylib thread_start (__offset:4) More useless system frames Useless iOS stack traces
  10. *** Terminating app due to uncaught exception 'DBException', reason: 'DBException:

    std::length_error: vector {-[DBThreadFunc run]}’ CoreFoundation __exceptionPreprocess (__offset:228) libobjc.A.dylib objc_exception_throw (__offset:56) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox djinni::throwNSExceptionFromCurrent(char const*) (__offset:1124) Dropbox -[DBThreadFunc run] (__offset:84) Foundation __NSThread__start__ (__offset:1040) libsystem_pthread.dylib _pthread_body (__offset:272) libsystem_pthread.dylib _pthread_body (__offset:0) libsystem_pthread.dylib thread_start (__offset:4) Only useful part Useless iOS stack traces
  11. We have to learn something about C++ to figure this

    out Caught C++ exceptions do not have a stack trace (?!?!)
  12. We have to learn something about C++ to figure this

    out Once caught, You cannot get a stack trace
  13. We have to learn something about C++ to figure this

    out To get a stack trace you must let it crash the app
  14. 1) Learn way too much about the working on C++

    exceptions How to solve this one?
  15. 2) Roll out a change to make system exception crash

    the app in C++ How to solve this one?
  16. 3) Get the real stack trace and easily fix the

    actual bug How to solve this one?
  17. Create tooling to allow the C++ code and native languages

    to communicate The technical strategy
  18. Build frameworks and libraries that the core functionality depends on

    (E.g: Feature flags) The technical strategy
  19. Frameworks and Libraries A Framework calls into your code A

    library is something your code calls into
  20. Stats 85k LoC in C++ 35K LoC in open source

    project 10K for build tools
  21. Apple and Google are diverging Different incentives for evolution No

    incentive to converge We have no control over their choices
  22. Situation 2 And even then - keep you the surface

    area of you custom solution minimal