[Libreoffice-commits] online.git: 2 commits - common/FileUtil.cpp common/Log.cpp common/Session.cpp common/Unit.cpp common/Unit.hpp ios/config.h ios/ios.h ios/ios.mm kit/ChildSession.cpp kit/ChildSession.hpp kit/Kit.cpp kit/Kit.hpp Mobile/Mobile Mobile/Mobile.xcodeproj net/ServerSocket.hpp net/Socket.cpp net/Socket.hpp net/WebSocketHandler.hpp wsd/ClientSession.cpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/LOOLWSD.cpp wsd/LOOLWSD.hpp wsd/Storage.cpp wsd/TileCache.cpp

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Wed Sep 19 08:32:14 UTC 2018


 Mobile/Mobile.xcodeproj/project.pbxproj |  101 ++++++++++-------
 Mobile/Mobile/AppDelegate.mm            |   32 ++++-
 Mobile/Mobile/Document.h                |    7 -
 Mobile/Mobile/Document.mm               |  109 +++++++++---------
 Mobile/Mobile/DocumentViewController.mm |   80 ++++++++++---
 common/FileUtil.cpp                     |    2 
 common/Log.cpp                          |   20 +--
 common/Session.cpp                      |    2 
 common/Unit.cpp                         |    4 
 common/Unit.hpp                         |    4 
 ios/config.h                            |    8 -
 ios/ios.h                               |    4 
 ios/ios.mm                              |    4 
 kit/ChildSession.cpp                    |    2 
 kit/ChildSession.hpp                    |    8 -
 kit/Kit.cpp                             |   37 +-----
 kit/Kit.hpp                             |   34 -----
 net/ServerSocket.hpp                    |   14 ++
 net/Socket.cpp                          |  102 +++++++++--------
 net/Socket.hpp                          |  127 +++++++++++++++------
 net/WebSocketHandler.hpp                |   32 +++++
 wsd/ClientSession.cpp                   |   10 -
 wsd/DocumentBroker.cpp                  |   24 +---
 wsd/DocumentBroker.hpp                  |   24 ----
 wsd/LOOLWSD.cpp                         |  185 ++++++++++++++++++++++++++------
 wsd/LOOLWSD.hpp                         |   14 ++
 wsd/Storage.cpp                         |   24 +++-
 wsd/TileCache.cpp                       |    2 
 28 files changed, 631 insertions(+), 385 deletions(-)

New commits:
commit 95eb84921728dec5b6f6c97e62974120b6fd1e3d
Author:     Tor Lillqvist <tml at iki.fi>
AuthorDate: Thu Sep 13 19:16:00 2018 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Wed Sep 19 11:31:18 2018 +0300

    Still more iOS app and related Online C++ code hacking
    
    Re-think the plumbing between the different parts of the C++ Online
    code. Do try to have it work more like in real Online on all but the
    lowest socket level. Except that we don't have multiple processes, but
    threads inside the same process. And instead of using actual system
    sockets for WebSocket traffic between the threads, we use our own
    FakeSocket things, with no WebSocket framing of messages.
    
    Reduce the amount of #ifdef MOBILEAPP a bit also by compiling in the
    UnitFoo things. Hardcode that so that no unit testing is ever
    attempted, though. We don't try to dlopen any library.
    
    Corresponding changes in the app Objective-C code. Plus fixes and
    functionality improvements.
    
    Now it gets so far that the JavaScript code thinks it has the document
    tiles presented, and doesn't crash. But it hangs occasionally. And all
    tiles show up blank.
    
    Anyway, progress.
    
    Change-Id: I769497c9a46ddb74984bc7af36d132b7b43895d4

diff --git a/Mobile/Mobile.xcodeproj/project.pbxproj b/Mobile/Mobile.xcodeproj/project.pbxproj
index 0d2062dff..da86e716c 100644
--- a/Mobile/Mobile.xcodeproj/project.pbxproj
+++ b/Mobile/Mobile.xcodeproj/project.pbxproj
@@ -57,6 +57,8 @@
 		BEA283582146945500848631 /* ChildSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA283572146945500848631 /* ChildSession.cpp */; };
 		BEA2835A21470A1C00848631 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEA2835921470A1C00848631 /* WebKit.framework */; };
 		BEA2835D21498AD400848631 /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2835C21498AD400848631 /* Socket.cpp */; };
+		BEA28360214ACA8500848631 /* FakeSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2835F214ACA8500848631 /* FakeSocket.cpp */; };
+		BEA28377214FFD8C00848631 /* Unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA28376214FFD8C00848631 /* Unit.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -84,6 +86,7 @@
 		BE5EB5D521401E0F00E0826C /* Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storage.cpp; sourceTree = "<group>"; };
 		BE5EB5D92140363100E0826C /* ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios.mm; path = ../../ios/ios.mm; sourceTree = "<group>"; };
 		BE5EB5DB2140480B00E0826C /* icudt62l.dat */ = {isa = PBXFileReference; lastKnownFileType = file; name = icudt62l.dat; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/icudt62l.dat"; sourceTree = "<group>"; };
+		BE636210215101D000F4237E /* WebSocketHandler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = WebSocketHandler.hpp; sourceTree = "<group>"; };
 		BE8D77272136762500AC58EA /* Mobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mobile.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		BE8D772A2136762500AC58EA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 		BE8D772B2136762500AC58EA /* AppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = "<group>"; };
@@ -116,6 +119,10 @@
 		BEA283572146945500848631 /* ChildSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChildSession.cpp; sourceTree = "<group>"; };
 		BEA2835921470A1C00848631 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
 		BEA2835C21498AD400848631 /* Socket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = ../net/Socket.cpp; sourceTree = "<group>"; };
+		BEA2835E214A8E2000848631 /* Socket.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Socket.hpp; sourceTree = "<group>"; };
+		BEA2835F214ACA8500848631 /* FakeSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FakeSocket.cpp; sourceTree = "<group>"; };
+		BEA28376214FFD8C00848631 /* Unit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Unit.cpp; sourceTree = "<group>"; };
+		BEA283782150172600848631 /* Unit.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Unit.hpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -185,6 +192,8 @@
 		BE5EB5B6213FE21000E0826C /* common */ = {
 			isa = PBXGroup;
 			children = (
+				BEA283782150172600848631 /* Unit.hpp */,
+				BEA28376214FFD8C00848631 /* Unit.cpp */,
 				BE5EB5C0213FE29900E0826C /* FileUtil.cpp */,
 				BE5EB5B9213FE29900E0826C /* Log.cpp */,
 				BE5EB5BD213FE29900E0826C /* MessageQueue.cpp */,
@@ -264,7 +273,10 @@
 		BEA2835B21498ABF00848631 /* net */ = {
 			isa = PBXGroup;
 			children = (
+				BEA2835F214ACA8500848631 /* FakeSocket.cpp */,
+				BEA2835E214A8E2000848631 /* Socket.hpp */,
 				BEA2835C21498AD400848631 /* Socket.cpp */,
+				BE636210215101D000F4237E /* WebSocketHandler.hpp */,
 			);
 			name = net;
 			path = ../net;
@@ -371,10 +383,12 @@
 				BE5EB5C1213FE29900E0826C /* Log.cpp in Sources */,
 				BE5EB5DA2140363100E0826C /* ios.mm in Sources */,
 				BE5EB5D421400DC100E0826C /* DocumentBroker.cpp in Sources */,
+				BEA28377214FFD8C00848631 /* Unit.cpp in Sources */,
 				BE5EB5CF213FE2D000E0826C /* ClientSession.cpp in Sources */,
 				BE5EB5C2213FE29900E0826C /* SpookyV2.cpp in Sources */,
 				BE8D77402136762600AC58EA /* main.m in Sources */,
 				BE5EB5C8213FE29900E0826C /* FileUtil.cpp in Sources */,
+				BEA28360214ACA8500848631 /* FakeSocket.cpp in Sources */,
 				BE8D77352136762500AC58EA /* Document.mm in Sources */,
 				BE5EB5C7213FE29900E0826C /* Protocol.cpp in Sources */,
 				BE8D772F2136762500AC58EA /* DocumentBrowserViewController.mm in Sources */,
@@ -531,6 +545,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
 				CODE_SIGN_STYLE = Automatic;
 				DEVELOPMENT_TEAM = J4FQ687VJK;
 				ENABLE_BITCODE = NO;
@@ -539,7 +554,9 @@
 					"IOS=IOS",
 					"DISABLE_DYNLOADING=1",
 					"DEBUG=1",
+					"LOOLWSD_CONFIGDIR='\".\"'",
 				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				HEADER_SEARCH_PATHS = (
 					"$(SOURCE_ROOT)/..",
 					"$(SOURCE_ROOT)/../ios",
@@ -554,6 +571,7 @@
 					"$(POCOINSTDIR)/include",
 				);
 				INFOPLIST_FILE = Mobile/Info.plist;
+				LD_GENERATE_MAP_FILE = YES;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -570,11 +588,11 @@
 					"$(PNGINSTDIR)/lib",
 					"-L",
 					"$(POCOINSTDIR)/lib",
-					"-lPocoFoundation",
-					"-lPocoUtil",
-					"-lPocoXML",
-					"-lPocoJSON",
-					"-lPocoNet",
+					"-lPocoFoundationd",
+					"-lPocoUtild",
+					"-lPocoXMLd",
+					"-lPocoJSONd",
+					"-lPocoNetd",
 				);
 				PRODUCT_BUNDLE_IDENTIFIER = com.collabora.office.Mobile;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -586,6 +604,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
 				CODE_SIGN_STYLE = Automatic;
 				DEVELOPMENT_TEAM = J4FQ687VJK;
 				ENABLE_BITCODE = NO;
@@ -594,6 +613,7 @@
 					"IOS=IOS",
 					"DISABLE_DYNLOADING=1",
 				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				HEADER_SEARCH_PATHS = (
 					"$(SOURCE_ROOT)/..",
 					"$(SOURCE_ROOT)/../ios",
@@ -608,6 +628,7 @@
 					"$(POCOINSTDIR)/include",
 				);
 				INFOPLIST_FILE = Mobile/Info.plist;
+				LD_GENERATE_MAP_FILE = YES;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
diff --git a/Mobile/Mobile/AppDelegate.mm b/Mobile/Mobile/AppDelegate.mm
index bb0fefe4e..6fbd25d75 100644
--- a/Mobile/Mobile/AppDelegate.mm
+++ b/Mobile/Mobile/AppDelegate.mm
@@ -8,14 +8,21 @@
 
 #import "config.h"
 
-//#define LOK_USE_UNSTABLE_API
-//#import <LibreOfficeKit/LibreOfficeKitInit.h>
+#import <cassert>
+#import <cstring>
 
 #import "AppDelegate.h"
 #import "DocumentBrowserViewController.h"
 #import "DocumentViewController.h"
 #import "Document.h"
 
+#import "FakeSocket.hpp"
+#import "Log.hpp"
+#import "LOOLWSD.hpp"
+#import "Util.hpp"
+
+static LOOLWSD *loolwsd = nullptr;
+
 @interface AppDelegate ()
 
 @end
@@ -25,8 +32,25 @@
 }
 
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
-//    _kit = lok_init_2(nullptr, nullptr);
-
+    Log::initialize("app", "trace", false, false, {});
+    fakeSocketSetLoggingCallback([](const std::string& line)
+                                 {
+                                     LOG_TRC_NOFILE(line);
+                                 });
+
+    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+                   ^{
+                       if (loolwsd == nullptr)
+                       {
+                           loolwsd = new LOOLWSD();
+                           Util::setThreadName("app");
+                       }
+                       char *argv[2];
+                       argv[0] = strdup([[NSBundle mainBundle].executablePath UTF8String]);
+                       argv[1] = nullptr;
+                       loolwsd->run(1, argv);
+                       assert(false && "????? LOOLWSD::main() returned?");
+                   });
     return YES;
 }
 
diff --git a/Mobile/Mobile/Document.h b/Mobile/Mobile/Document.h
index 875ec2e80..f51cb3bac 100644
--- a/Mobile/Mobile/Document.h
+++ b/Mobile/Mobile/Document.h
@@ -6,18 +6,19 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+#import <string>
+
 #import <UIKit/UIKit.h>
 
 #define LOK_USE_UNSTABLE_API
 #import <LibreOfficeKit/LibreOfficeKit.h>
 
-#import "Kit.hpp"
-
 @class DocumentViewController;
 
 @interface Document : UIDocument {
 @public
-    JS2OnlineBridge bridge;
+    std::string uri;
+    int fakeClientFd;
 }
 
 @property (strong) DocumentViewController *viewController;
diff --git a/Mobile/Mobile/Document.mm b/Mobile/Mobile/Document.mm
index 14229777d..d6f0500b5 100644
--- a/Mobile/Mobile/Document.mm
+++ b/Mobile/Mobile/Document.mm
@@ -8,65 +8,39 @@
 
 #import "config.h"
 
+#import <algorithm>
+
+#import "ios.h"
 #import "AppDelegate.h"
 #import "Document.h"
 #import "DocumentViewController.h"
 
+#import "ClientSession.hpp"
+#import "DocumentBroker.hpp"
+#import "FakeSocket.hpp"
 #import "Kit.hpp"
 #import "KitHelper.hpp"
 #import "Log.hpp"
+#import "LOOLWSD.hpp"
 #import "Protocol.hpp"
 
 @implementation Document
 
-// https://github.com/google/google-api-cpp-client/blob/master/src/googleapis/strings/memutil.cc,
-// Apache licensed
-
-static size_t memspn(const char* s, size_t slen, const char* accept) {
-  const char* p = s;
-  const char* spanp;
-  char c, sc;
-
-cont:
-  c = *p++;
-  if (slen-- == 0) return p - 1 - s;
-  for (spanp = accept; (sc = *spanp++) != '\0';)
-    if (sc == c) goto cont;
-  return p - 1 - s;
-}
-
-static const char* setupSafeNonBinaryCharSpan()
-{
-    static char result[256];
-
-    memset(result, 0, 256);
-    char *p = result;
-    for (char c = ' '; c <= '~'; c++)
-        if (c != '\'' && c != '\\')
-            *p++ = c;
-    return result;
-}
-
-static void send2JS(const char *buffer, int length, void *data)
-{
-    Document *doc = (__bridge Document*) data;
-    [doc send2JS:buffer length:length];
-}
-
 - (id)contentsForType:(NSString*)typeName error:(NSError **)errorPtr {
     // Encode your document with an instance of NSData or NSFileWrapper
     return [[NSData alloc] init];
 }
 
 - (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)errorPtr {
-    Log::initialize("", "trace", false, false, {});
+    fakeClientFd = fakeSocketSocket();
+    uri = [[[self fileURL] absoluteString] UTF8String];
 
-    bridge.registerJSSender(send2JS, (__bridge void*) self);
-
-    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
-                   ^{
-                       lokit_main(std::string([[[self fileURL] absoluteString] UTF8String]), self->bridge);
-                   });
+    NSURL *url = [[NSBundle mainBundle] URLForResource:@"loleaflet" withExtension:@"html"];
+    NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
+    components.queryItems = @[ [NSURLQueryItem queryItemWithName:@"file_path" value:[NSString stringWithUTF8String:uri.c_str()]],
+                               [NSURLQueryItem queryItemWithName:@"debug" value:@"true"]];
+    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:components.URL];
+    [self.viewController.webView loadRequest:request];
 
     return YES;
 }
@@ -74,38 +48,61 @@ static void send2JS(const char *buffer, int length, void *data)
 - (void)send2JS:(const char *)buffer length:(int)length {
     NSLog(@"send to JS: %s", LOOLProtocol::getAbbreviatedMessage(buffer, length).c_str());
 
-    static const char * const safeChar = setupSafeNonBinaryCharSpan();
-
     NSString *js;
-    // Check if the message is non-binary and doesn't contain any single quotes or backslashes either.
 
-    // Yes, this doesn't accept non-ASCII UTF-8 sequences even if they would be perfectly fine. I
-    // think we don't send any such to this, though?
+    // Check if the message is binary. We say that any message that isn't just a single line is
+    // "binary" even if that strictly speaking isn't the case; for instance the commandvalues:
+    // message has a long bunch of non-binary JSON on multiple lines. But _onMessage() in Socket.js
+    // handles it fine even if such a message, too, comes in as an ArrayBuffer. (Look for the
+    // "textMsg = String.fromCharCode.apply(null, imgBytes);".)
+
+    const char *newline = (const char *)memchr(buffer, '\n', length);
+    if (newline != nullptr) {
+        // The data needs to be an ArrayBuffer
+        js = @"window.TheFakeWebSocket.onmessage({'data': Base64ToArrayBuffer('";
+        js = [js stringByAppendingString: [[NSData dataWithBytes:buffer length:length] base64EncodedStringWithOptions:0]];
+        js = [js stringByAppendingString:@"')});"];
+        NSString *subjs = [js substringToIndex:std::min(40ul, js.length)];
+
+        // NSLog(@"Evaluating JavaScript: %@ (length %lu)", subjs, (unsigned long)js.length);
 
-    if (memspn(buffer, length, safeChar) == length) {
-        js = @"window.TheFakeWebSocket.onmessage({'data': '";
-        js = [js stringByAppendingString: [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding]];
-        js = [js stringByAppendingString:@"'});"];
         dispatch_async(dispatch_get_main_queue(), ^{
                 [self.viewController.webView evaluateJavaScript:js
                                               completionHandler:^(id _Nullable obj, NSError * _Nullable error)
                      {
                          if (error) {
-                             NSLog(@"name = %@ error = %@",@"", error.localizedDescription);
+                             NSLog(@"error after %@ (length %lu): %@", subjs, (unsigned long)js.length, error.localizedDescription);
                          }
                      }
                  ];
-            });
+        });
     } else {
-        js = @"window.TheFakeWebSocket.onmessage({'data': atob('";
-        js = [js stringByAppendingString: [[NSData dataWithBytes:buffer length:length] base64EncodedStringWithOptions:0]];
-        js = [js stringByAppendingString:@"')});"];
+        const unsigned char *ubufp = (const unsigned char *)buffer;
+        std::vector<char> data;
+        for (int i = 0; i < length; i++) {
+            if (ubufp[i] < ' ' || ubufp[i] == '\'' || ubufp[i] == '\\') {
+                data.push_back('\\');
+                data.push_back('x');
+                data.push_back("0123456789abcdef"[(ubufp[i] >> 4) & 0x0F]);
+                data.push_back("0123456789abcdef"[ubufp[i] & 0x0F]);
+            } else {
+                data.push_back(ubufp[i]);
+            }
+        }
+        data.push_back(0);
+
+        js = @"window.TheFakeWebSocket.onmessage({'data': '";
+        js = [js stringByAppendingString:[NSString stringWithUTF8String:data.data()]];
+        js = [js stringByAppendingString:@"'});"];
+
+        // NSLog(@"Evaluating JavaScript: %@", js);
+
         dispatch_async(dispatch_get_main_queue(), ^{
                 [self.viewController.webView evaluateJavaScript:js
                                               completionHandler:^(id _Nullable obj, NSError * _Nullable error)
                      {
                          if (error) {
-                             NSLog(@"name = %@ error = %@",@"", error.localizedDescription);
+                             NSLog(@"error after %@: %@: %@", js, error.localizedDescription, error.userInfo[@"WKJavaScriptExceptionMessage"]);
                          }
                      }
                  ];
diff --git a/Mobile/Mobile/DocumentViewController.mm b/Mobile/Mobile/DocumentViewController.mm
index 83b344850..c3da9f6d6 100644
--- a/Mobile/Mobile/DocumentViewController.mm
+++ b/Mobile/Mobile/DocumentViewController.mm
@@ -8,6 +8,14 @@
 
 #import "config.h"
 
+#import <string>
+#import <vector>
+
+#import <poll.h>
+
+#import "ios.h"
+#import "FakeSocket.hpp"
+
 #import "DocumentViewController.h"
 
 @interface DocumentViewController() <WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler> {
@@ -47,11 +55,6 @@
                                                                       options:0
                                                                       metrics:nil
                                                                         views:views]];
-
-    NSURL *loleafletURL = [[NSBundle mainBundle] URLForResource:@"loleaflet" withExtension:@"html"];
-    NSURLRequest * myNSURLRequest = [[NSURLRequest alloc]initWithURL:loleafletURL];
-    waitingForInitialLoad = YES;
-    [self.webView loadRequest:myNSURLRequest];
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -88,22 +91,6 @@
 
 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
     NSLog(@"didFinishNavigation: %@", navigation);
-
-    // Huh, this is horrible.
-    if (waitingForInitialLoad) {
-        waitingForInitialLoad = NO;
-        NSString *js;
-
-        js = @"window.postMessage(JSON.stringify({'MessageId': 'Host_PostmessageReady'}), '*');";
-        [webView evaluateJavaScript:js
-                  completionHandler:^(id _Nullable obj, NSError * _Nullable error)
-                 {
-                     if (error) {
-                         NSLog(@"name = %@ error = %@",@"", error.localizedDescription);
-                     }
-                 }
-         ];
-    }
 }
 
 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
@@ -151,13 +138,62 @@
 }
 
 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
+    int rc;
+    struct pollfd p;
+
     if ([message.name isEqualToString:@"error"]) {
         NSLog(@"Error from WebView: %@", message.body);
     } else if ([message.name isEqualToString:@"debug"]) {
         NSLog(@"===== %@", message.body);
     } else if ([message.name isEqualToString:@"lool"]) {
         NSLog(@"===== To Online: %@", message.body);
-        self.document->bridge.sendToOnline([[@"child-0001 " stringByAppendingString:(NSString*)message.body] UTF8String]);
+
+        if ([message.body isEqualToString:@"HULLO"]) {
+            // Now we know that the JS has started completely
+
+            // Contact the permanently (during app lifetime) listening LOOLWSD server
+            // "public" socket
+            assert(loolwsd_server_socket_fd != -1);
+            rc = fakeSocketConnect(self.document->fakeClientFd, loolwsd_server_socket_fd);
+            assert(rc != -1);
+
+            // Start another thread to read responses and forward them to the JavaScript
+            dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+                           ^{
+                               while (true) {
+                                   struct pollfd p;
+                                   p.fd = self.document->fakeClientFd;
+                                   p.events = POLLIN;
+                                   if (fakeSocketPoll(&p, 1, 0) == 1) {
+                                       int n = fakeSocketAvailableDataLength(self.document->fakeClientFd);
+                                       if (n == 0)
+                                           return;
+                                       std::vector<char> buf(n);
+                                       n = fakeSocketRead(self.document->fakeClientFd, buf.data(), n);
+                                       [self.document send2JS:buf.data() length:n];
+                                   }
+                                   else
+                                       break;
+                               }
+                               assert(false);
+                           });
+
+            // First we simply send it the URL. This corresponds to the GET request with Upgrade to
+            // WebSocket.
+            std::string url([[[self.document fileURL] absoluteString] UTF8String]);
+            p.fd = self.document->fakeClientFd;
+            p.events = POLLOUT;
+            fakeSocketPoll(&p, 1, 0);
+            fakeSocketWrite(self.document->fakeClientFd, url.c_str(), url.size());
+
+            return;
+        }
+
+        const char *buf = [message.body UTF8String];
+        p.fd = self.document->fakeClientFd;
+        p.events = POLLOUT;
+        fakeSocketPoll(&p, 1, 0);
+        fakeSocketWrite(self.document->fakeClientFd, buf, strlen(buf));
     } else {
         NSLog(@"Unrecognized kind of message received from WebView: %@: %@", message.name, message.body);
     }
diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp
index cae138ed8..0ba6256d0 100644
--- a/common/FileUtil.cpp
+++ b/common/FileUtil.cpp
@@ -190,6 +190,7 @@ namespace
 
 namespace FileUtil
 {
+#ifndef MOBILEAPP
     void registerFileSystemForDiskSpaceChecks(const std::string& path)
     {
         const std::string::size_type lastSlash = path.rfind('/');
@@ -233,6 +234,7 @@ namespace FileUtil
 
         return std::string();
     }
+#endif
 
     bool checkDiskSpace(const std::string& path)
     {
diff --git a/common/Log.cpp b/common/Log.cpp
index 38e93c2cb..a8e654d70 100644
--- a/common/Log.cpp
+++ b/common/Log.cpp
@@ -111,7 +111,10 @@ namespace Log
             osTid = Util::getThreadId();
             threadName = Util::getThreadName();
         }
-
+#elif defined IOS
+        const char *threadName = Util::getThreadName();
+        auto osTid = pthread_mach_thread_np(pthread_self());
+#endif
         Poco::DateTime time;
         snprintf(buffer, 1023, "%s-%.05lu %.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.6u [ %s ] %s  ",
                     (Source.inited ? Source.id.c_str() : "<shutdown>"),
@@ -120,16 +123,6 @@ namespace Log
                     time.hour(), time.minute(), time.second(),
                     time.millisecond() * 1000 + time.microsecond(),
                     threadName, level);
-#else
-        Poco::DateTime time;
-        const char *threadName = Util::getThreadName();
-        snprintf(buffer, 1023, "%s %.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.6u [ %s ] %s  ",
-                    (Source.inited ? Source.id.c_str() : "<shutdown>"),
-                    time.year(), time.month(), time.day(),
-                    time.hour(), time.minute(), time.second(),
-                    time.millisecond() * 1000 + time.microsecond(),
-                    threadName, level);
-#endif
         return buffer;
     }
 
@@ -148,8 +141,11 @@ namespace Log
     {
         Source.name = name;
         std::ostringstream oss;
-        oss << Source.name << '-'
+        oss << Source.name;
+#ifndef MOBILEAPP // Just one process in a mobile app, the pid is uninteresting.
+        oss << '-'
             << std::setw(5) << std::setfill('0') << Poco::Process::id();
+#endif
         Source.id = oss.str();
 
         // Configure the logger.
diff --git a/common/Session.cpp b/common/Session.cpp
index adbbbb857..4dd9d2902 100644
--- a/common/Session.cpp
+++ b/common/Session.cpp
@@ -187,7 +187,6 @@ void Session::handleMessage(bool /*fin*/, WSOpCode /*code*/, std::vector<char> &
 {
     try
     {
-#ifndef MOBILEAPP
         std::unique_ptr< std::vector<char> > replace;
         if (UnitBase::get().filterSessionInput(this, &data[0], data.size(), replace))
         {
@@ -195,7 +194,6 @@ void Session::handleMessage(bool /*fin*/, WSOpCode /*code*/, std::vector<char> &
                 _handleInput(replace->data(), replace->size());
             return;
         }
-#endif
         if (!data.empty())
             _handleInput(&data[0], data.size());
     }
diff --git a/common/Unit.cpp b/common/Unit.cpp
index 6391a5d9d..7eba4fc2a 100644
--- a/common/Unit.cpp
+++ b/common/Unit.cpp
@@ -30,6 +30,7 @@ static Poco::Thread TimeoutThread("unit timeout");
 
 UnitBase *UnitBase::linkAndCreateUnit(UnitType type, const std::string &unitLibPath)
 {
+#ifndef MOBILEAPP
     void *dlHandle = dlopen(unitLibPath.c_str(), RTLD_GLOBAL|RTLD_NOW);
     if (!dlHandle)
     {
@@ -60,6 +61,9 @@ UnitBase *UnitBase::linkAndCreateUnit(UnitType type, const std::string &unitLibP
         hooks->setHandle(dlHandle);
 
     return hooks;
+#else
+    return nullptr;
+#endif
 }
 
 bool UnitBase::init(UnitType type, const std::string &unitLibPath)
diff --git a/common/Unit.hpp b/common/Unit.hpp
index eaf393611..5844cc3bd 100644
--- a/common/Unit.hpp
+++ b/common/Unit.hpp
@@ -9,8 +9,6 @@
 #ifndef INCLUDED_UNIT_HPP
 #define INCLUDED_UNIT_HPP
 
-#ifndef MOBILEAPP
-
 #include <atomic>
 #include <cassert>
 #include <memory>
@@ -293,6 +291,4 @@ public:
 
 #endif
 
-#endif
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ios/config.h b/ios/config.h
index b9090b03e..9f4751035 100644
--- a/ios/config.h
+++ b/ios/config.h
@@ -67,7 +67,7 @@
 #define HAVE_UNISTD_H 1
 
 /* Cache folder */
-#define LOOLWSD_CACHEDIR getCacheDir()
+#define LOOLWSD_CACHEDIR lo_ios_app_getCacheDir()
 
 /* LibreOffice Online WebSocket server version */
 #define LOOLWSD_VERSION "master" // ???
@@ -76,16 +76,16 @@
 #define LOOLWSD_VERSION_HASH "xxxxxx" // ???
 
 /* Path to LibreOffice installation */
-#undef LO_PATH
+#define LO_PATH "."
 
 /* Define to the sub-directory where libtool stores uninstalled libraries. */
 #undef LT_OBJDIR
 
 /* Limit the maximum number of open connections */
-#undef MAX_CONNECTIONS
+#define MAX_CONNECTIONS 3
 
 /* Limit the maximum number of open documents */
-#undef MAX_DOCUMENTS
+#define MAX_DOCUMENTS 1
 
 /* Name of package */
 #undef PACKAGE
diff --git a/ios/ios.h b/ios/ios.h
index fb7a68dc7..2fe488c9e 100644
--- a/ios/ios.h
+++ b/ios/ios.h
@@ -7,6 +7,8 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-extern const char* getCacheDir();
+extern const char* lo_ios_app_getCacheDir();
+
+extern int loolwsd_server_socket_fd;
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ios/ios.mm b/ios/ios.mm
index e608627c6..cc0c0f902 100644
--- a/ios/ios.mm
+++ b/ios/ios.mm
@@ -14,7 +14,9 @@ extern "C" {
 #import <native-code.h>
 }
 
-const char* getCacheDir()
+int loolwsd_server_socket_fd = -1;
+
+const char* lo_ios_app_getCacheDir()
 {
     static NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
     static const char* result = strdup([cachePath UTF8String]);
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index a8380fc81..2cb733059 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -213,14 +213,12 @@ bool ChildSession::_handleInput(const char *buffer, int length)
     {
         assert(false && "Tile traffic should go through the DocumentBroker-LoKit WS.");
     }
-#ifdef MOBILEAPP
     else if (tokens[0] == "requestloksession" ||
              tokens[0] == "canceltiles")
     {
         // Just ignore these.
         // FIXME: We probably should do something for "canceltiles" at least?
     }
-#endif
     else
     {
         // All other commands are such that they always require a LibreOfficeKitDocument session,
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index 4071ee466..e426f2ede 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -158,24 +158,16 @@ public:
 
     bool sendTextFrame(const char* buffer, int length) override
     {
-#ifndef MOBILEAPP
         const auto msg = "client-" + getId() + ' ' + std::string(buffer, length);
         const std::unique_lock<std::mutex> lock = getLock();
         return _docManager.sendFrame(msg.data(), msg.size(), WSOpCode::Text);
-#else
-        return _docManager.sendFrame(buffer, length, WSOpCode::Text);
-#endif
     }
 
     bool sendBinaryFrame(const char* buffer, int length) override
     {
-#ifndef MOBILEAPP
         const auto msg = "client-" + getId() + ' ' + std::string(buffer, length);
         const std::unique_lock<std::mutex> lock = getLock();
         return _docManager.sendFrame(msg.data(), msg.size(), WSOpCode::Binary);
-#else
-        return _docManager.sendFrame(buffer, length, WSOpCode::Text);
-#endif
     }
 
     using Session::sendTextFrame;
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 1161507c2..0e96f78ac 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -78,6 +78,10 @@
 #include <wsd/LOOLWSD.hpp>
 #endif
 
+#ifdef MOBILEAPP
+#include "LOOLWSD.hpp"
+#endif
+
 #define LIB_SOFFICEAPP  "lib" "sofficeapp" ".so"
 #define LIB_MERGED      "lib" "mergedlo" ".so"
 
@@ -104,10 +108,6 @@ using namespace LOOLProtocol;
 class Document;
 static std::shared_ptr<Document> document;
 
-#ifdef MOBILEAPP
-static JS2OnlineBridge *theBridge;
-#endif
-
 #if ENABLE_DEBUG
 #  define ADD_DEBUG_RENDERID(s) ((s)+ " renderid=" + Util::UniqueId())
 #else
@@ -1145,17 +1145,11 @@ public:
 
     bool sendTextFrame(const std::string& message)
     {
-#ifndef MOBILEAPP
         return sendFrame(message.data(), message.size());
-#else
-        theBridge->sendToJS(message.data(), message.size());
-        return true;
-#endif
     }
 
     bool sendFrame(const char* buffer, int length, WSOpCode opCode = WSOpCode::Text) override
     {
-#ifndef MOBILEAPP
         try
         {
             std::shared_ptr<std::vector<char>> message = std::make_shared<std::vector<char>>();
@@ -1170,10 +1164,6 @@ public:
                     (exc.nested() ? "( " + exc.nested()->displayText() + ")" : ""));
         }
         return false;
-#else
-        theBridge->sendToJS(buffer, length);
-        return true;
-#endif
     }
 
     static void GlobalCallback(const int type, const char* p, void* data)
@@ -2152,7 +2142,7 @@ void lokit_main(
                 bool displayVersion
 #else
                 const std::string& documentUri,
-                JS2OnlineBridge& bridge
+                int docBrokerSocket
 #endif
                 )
 {
@@ -2409,6 +2399,8 @@ void lokit_main(
             std::_Exit(Application::EXIT_SOFTWARE);
         }
 
+        LOOLWSD::LOKitVersion = loKit->getVersionInfo();
+
         // Dummies
         Poco::URI uri;
         const std::string jailId;
@@ -2418,19 +2410,12 @@ void lokit_main(
 
         SocketPoll mainKit("kit");
 
-#ifdef MOBILEAPP
-        // Ugly, but not ay uglier than the singleton 'document' variable.
-        theBridge = &bridge;
-        theBridge->registerSocket(mainKit);
-        std::thread([&] {
-                theBridge->sendToOnline("session 0001 foo 0001");
-                // No jailing in the mobile app, just use the same URI for the "jail" parameter to
-                // the "load" command, too.
-                theBridge->sendToOnline("child-0001 load url=" + documentUri + " jail=" + documentUri);
-            }).detach();
+#ifndef MOBILEAPP
+        mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
+#else
+        mainKit.insertNewWebSocketSync(docBrokerSocket, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
 #endif
 
-        mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
         LOG_INF("New kit client websocket inserted.");
 
         while (!TerminationFlag)
diff --git a/kit/Kit.hpp b/kit/Kit.hpp
index 19543e733..3056ffc6a 100644
--- a/kit/Kit.hpp
+++ b/kit/Kit.hpp
@@ -16,38 +16,10 @@
 
 #ifdef MOBILEAPP
 
+#include "ClientSession.hpp"
+#include "DocumentBroker.hpp"
 #include "Socket.hpp"
 
-class JS2OnlineBridge
-{
-public:
-    void registerSocket(SocketPoll& socketPoll)
-    {
-        _SocketPoll = &socketPoll;
-    }
-
-    void registerJSSender(void (*function)(const char *, int, void *), void *data)
-    {
-        _JSCallbackFunction = function;
-        _JSCallbackData = data;
-    }
-
-    void sendToOnline(const std::string& payload)
-    {
-        _SocketPoll->feed(payload);
-    }
-
-    void sendToJS(const char *data, int length)
-    {
-        _JSCallbackFunction(data, length, _JSCallbackData);
-    }
-
-private:
-    SocketPoll *_SocketPoll;
-    void (*_JSCallbackFunction)(const char *, int, void *);
-    void *_JSCallbackData;
-};
-
 #endif
 
 void lokit_main(
@@ -63,7 +35,7 @@ void lokit_main(
                 bool displayVersion
 #else
                 const std::string& documentUri,
-                JS2OnlineBridge& bridge
+                int docBrokerSocket
 #endif
                 );
 
diff --git a/net/ServerSocket.hpp b/net/ServerSocket.hpp
index f0ad38ad3..314b56f2d 100644
--- a/net/ServerSocket.hpp
+++ b/net/ServerSocket.hpp
@@ -47,8 +47,11 @@ public:
     /// Returns true on success only.
     bool listen(const int backlog = 64)
     {
+#ifndef MOBILEAPP
         const int rc = ::listen(getFD(), backlog);
-
+#else
+        const int rc = fakeSocketListen(getFD());
+#endif
         if (rc)
             LOG_SYS("Failed to listen");
         return rc == 0;
@@ -61,15 +64,20 @@ public:
     {
         // Accept a connection (if any) and set it to non-blocking.
         // There still need the client's address to filter request from POST(call from REST) here.
+#ifndef MOBILEAPP
         struct sockaddr_in6 clientInfo;
         socklen_t addrlen = sizeof(clientInfo);
         const int rc = ::accept4(getFD(), (struct sockaddr *)&clientInfo, &addrlen, SOCK_NONBLOCK);
+#else
+        const int rc = fakeSocketAccept4(getFD(), SOCK_NONBLOCK);
+#endif
         LOG_DBG("Accepted socket #" << rc << ", creating socket object.");
         try
         {
             // Create a socket object using the factory.
             if (rc != -1)
             {
+#ifndef MOBILEAPP
                 char addrstr[INET6_ADDRSTRLEN];
 
                 const void *inAddr;
@@ -89,6 +97,10 @@ public:
                 _socket->_clientAddress = addrstr;
                 LOG_DBG("Accepted socket has family " << clientInfo.sin6_family <<
                         " address " << _socket->_clientAddress);
+#else
+                std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
+                _socket->_clientAddress = "dummy";
+#endif
                 return _socket;
             }
             return std::shared_ptr<Socket>(nullptr);
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 5c133b33a..91006f069 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -24,8 +24,8 @@
 
 #include <SigUtil.hpp>
 #include "Socket.hpp"
-#ifndef MOBILEAPP
 #include "ServerSocket.hpp"
+#ifndef MOBILEAPP
 #include "SslSocket.hpp"
 #endif
 #include "WebSocketHandler.hpp"
@@ -34,12 +34,14 @@ int SocketPoll::DefaultPollTimeoutMs = 5000;
 std::atomic<bool> SocketPoll::InhibitThreadChecks(false);
 std::atomic<bool> Socket::InhibitThreadChecks(false);
 
-#ifndef MOBILEAPP
-
 int Socket::createSocket(Socket::Type type)
 {
+#ifndef MOBILEAPP
     int domain = type == Type::IPv4 ? AF_INET : AF_INET6;
     return socket(domain, SOCK_STREAM | SOCK_NONBLOCK, 0);
+#else
+    return fakeSocketSocket();
+#endif
 }
 
 // help with initialization order
@@ -56,8 +58,6 @@ namespace {
     }
 }
 
-#endif
-
 SocketPoll::SocketPoll(const std::string& threadName)
     : _name(threadName),
       _stop(false),
@@ -65,23 +65,24 @@ SocketPoll::SocketPoll(const std::string& threadName)
       _threadFinished(false),
       _owner(std::this_thread::get_id())
 {
-#ifndef MOBILEAPP
     // Create the wakeup fd.
-    if (::pipe2(_wakeup, O_CLOEXEC | O_NONBLOCK) == -1)
+    if (
+#ifndef MOBILEAPP
+        ::pipe2(_wakeup, O_CLOEXEC | O_NONBLOCK) == -1
+#else
+        fakeSocketPipe2(_wakeup) == -1
+#endif
+        )
     {
         throw std::runtime_error("Failed to allocate pipe for SocketPoll [" + threadName + "] waking.");
     }
 
     std::lock_guard<std::mutex> lock(getPollWakeupsMutex());
     getWakeupsArray().push_back(_wakeup[1]);
-#else
-    _bufferEmpty = true;
-#endif
 }
 
 SocketPoll::~SocketPoll()
 {
-#ifndef MOBILEAPP
     joinThread();
 
     {
@@ -94,11 +95,15 @@ SocketPoll::~SocketPoll()
             getWakeupsArray().erase(it);
     }
 
+#ifndef MOBILEAPP
     ::close(_wakeup[0]);
     ::close(_wakeup[1]);
+#else
+    fakeSocketClose(_wakeup[0]);
+    fakeSocketClose(_wakeup[1]);
+#endif
     _wakeup[0] = -1;
     _wakeup[1] = -1;
-#endif
 }
 
 void SocketPoll::startThread()
@@ -118,8 +123,6 @@ void SocketPoll::startThread()
     }
 }
 
-#ifndef MOBILEAPP
-
 void SocketPoll::joinThread()
 {
     addCallback([this](){ removeSockets(); });
@@ -136,23 +139,6 @@ void SocketPoll::joinThread()
     }
 }
 
-#endif
-
-#ifdef MOBILEAPP
-
-void SocketPoll::feed(const std::string& payload)
-{
-    std::unique_lock<std::mutex> lock(_bufferMutex);
-    if (!_bufferEmpty)
-        _bufferCV.wait(lock, [&]{return _bufferEmpty;});
-    _buffer = payload;
-    _bufferEmpty = false;
-    lock.unlock();
-    _bufferCV.notify_one();
-}
-
-#endif
-
 void SocketPoll::pollingThreadEntry()
 {
     try
@@ -181,13 +167,17 @@ void SocketPoll::pollingThreadEntry()
 
 void SocketPoll::wakeupWorld()
 {
-#ifndef MOBILEAPP
     for (const auto& fd : getWakeupsArray())
         wakeup(fd);
-#endif
 }
 
-void SocketPoll::insertNewWebSocketSync(const Poco::URI &uri, const std::shared_ptr<SocketHandlerInterface>& websocketHandler)
+void SocketPoll::insertNewWebSocketSync(
+#ifndef MOBILEAPP
+                                        const Poco::URI &uri,
+#else
+                                        int peerSocket,
+#endif
+                                        const std::shared_ptr<SocketHandlerInterface>& websocketHandler)
 {
 #ifndef MOBILEAPP
     LOG_INF("Connecting to " << uri.getHost() << " : " << uri.getPort() << " : " << uri.getPath());
@@ -275,12 +265,33 @@ void SocketPoll::insertNewWebSocketSync(const Poco::URI &uri, const std::shared_
     else
         LOG_ERR("Failed to lookup client websocket host '" << uri.getHost() << "' skipping");
 #else
-    _socketHandler = websocketHandler;
+    LOG_INF("Connecting to " << peerSocket);
+    int fd = fakeSocketSocket();
+    int res = fakeSocketConnect(fd, peerSocket);
+    if (fd < 0 || (res < 0 && errno != EINPROGRESS))
+    {
+        LOG_ERR("Failed to connect to the 'wsd' socket");
+        fakeSocketClose(fd);
+    }
+    else
+    {
+        std::shared_ptr<StreamSocket> socket;
+        socket = StreamSocket::create<StreamSocket>(fd, true, websocketHandler);
+        if (socket)
+        {
+            LOG_TRC("Sending 'hello' instead of HTTP GET for now");
+            socket->send("hello");
+            insertNewSocket(socket);
+        }
+        else
+        {
+            LOG_ERR("Failed to allocate socket for client websocket");
+            fakeSocketClose(fd);
+        }
+    }
 #endif
 }
 
-#ifndef MOBILEAPP
-
 void ServerSocket::dumpState(std::ostream& os)
 {
     os << "\t" << getFD() << "\t<accept>\n";
@@ -293,14 +304,12 @@ void SocketDisposition::execute()
     if (_socketMove)
     {
         // Drop pretentions of ownership before _socketMove.
-        _socket->setThreadOwner(std::thread::id(0));
+        _socket->setThreadOwner(std::thread::id());
         _socketMove(_socket);
     }
     _socketMove = nullptr;
 }
 
-#endif
-
 const int WebSocketHandler::InitialPingDelayMs = 25;
 const int WebSocketHandler::PingFrequencyMs = 18 * 1000;
 
@@ -340,7 +349,6 @@ void StreamSocket::send(Poco::Net::HTTPResponse& response)
 
 void SocketPoll::dumpState(std::ostream& os)
 {
-#ifndef MOBILEAPP
     // FIXME: NOT thread-safe! _pollSockets is modified from the polling thread!
     os << " Poll [" << _pollSockets.size() << "] - wakeup r: "
        << _wakeup[0] << " w: " << _wakeup[1] << "\n";
@@ -349,14 +357,12 @@ void SocketPoll::dumpState(std::ostream& os)
     os << "\tfd\tevents\trsize\twsize\n";
     for (auto &i : _pollSockets)
         i->dumpState(os);
-#endif
 }
 
-#ifndef MOBILEAPP
-
 /// Returns true on success only.
 bool ServerSocket::bind(Type type, int port)
 {
+#ifndef MOBILEAPP
     // Enable address reuse to avoid stalling after
     // recycling, when previous socket is TIME_WAIT.
     //TODO: Might be worth refactoring out.
@@ -401,9 +407,12 @@ bool ServerSocket::bind(Type type, int port)
         LOG_SYS("Failed to bind to: " << (_type == Socket::Type::IPv4 ? "IPv4" : "IPv6") << " port: " << port);
 
     return rc == 0;
+#else
+    return true;
+#endif
 }
 
-#endif
+#ifndef MOBILEAPP
 
 bool StreamSocket::parseHeader(const char *clientName,
                                Poco::MemoryInputStream &message,
@@ -477,7 +486,6 @@ bool StreamSocket::parseHeader(const char *clientName,
     return true;
 }
 
-
 namespace HttpHelper
 {
     void sendUncompressedFileContent(const std::shared_ptr<StreamSocket>& socket,
@@ -585,4 +593,6 @@ namespace HttpHelper
     }
 }
 
+#endif // !MOBILEAPP
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 3a081d526..7bb442b41 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -22,6 +22,7 @@
 #include <cassert>
 #include <cerrno>
 #include <chrono>
+#include <climits>
 #include <cstdlib>
 #include <cstring>
 #include <fstream>
@@ -33,8 +34,10 @@
 #include <thread>
 
 #include "Common.hpp"
+#include "FakeSocket.hpp"
 #include "Log.hpp"
 #include "Util.hpp"
+#include "Protocol.hpp"
 #include "SigUtil.hpp"
 
 namespace Poco
@@ -114,7 +117,11 @@ public:
         LOG_TRC("#" << getFD() << " Socket dtor.");
 
         // Doesn't block on sockets; no error handling needed.
-        close(_fd);
+#ifndef MOBILEAPP
+        ::close(_fd);
+#else
+        fakeSocketClose(_fd);
+#endif
     }
 
     /// Create socket of the given type.
@@ -128,7 +135,11 @@ public:
     virtual void shutdown()
     {
         LOG_TRC("#" << _fd << ": socket shutdown RDWR.");
+#ifndef MOBILEAPP
         ::shutdown(_fd, SHUT_RDWR);
+#else
+        fakeSocketShutdown(_fd);
+#endif
     }
 
     /// Prepare our poll record; adjust @timeoutMaxMs downwards
@@ -145,11 +156,14 @@ public:
     /// manage latency issues around packet aggregation
     void setNoDelay()
     {
+#ifndef MOBILEAPP
         const int val = 1;
         ::setsockopt(_fd, IPPROTO_TCP, TCP_NODELAY,
                      (char *) &val, sizeof(val));
+#endif
     }
 
+#ifndef MOBILEAPP
     /// Sets the kernel socket send buffer in size bytes.
     /// Note: TCP will allocate twice this size for admin purposes,
     /// so a subsequent call to getSendBufferSize will return
@@ -190,13 +204,19 @@ public:
         const int rc = ::getsockopt(_fd, SOL_SOCKET, SO_SNDBUF, &size, &len);
         return rc == 0 ? size : -1;
     }
+#endif
 
     /// Gets our fast cache of the socket buffer size
     int getSendBufferSize() const
     {
+#ifndef MOBILEAPP
         return _sendBufferSize;
+#else
+        return INT_MAX; // We want to always send a single record in one go
+#endif
     }
 
+#ifndef MOBILEAPP
     /// Sets the receive buffer size in bytes.
     /// Note: TCP will allocate twice this size for admin purposes,
     /// so a subsequent call to getReceieveBufferSize will return
@@ -237,6 +257,7 @@ public:
 
         return rc;
     }
+#endif
 
     virtual void dumpState(std::ostream&) {}
 
@@ -288,6 +309,7 @@ protected:
         _owner = std::this_thread::get_id();
         LOG_DBG("#" << _fd << " Thread affinity set to " << Log::to_string(_owner) << ".");
 
+#ifndef MOBILEAPP
 #if ENABLE_DEBUG
         if (std::getenv("LOOL_ZERO_BUFFER_SIZE"))
         {
@@ -297,6 +319,7 @@ protected:
                     " (was " << oldSize << ")");
         }
 #endif
+#endif
     }
 
 private:
@@ -428,7 +451,6 @@ public:
     /// Poll the sockets for available data to read or buffer to write.
     void poll(int timeoutMaxMs)
     {
-#ifndef MOBILEAPP
         assertCorrectThread();
 
         std::chrono::steady_clock::time_point now =
@@ -441,7 +463,12 @@ public:
         int rc;
         do
         {
+#ifndef MOBILEAPP
             rc = ::poll(&_pollFds[0], size + 1, std::max(timeoutMaxMs,0));
+#else
+            LOG_TRC("SocketPoll Poll");
+            rc = fakeSocketPoll(&_pollFds[0], size + 1, std::max(timeoutMaxMs,0));
+#endif
         }
         while (rc < 0 && errno == EINTR);
         LOG_TRC("Poll completed with " << rc << " live polls max (" <<
@@ -455,8 +482,12 @@ public:
                 std::lock_guard<std::mutex> lock(_mutex);
 
                 // Clear the data.
+#ifndef MOBILEAPP
                 int dump = ::read(_wakeup[0], &dump, sizeof(dump));
-
+#else
+                LOG_TRC("Wakeup pipe read");
+                int dump = fakeSocketRead(_wakeup[0], &dump, sizeof(dump));
+#endif
                 // Copy the new sockets over and clear.
                 _pollSockets.insert(_pollSockets.end(),
                                     _newSockets.begin(), _newSockets.end());
@@ -527,42 +558,48 @@ public:
 
             disposition.execute();
         }
-#else
-        std::unique_lock<std::mutex> lock(_bufferMutex);
-        if (_bufferEmpty)
-            _bufferCV.wait(lock, [&]{return !_bufferEmpty;});
-        _socketHandler->handleMessage(_buffer);
-        _bufferEmpty = true;
-        lock.unlock();
-        _bufferCV.notify_one();
-#endif
     }
 
-#ifndef MOBILEAPP
     /// Write to a wakeup descriptor
     static void wakeup (int fd)
     {
         // wakeup the main-loop.
         int rc;
         do {
+#ifndef MOBILEAPP
             rc = ::write(fd, "w", 1);
+#else
+#if 0
+            // Our fake sockets are record-oriented with a single record buffer, so as we write one
+            // byte at a time to the wakeup pipe, we can't write another one before the previous one
+            // has been read.
+            //
+            // FIXME: Still, explicitly waiting here with fakeSocketPoll() for it to be writable
+            // doesn't seem to be any improvement. On the contrary, with this fakeSocketPoll(), we
+            // hang every time we run the app. Without it, we only hang occasionally.
+
+            LOG_TRC("Wakeup pipe write");
+            struct pollfd p;
+            p.fd = fd;
+            p.events = POLLOUT;
+            fakeSocketPoll(&p, 1, 0);
+#endif
+            rc = fakeSocketWrite(fd, "w", 1);
+#endif
         } while (rc == -1 && errno == EINTR);
 
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
             LOG_SYS("wakeup socket #" << fd << " is closed at wakeup?");
     }
-#endif
 
     /// Wakeup the main polling loop in another thread
     void wakeup()
     {
-#ifndef MOBILEAPP
         if (!isAlive())
             LOG_WRN("Waking up dead poll thread [" << _name << "], started: " <<
                     _threadStarted << ", finished: " << _threadFinished);
 
         wakeup(_wakeup[1]);
-#endif
     }
 
     /// Global wakeup - signal safe: wakeup all socket polls.
@@ -585,7 +622,13 @@ public:
 
     /// Inserts a new websocket to be polled.
     /// NOTE: The DNS lookup is synchronous.
-    void insertNewWebSocketSync(const Poco::URI &uri, const std::shared_ptr<SocketHandlerInterface>& websocketHandler);
+    void insertNewWebSocketSync(
+#ifndef MOBILEAPP
+                                const Poco::URI &uri,
+#else
+                                int peerSocket,
+#endif
+                                const std::shared_ptr<SocketHandlerInterface>& websocketHandler);
 
     typedef std::function<void()> CallbackFn;
 
@@ -629,15 +672,7 @@ public:
     /// Stop and join the polling thread before returning (if active)
     void joinThread();
 
-#ifdef MOBILEAPP
-    // In the mobile app(s), a SocketPoll doesn't actually "poll" any "sockets" but simply acts as a
-    // conduit for sending messages that correspond to what we would receive as WebSocket messages
-    // in the server online from the app code into the shared online code.
-    void feed(const std::string& payload);
-#endif
-
 private:
-#ifndef MOBILEAPP
     /// Initialize the poll fds array with the right events
     void setupPollFds(std::chrono::steady_clock::time_point now,
                       int &timeoutMaxMs)
@@ -667,7 +702,6 @@ private:
         _pollFds[size].events = POLLIN;
         _pollFds[size].revents = 0;
     }
-#endif
 
     /// The polling thread entry.
     /// Used to set the thread name and mark the thread as stopped when done.
@@ -677,10 +711,8 @@ private:
     /// Debug name used for logging.
     const std::string _name;
 
-#ifndef MOBILEAPP
     /// main-loop wakeup pipe
     int _wakeup[2];
-#endif
     /// The sockets we're controlling
     std::vector<std::shared_ptr<Socket>> _pollSockets;
     /// Protects _newSockets
@@ -698,14 +730,6 @@ protected:
     std::atomic<bool> _threadStarted;
     std::atomic<bool> _threadFinished;
     std::thread::id _owner;
-
-#ifdef MOBILEAPP
-    std::mutex _bufferMutex;
-    std::condition_variable _bufferCV;
-    bool _bufferEmpty;
-    std::string _buffer;
-    std::shared_ptr<SocketHandlerInterface> _socketHandler;
-#endif
 };
 
 /// A plain, non-blocking, data streaming socket.
@@ -803,6 +827,7 @@ public:
     {
         assertCorrectThread();
 
+#ifndef MOBILEAPP
         // SSL decodes blocks of 16Kb, so for efficiency we use the same.
         char buf[16 * 1024];
         ssize_t len;
@@ -825,6 +850,22 @@ public:
             // else poll will handle errors.
         }
         while (len == (sizeof(buf)));
+#else
+        LOG_TRC("readIncomingData #" << getFD());
+        ssize_t available = fakeSocketAvailableDataLength(getFD());
+        ssize_t len;
+        if (available == -1)
+            len = -1;
+        else
+        {
+            std::vector<char>buf(available);
+            len = readData(buf.data(), available);
+            assert(len == available);
+            _bytesRecvd += len;
+            assert(_inBuffer.size() == 0);
+            _inBuffer.insert(_inBuffer.end(), buf.data(), buf.data() + len);
+        }
+#endif
 
         return len != 0; // zero is eof / clean socket close.
     }
@@ -899,7 +940,7 @@ protected:
         if (log.trace()) {
             LOG_TRC("#" << getFD() << ": Incoming data buffer " << _inBuffer.size() <<
                     " bytes, closeSocket? " << closed);
-            // log.dump("", &_inBuffer[0], _inBuffer.size());
+            log.dump("", &_inBuffer[0], _inBuffer.size());
         }
 
         // If we have data, allow the app to consume.
@@ -991,14 +1032,26 @@ protected:
     virtual int readData(char* buf, int len)
     {
         assertCorrectThread();
+#ifndef MOBILEAPP
         return ::read(getFD(), buf, len);
+#else
+        return fakeSocketRead(getFD(), buf, len);
+#endif
     }
 
     /// Override to handle writing data to socket differently.
     virtual int writeData(const char* buf, const int len)
     {
         assertCorrectThread();
+#ifndef MOBILEAPP
         return ::write(getFD(), buf, len);
+#else
+        struct pollfd p;
+        p.fd = getFD();
+        p.events = POLLOUT;
+        fakeSocketPoll(&p, 1, 0);
+        return fakeSocketWrite(getFD(), buf, len);
+#endif
     }
 
     void dumpState(std::ostream& os) override;
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index 104c9b879..f9abbae42 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -112,6 +112,7 @@ public:
                 static_cast<unsigned>(statusCode) << ", message: " << statusMessage);
         _shuttingDown = true;
 
+#ifndef MOBILEAPP
         const size_t len = statusMessage.size();
         std::vector<char> buf(2 + len);
         buf[0] = ((((int)statusCode) >> 8) & 0xff);
@@ -121,6 +122,7 @@ public:
                                   | static_cast<char>(WSOpCode::Close);
 
         sendFrame(socket, buf.data(), buf.size(), flags);
+#endif
     }
 
     bool handleOneIncomingMessage(const std::shared_ptr<StreamSocket>& socket)
@@ -306,13 +308,24 @@ public:
     /// Implementation of the SocketHandlerInterface.
     virtual void handleIncomingMessage(SocketDisposition&) override
     {
+        // LOG_TRC("***** WebSocketHandler::handleIncomingMessage()");
+
         std::shared_ptr<StreamSocket> socket = _socket.lock();
+
+#ifdef MOBILEAPP
+        // No separate "upgrade" is going on
+        if (socket != nullptr && !socket->isWebSocket())
+            socket->setWebSocket();
+#endif
+
         if (socket == nullptr)
         {
             LOG_ERR("No socket associated with WebSocketHandler " << this);
         }
+#ifndef MOBILEAPP
         else if (_isClient && !socket->isWebSocket())
             handleClientUpgrade();
+#endif
         else
         {
             while (handleOneIncomingMessage(socket))
@@ -332,6 +345,7 @@ public:
         return POLLIN;
     }
 
+#ifndef MOBILEAPP
     /// Send a ping message
     void sendPingOrPong(std::chrono::steady_clock::time_point now,
                         const char* data, const size_t len,
@@ -369,10 +383,12 @@ public:
         assert(_isClient);
         sendPingOrPong(now, data, len, WSOpCode::Pong, socket);
     }
+#endif
 
     /// Do we need to handle a timeout ?
     void checkTimeout(std::chrono::steady_clock::time_point now) override
     {
+#ifndef MOBILEAPP
         if (_isClient)
             return;
 
@@ -384,6 +400,7 @@ public:
             if (socket)
                 sendPing(now, socket);
         }
+#endif
     }
 
     /// By default rely on the socket buffer.
@@ -400,11 +417,9 @@ public:
     /// 0 for closed/invalid socket, and -1 for other errors.
     int sendMessage(const char* data, const size_t len, const WSOpCode code, const bool flush = true) const
     {
-#ifndef MOBILEAPP
         int unitReturn = -1;
         if (UnitBase::get().filterSendMessage(data, len, code, flush, unitReturn))
             return unitReturn;
-#endif
 
         //TODO: Support fragmented messages.
 
@@ -431,6 +446,8 @@ private:
         std::vector<char>& out = socket->_outBuffer;
         const size_t oldSize = out.size();
 
+#ifndef MOBILEAPP
+
         out.push_back(flags);
 
         int maskFlag = _isMasking ? 0x80 : 0;
@@ -479,7 +496,14 @@ private:
             out.insert(out.end(), data, data + len);
         }
         const size_t size = out.size() - oldSize;
+#else
+        LOG_TRC("WebSocketHandle::sendFrame: Writing to #" << socket->getFD() << " " << len << " bytes");
+        assert(flush);
+        assert(out.size() == 0);
 
+        out.insert(out.end(), data, data + len);
+        const size_t size = out.size();
+#endif
         if (flush)
             socket->writeOutgoingData();
 
@@ -517,6 +541,7 @@ protected:
         LOG_TRC("#" << socket->getFD() << ": Upgrading to WebSocket.");
         assert(!socket->isWebSocket());
 
+#ifndef MOBILEAPP
         // create our websocket goodness ...
         const int wsVersion = std::stoi(req.get("Sec-WebSocket-Version", "13"));
         const std::string wsKey = req.get("Sec-WebSocket-Key", "");
@@ -540,9 +565,11 @@ protected:
         const std::string res = oss.str();
         LOG_TRC("#" << socket->getFD() << ": Sending WS Upgrade response: " << res);
         socket->send(res);
+#endif
         setWebSocket();
     }
 
+#ifndef MOBILEAPP
     // Handle incoming upgrade to full socket as client WS.
     void handleClientUpgrade()
     {
@@ -607,6 +634,7 @@ protected:
         setWebSocket();
         socket->eraseFirstInputBytes(responseSize);
     }
+#endif
 
     void setWebSocket()
     {
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index c5b7bc1ac..ad623b25d 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -66,11 +66,11 @@ ClientSession::~ClientSession()
 
 void ClientSession::handleIncomingMessage(SocketDisposition &disposition)
 {
-#ifndef MOBILEAPP
+    // LOG_TRC("***** ClientSession::handleIncomingMessage()");
     if (UnitWSD::get().filterHandleRequest(
             UnitWSD::TestRequest::Client, disposition, *this))
         return;
-#endif
+
     Session::handleIncomingMessage(disposition);
 }
 
@@ -95,7 +95,6 @@ bool ClientSession::_handleInput(const char *buffer, int length)
         updateLastActivityTime();
         docBroker->updateLastActivityTime();
     }
-#ifndef MOBILEAPP
     if (tokens[0] == "loolclient")
     {
         if (tokens.size() < 1)
@@ -125,8 +124,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
 
         return true;
     }
-#endif
-    if (tokens[0] == "load")
+    else if (tokens[0] == "load")
     {
         if (_docURL != "")
         {
@@ -761,6 +759,7 @@ bool ClientSession::handleKitToClientMessage(const char* buffer, const int lengt
                 return false;
          }
     }
+#ifndef MOBILEAPP
     else if (tokens.size() == 3 && tokens[0] == "saveas:")
     {
         bool isConvertTo = static_cast<bool>(_saveAsSocket);
@@ -857,6 +856,7 @@ bool ClientSession::handleKitToClientMessage(const char* buffer, const int lengt
 
         return true;
     }
+#endif
     else if (tokens.size() == 2 && tokens[0] == "statechanged:")
     {
         StringTokenizer stateTokens(tokens[1], "=", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index b29616ec6..79d410407 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -194,9 +194,8 @@ void DocumentBroker::pollThread()
 
     _threadStart = std::chrono::steady_clock::now();
 
-#ifndef MOBILEAPP
-
     // Request a kit process for this doc.
+#ifndef MOBILEAPP
     do
     {
         static const int timeoutMs = COMMAND_TIMEOUT_MS * 5;
@@ -205,11 +204,13 @@ void DocumentBroker::pollThread()
             std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() -
                                                                   _threadStart).count() > timeoutMs)
             break;
-
         // Nominal time between retries, lest we busy-loop. getNewChild could also wait, so don't double that here.
         std::this_thread::sleep_for(std::chrono::milliseconds(CHILD_REBALANCE_INTERVAL_MS / 10));
     }
     while (!_stop && _poll->continuePolling() && !TerminationFlag && !ShutdownRequestFlag);
+#else
+    _childProcess = getNewChild_Blocks(getPublicUri().getPath());
+#endif
 
     if (!_childProcess)
     {
@@ -236,7 +237,6 @@ void DocumentBroker::pollThread()
         LOG_INF("Finished docBroker polling thread for docKey [" << _docKey << "].");
         return;
     }
-#endif
 
     _childProcess->setDocumentBroker(shared_from_this());
     LOG_INF("Doc [" << _docKey << "] attached to child [" << _childProcess->getPid() << "].");
@@ -258,9 +258,9 @@ void DocumentBroker::pollThread()
     {
         const auto now = std::chrono::steady_clock::now();
 
-#ifndef MOBILEAPP
         _poll->poll(SocketPoll::DefaultPollTimeoutMs);
 
+#ifndef MOBILEAPP
         if (std::chrono::duration_cast<std::chrono::milliseconds>
                     (now - lastBWUpdateTime).count() >= 5 * 1000)
         {
@@ -391,10 +391,8 @@ DocumentBroker::~DocumentBroker()
     LOG_INF("~DocumentBroker [" << _docKey <<
             "] destroyed with " << _sessions.size() << " sessions left.");
 
-#ifndef MOBILEAPP
     // Do this early - to avoid operating on _childProcess from two threads.
     _poll->joinThread();
-#endif
 
     if (!_sessions.empty())
     {
@@ -408,9 +406,7 @@ DocumentBroker::~DocumentBroker()
 
 void DocumentBroker::joinThread()
 {
-#ifndef MOBILEAPP
     _poll->joinThread();
-#endif
 }
 
 void DocumentBroker::stop(const std::string& reason)
@@ -429,13 +425,11 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
 
     LOG_INF("Loading [" << _docKey << "] for session [" << sessionId << "] and jail [" << jailId << "].");
 
-#ifndef MOBILEAPP
     {
         bool result;
         if (UnitWSD::get().filterLoad(sessionId, jailId, result))
             return result;
     }
-#endif
 
     if (_markToDestroy)
     {
@@ -996,11 +990,7 @@ bool DocumentBroker::sendUnoSave(const std::string& sessionId, bool dontTerminat
         oss << "}";
 
         assert(_storage);
-        _storage->setIsAutosave(isAutosave
-#ifndef MOBILEAPP
-                                || UnitWSD::get().isAutosave()
-#endif
-                                );
+        _storage->setIsAutosave(isAutosave || UnitWSD::get().isAutosave());
 
         const std::string saveArgs = oss.str();
         LOG_TRC(".uno:Save arguments: " << saveArgs);
@@ -1190,10 +1180,8 @@ void DocumentBroker::alertAllUsers(const std::string& msg)
 {
     assertCorrectThread();
 
-#ifndef MOBILEAPP
     if (UnitWSD::get().filterAlertAllusers(msg))
         return;
-#endif
 
     auto payload = std::make_shared<Message>(msg, Message::Dir::Out);
 
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index c52cbf243..4993acd66 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -57,7 +57,6 @@ public:
 class ChildProcess
 {
 public:
-#ifndef MOBILEAPP
     /// @param pid is the process ID of the child.
     /// @param socket is the underlying Sockeet to the child.
     ChildProcess(const Poco::Process::PID pid,
@@ -72,15 +71,6 @@ public:
     {
         LOG_INF("ChildProcess ctor [" << _pid << "].");
     }
-#else
-    ChildProcess(const std::shared_ptr<WebSocketHandler>& ws) :
-        _pid(0),
-        _jailId(""),
-        _ws(ws)
-    {
-        LOG_INF("ChildProcess ctor.");
-    }
-#endif
 
 
     ChildProcess(ChildProcess&& other) = delete;
@@ -89,7 +79,6 @@ public:
 
     ~ChildProcess()
     {
-#ifndef MOBILEAPP
         if (_pid <= 0)
             return;
 
@@ -99,7 +88,6 @@ public:
         // No need for the socket anymore.
         _ws.reset();
         _socket.reset();
-#endif
     }
 
     void setDocumentBroker(const std::shared_ptr<DocumentBroker>& docBroker);
@@ -108,7 +96,6 @@ public:
     /// Let the child close a nice way.
     void close()
     {
-#ifndef MOBILEAPP
         if (_pid < 0)
             return;
 
@@ -133,16 +120,15 @@ public:
         }
 
         _pid = -1;
-#endif
     }
 
     /// Kill or abandon the child.
     void terminate()
     {
-#ifndef MOBILEAPP
         if (_pid < 0)
             return;
 
+#ifndef MOBILEAPP
         if (::kill(_pid, 0) == 0)
         {
             LOG_INF("Killing child [" << _pid << "].");
@@ -151,9 +137,11 @@ public:
                 LOG_ERR("Cannot terminate lokit [" << _pid << "]. Abandoning.");
             }
         }
-
-        _pid = -1;
+#else
+        // What to do? Throw some unique exception that the outermost call in the thread catches and
+        // exits from the thread?
 #endif
+        _pid = -1;
     }
 
     Poco::Process::PID getPid() const { return _pid; }
@@ -206,9 +194,7 @@ private:
     Poco::Process::PID _pid;
     const std::string _jailId;
     std::shared_ptr<WebSocketHandler> _ws;
-#ifndef MOBILEAP
     std::shared_ptr<Socket> _socket;
-#endif
     std::weak_ptr<DocumentBroker> _docBroker;
 };
 
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 8f83234da..8ef290914 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -62,8 +62,6 @@
 #include <Poco/Net/PartHandler.h>
 #include <Poco/Net/SocketAddress.h>
 
-#include <ServerSocket.hpp>
-
 using Poco::Net::HTMLForm;
 using Poco::Net::PartHandler;
 
@@ -111,7 +109,7 @@ using Poco::Net::PartHandler;
 #include "FileServer.hpp"
 #include <FileUtil.hpp>
 #include <IoUtil.hpp>
-#ifdef KIT_IN_PROCESS
+#if defined KIT_IN_PROCESS || defined MOBILEAPP
 #  include <Kit.hpp>
 #endif
 #include <Log.hpp>
@@ -133,6 +131,12 @@ using Poco::Net::PartHandler;
 
 #include <common/SigUtil.hpp>
 
+#include <ServerSocket.hpp>
+
+#ifdef IOS
+#include "ios.h"
+#endif
+
 using namespace LOOLProtocol;
 
 using Poco::DirectoryIterator;
@@ -199,10 +203,6 @@ extern "C" { void dump_state(void); /* easy for gdb */ }
 static int careerSpanMs = 0;
 #endif
 
-#ifdef IOS
-#include "ios.h"
-#endif
-
 bool LOOLWSD::NoCapsForKit = false;
 bool LOOLWSD::TileCachePersistent = true;
 std::atomic<unsigned> LOOLWSD::NumConnections;
@@ -210,16 +210,9 @@ std::string LOOLWSD::Cache = LOOLWSD_CACHEDIR;
 std::set<std::string> LOOLWSD::EditFileExtensions;
 
 #ifdef MOBILEAPP
-
-// Some dummy versions of static ember functions
-
-void LOOLWSD::dumpIncomingTrace(const std::string& id, const std::string& sessionId, const std::string& data)
-{
-}
-
-#else
-
-// Most of this file is probably not used in a mobile app. Let's see.
+// Or can this be retreieved in some other way?
+int LOOLWSD::prisonerServerSocketFD;
+#endif
 
 namespace
 {
@@ -247,6 +240,8 @@ inline void shutdownLimitReached(WebSocketHandler& ws)
 
 inline void checkSessionLimitsAndWarnClients()
 {
+#ifndef MOBILEAPP
+
     if (DocBrokers.size() > LOOLWSD::MaxDocuments || LOOLWSD::NumConnections >= LOOLWSD::MaxConnections)
     {
         const std::string info = Poco::format(PAYLOAD_INFO_LIMIT_REACHED, LOOLWSD::MaxDocuments, LOOLWSD::MaxConnections);
@@ -261,12 +256,15 @@ inline void checkSessionLimitsAndWarnClients()
             LOG_ERR("Error while shuting down socket on reaching limit: " << ex.what());
         }
     }
+#endif
 }
 
 /// Internal implementation to alert all clients
 /// connected to any document.
 void alertAllUsersInternal(const std::string& msg)
 {
+#ifndef MOBILEAPP
+
     std::lock_guard<std::mutex> docBrokersLock(DocBrokersMutex);
 
     LOG_INF("Alerting all users: [" << msg << "]");
@@ -279,10 +277,12 @@ void alertAllUsersInternal(const std::string& msg)
         std::shared_ptr<DocumentBroker> docBroker = brokerIt.second;
         docBroker->addCallback([msg, docBroker](){ docBroker->alertAllUsers(msg); });
     }
+#endif
 }
 
 static void checkDiskSpaceAndWarnClients(const bool cacheLastCheck)
 {
+#ifndef MOBILEAPP
     try
     {
         const std::string fs = FileUtil::checkDiskSpaceOnRegisteredFileSystems(cacheLastCheck);
@@ -296,6 +296,7 @@ static void checkDiskSpaceAndWarnClients(const bool cacheLastCheck)
     {
         LOG_WRN("Exception while checking disk-space and warning clients: " << exc.what());
     }
+#endif
 }
 
 }
@@ -339,6 +340,8 @@ void cleanupDocBrokers()
     }
 }
 
+#ifndef MOBILEAPP
+
 /// Forks as many children as requested.
 /// Returns the number of children requested to spawn,
 /// -1 for error.
@@ -437,6 +440,8 @@ static bool prespawnChildren()
     return lock.try_lock() && (rebalanceChildren(LOOLWSD::NumPreSpawnedChildren) > 0);
 }
 
+#endif
+
 static size_t addNewChild(const std::shared_ptr<ChildProcess>& child)
 {
     std::unique_lock<std::mutex> lock(NewChildrenMutex);
@@ -446,22 +451,29 @@ static size_t addNewChild(const std::shared_ptr<ChildProcess>& child)
     if (OutstandingForks < 0)
         ++OutstandingForks;
 
+    LOG_TRC("Adding one child to NewChildren");
     NewChildren.emplace_back(child);
     const size_t count = NewChildren.size();
     LOG_INF("Have " << count << " spare " <<
             (count == 1 ? "child" : "children") << " after adding [" << child->getPid() << "].");
     lock.unlock();
 
+    LOG_TRC("Notifying NewChildrenCV");
     NewChildrenCV.notify_one();
     return count;
 }
 
-std::shared_ptr<ChildProcess> getNewChild_Blocks()
+std::shared_ptr<ChildProcess> getNewChild_Blocks(
+#ifdef MOBILEAPP
+                                                 const std::string& uri
+#endif
+                                                 )
 {
     std::unique_lock<std::mutex> lock(NewChildrenMutex);
 
     const auto startTime = std::chrono::steady_clock::now();
 
+#ifndef MOBILEAPP
     LOG_DBG("getNewChild: Rebalancing children.");
     int numPreSpawn = LOOLWSD::NumPreSpawnedChildren;
     ++numPreSpawn; // Replace the one we'll dispatch just now.
@@ -474,17 +486,33 @@ std::shared_ptr<ChildProcess> getNewChild_Blocks()
         // Let the caller retry after a while.
         return nullptr;
     }
-
     // With valgrind we need extended time to spawn kits.
     const size_t timeoutMs = CHILD_TIMEOUT_MS / 2;
     LOG_TRC("Waiting for a new child for a max of " << timeoutMs << " ms.");
     const auto timeout = std::chrono::milliseconds(timeoutMs);
+#else
+    const auto timeout = std::chrono::hours(100);
+
+    std::thread([&]
+                {
+                    // Ugly to have that static global, otoh we know there is just one LOOLWSD
+                    // object. (Even in real Online.) I have no idea what I am doing here.
+                    lokit_main(uri, LOOLWSD::prisonerServerSocketFD);
+                }).detach();
+#endif
+
     // FIXME: blocks ...
     // Unfortunately we need to wait after spawning children to avoid bombing the system.
     // If we fail fast and return, the next document will spawn more children without knowing
     // there are some on the way already. And if the system is slow already, that wouldn't help.
-    if (NewChildrenCV.wait_for(lock, timeout, []() { return !NewChildren.empty(); }))
-    {
+    LOG_TRC("Waiting for NewChildrenCV");
+    if (NewChildrenCV.wait_for(lock, timeout, []()
+                               {
+                                   LOG_TRC("Predicate for NewChildrenCV wait: NewChildren.size()=" << NewChildren.size());
+                                   return !NewChildren.empty();
+                               }))
+    {
+        LOG_TRC("NewChildrenCV wait successful");
         std::shared_ptr<ChildProcess> child = NewChildren.back();
         NewChildren.pop_back();
         const size_t available = NewChildren.size();
@@ -504,6 +532,7 @@ std::shared_ptr<ChildProcess> getNewChild_Blocks()
     }
     else
     {
+        LOG_TRC("NewChildrenCV wait failed");
         LOG_WRN("getNewChild: No child available. Sending spawn request to forkit and failing.");
     }
 
@@ -511,6 +540,8 @@ std::shared_ptr<ChildProcess> getNewChild_Blocks()
     return nullptr;
 }
 
+#ifndef MOBILEAPP
+
 /// Handles the filename part of the convert-to POST request payload.
 class ConvertToPartHandler : public PartHandler
 {
@@ -605,6 +636,8 @@ inline std::string getAdminURI(const Poco::Util::LayeredConfiguration &config)
 
 } // anonymous namespace
 
+#endif // MOBILEAPP
+
 std::atomic<unsigned> LOOLWSD::NextSessionId;
 #ifndef KIT_IN_PROCESS
 std::atomic<int> LOOLWSD::ForKitWritePipe(-1);
@@ -678,10 +711,12 @@ LOOLWSD::~LOOLWSD()
 
 void LOOLWSD::initialize(Application& self)
 {
+#ifndef MOBILEAPP
     if (geteuid() == 0)
     {
         throw std::runtime_error("Do not run as root. Please run as lool user.");
     }
+#endif
 
     if (!UnitWSD::init(UnitWSD::UnitType::Wsd, UnitTestLibrary))
     {
@@ -761,6 +796,8 @@ void LOOLWSD::initialize(Application& self)
     AutoPtr<AppConfigMap> defConfig(new AppConfigMap(DefAppConfig));
     conf.addWriteable(defConfig, PRIO_SYSTEM); // Lowest priority
 
+#ifndef MOBILEAPP
+
     // Load default configuration files, if present.
     if (loadConfiguration(PRIO_DEFAULT) == 0)
     {
@@ -831,6 +868,7 @@ void LOOLWSD::initialize(Application& self)
         }
     }
 
+
     // Log at trace level until we complete the initialization.
     Log::initialize("wsd", "trace", withColor, logToFile, logProperties);
     if (LogLevel != "trace")
@@ -879,6 +917,8 @@ void LOOLWSD::initialize(Application& self)
     std::string allowedLanguages(config().getString("allowed_languages"));
     setenv("LOK_WHITELIST_LANGUAGES", allowedLanguages.c_str(), 1);
 
+#endif
+
     Cache = getPathFromConfig("tile_cache_path");
     SysTemplate = getPathFromConfig("sys_template_path");
     LoTemplate = getPathFromConfig("lo_template_path");
@@ -894,12 +934,14 @@ void LOOLWSD::initialize(Application& self)
     }
     LOG_INF("NumPreSpawnedChildren set to " << NumPreSpawnedChildren << ".");
 
+#ifndef MOBILEAPP
     const auto maxConcurrency = getConfigValue<int>(conf, "per_document.max_concurrency", 4);
     if (maxConcurrency > 0)
     {
         setenv("MAX_CONCURRENCY", std::to_string(maxConcurrency).c_str(), 1);
     }
     LOG_INF("MAX_CONCURRENCY set to " << maxConcurrency << ".");
+#endif
 
     // Otherwise we profile the soft-device at jail creation time.
     setenv("SAL_DISABLE_OPENCL", "true", 1);
@@ -995,10 +1037,13 @@ void LOOLWSD::initialize(Application& self)
         TraceDumper.reset(new TraceFileWriter(path, recordOutgoing, compress, takeSnapshot, filters));
     }
 
+#ifndef MOBILEAPP
     FileServerRequestHandler::initialize();
+#endif
 
     StorageBase::initialize();
 
+#ifndef MOBILEAPP
     ServerApplication::initialize(self);
 
     DocProcSettings docProcSettings;
@@ -1007,6 +1052,7 @@ void LOOLWSD::initialize(Application& self)
     docProcSettings.LimitFileSizeMb = getConfigValue<int>("per_document.limit_file_size_mb", 0);
     docProcSettings.LimitNumberOpenFiles = getConfigValue<int>("per_document.limit_num_open_files", 0);
     Admin::instance().setDefDocProcSettings(docProcSettings, false);
+#endif
 
 #if ENABLE_DEBUG
     std::cerr << "\nLaunch one of these in your browser:\n\n"
@@ -1024,6 +1070,7 @@ void LOOLWSD::initialize(Application& self)
 
 void LOOLWSD::initializeSSL()
 {
+#if ENABLE_SSL
     if (!LOOLWSD::isSSLEnabled())
         return;
 
@@ -1039,7 +1086,6 @@ void LOOLWSD::initializeSSL()
     const std::string ssl_cipher_list = config().getString("ssl.cipher_list", "");
     LOG_INF("SSL Cipher list: " << ssl_cipher_list);
 
-#if ENABLE_SSL
     // Initialize the non-blocking socket SSL.
     SslContext::initialize(ssl_cert_file_path,
                            ssl_key_file_path,
@@ -1104,6 +1150,7 @@ void LOOLWSD::dumpOutgoingTrace(const std::string& id, const std::string& sessio
 
 void LOOLWSD::defineOptions(OptionSet& optionSet)
 {
+#ifndef MOBILEAPP
     ServerApplication::defineOptions(optionSet);
 
     optionSet.addOption(Option("help", "", "Display help information on command line arguments.")
@@ -1161,11 +1208,13 @@ void LOOLWSD::defineOptions(OptionSet& optionSet)
                         .repeatable(false)
                         .argument("trace_file_name"));
 #endif
+#endif
 }
 
 void LOOLWSD::handleOption(const std::string& optionName,
                            const std::string& value)
 {
+#ifndef MOBILEAPP
     ServerApplication::handleOption(optionName, value);
 
     if (optionName == "help")
@@ -1215,8 +1264,11 @@ void LOOLWSD::handleOption(const std::string& optionName,
     else if (optionName == "fuzz")
         FuzzFileName = value;
 #endif
+#endif
 }
 
+#ifndef MOBILEAPP
+
 void LOOLWSD::displayHelp()
 {
     HelpFormatter helpFormatter(options());
@@ -1312,6 +1364,8 @@ bool LOOLWSD::checkAndRestoreForKit()
 #endif
 }
 
+#endif
+
 void LOOLWSD::doHousekeeping()
 {
     PrisonerPoll.wakeup();
@@ -1346,6 +1400,7 @@ void LOOLWSD::autoSave(const std::string& docKey)
 /// Really do the house-keeping
 void PrisonerPoll::wakeupHook()
 {
+#ifndef MOBILEAPP
     if (!LOOLWSD::checkAndRestoreForKit())
     {
         // No children have died.
@@ -1375,15 +1430,17 @@ void PrisonerPoll::wakeupHook()
 #endif
         }
     }
-
+#endif
     std::unique_lock<std::mutex> docBrokersLock(DocBrokersMutex, std::defer_lock);
     if (docBrokersLock.try_lock())
         cleanupDocBrokers();
 }
 
+#ifndef MOBILEAPP
+
 bool LOOLWSD::createForKit()
 {
-#ifdef KIT_IN_PROCESS
+#if defined KIT_IN_PROCESS
     return true;
 #else
     LOG_INF("Creating new forkit process.");
@@ -1474,6 +1531,8 @@ bool LOOLWSD::createForKit()
 #endif
 }
 
+#endif
+
 #ifdef FUZZER
 std::mutex Connection::Mutex;
 #endif
@@ -1639,6 +1698,8 @@ private:
     /// Called after successful socket reads.
     void handleIncomingMessage(SocketDisposition &disposition) override
     {
+        // LOG_TRC("***** PrisonerRequestDispatcher::handleIncomingMessage()");
+
         if (UnitWSD::get().filterHandleRequest(
                 UnitWSD::TestRequest::Prisoner, disposition, *this))
             return;
@@ -1659,6 +1720,7 @@ private:
 
         try
         {
+#ifndef MOBILEAPP
             if (!socket->parseHeader("Prisoner", message, request, &requestSize))
                 return;
 
@@ -1707,6 +1769,12 @@ private:
             LOG_INF("New child [" << pid << "], jailId: " << jailId << ".");
 
             UnitWSD::get().newChild(*this);
+#else
+            Poco::Process::PID pid = 1;
+            std::string jailId = "jail";
+            socket->_inBuffer.clear();
+#endif
+            LOG_TRC("Calling make_shared<ChildProcess>, for NewChildren?");
 
             auto child = std::make_shared<ChildProcess>(pid, jailId, socket, request);
 
@@ -1716,6 +1784,7 @@ private:
             // until we attach the childProcess (with this socket)
             // to a docBroker, which will do the polling.
             disposition.setMove([child](const std::shared_ptr<Socket> &){
+                    LOG_TRC("Calling addNewChild in disposition's move thing to add to NewChildren");
                     addNewChild(child);
                 });
         }
@@ -1812,8 +1881,10 @@ private:
     /// Called after successful socket reads.
     void handleIncomingMessage(SocketDisposition &disposition) override
     {
+        // LOG_TRC("***** ClientRequestDispatcher::handleIncomingMessage()");
         std::shared_ptr<StreamSocket> socket = _socket.lock();
 
+#ifndef MOBILEAPP
         Poco::MemoryInputStream message(&socket->_inBuffer[0],
                                         socket->_inBuffer.size());;
         Poco::Net::HTTPRequest request;
@@ -1927,6 +1998,11 @@ private:
         // if we succeeded - remove the request from our input buffer
         // we expect one request per socket
         socket->eraseFirstInputBytes(requestSize);
+#else
+        Poco::Net::HTTPRequest request;
+        handleClientWsUpgrade(request, std::string(socket->_inBuffer.data(), socket->_inBuffer.size()), disposition);
+        socket->_inBuffer.clear();
+#endif
     }
 
     int getPollEvents(std::chrono::steady_clock::time_point /* now */,
@@ -1939,6 +2015,7 @@ private:
     {
     }
 
+#ifndef MOBILEAPP
     void handleFileServerRequest(const Poco::Net::HTTPRequest& request, Poco::MemoryInputStream& message)
     {
         std::shared_ptr<StreamSocket> socket = _socket.lock();
@@ -2305,6 +2382,7 @@ private:
 
         throw BadRequestException("Invalid or unknown request.");
     }
+#endif
 
     void handleClientWsUpgrade(const Poco::Net::HTTPRequest& request, const std::string& url,
                                SocketDisposition &disposition)
@@ -2373,7 +2451,7 @@ private:
                         docBroker->startThread();
 
                         // We no longer own this socket.
-                        moveSocket->setThreadOwner(std::thread::id(0));
+                        moveSocket->setThreadOwner(std::thread::id());
 
                         docBroker->addCallback([docBroker, moveSocket, clientSession]()
                         {
@@ -2504,10 +2582,10 @@ class PlainSocketFactory final : public SocketFactory
     std::shared_ptr<Socket> create(const int physicalFd) override
     {
         int fd = physicalFd;
-
+#ifndef MOBILEAPP
         if (SimulatedLatencyMs > 0)
             fd = Delay::create(SimulatedLatencyMs, physicalFd);
-
+#endif
         std::shared_ptr<Socket> socket =
             StreamSocket::create<StreamSocket>(
                 fd, false, std::make_shared<ClientRequestDispatcher>());
@@ -2574,9 +2652,18 @@ public:
     void start(const int port)
     {
         _acceptPoll.startThread();
-        _acceptPoll.insertNewSocket(findServerPort(port));
+        std::shared_ptr<ServerSocket> serverSocket(findServerPort(port));
+        _acceptPoll.insertNewSocket(serverSocket);
+
+#ifdef MOBILEAPP
+        loolwsd_server_socket_fd = serverSocket->getFD();
+#endif
+
         WebServerPoll.startThread();
+
+#ifndef MOBILEAPP
         Admin::instance().start();
+#endif
     }
 
     void stop()
@@ -2613,11 +2700,13 @@ public:
         os << "Prisoner poll:\n";
         PrisonerPoll.dumpState(os);
 
+#ifndef MOBILEAPP
         os << "Admin poll:\n";
         Admin::instance().dumpState(os);
 
         // If we have any delaying work going on.
         Delay::dumpState(os);
+#endif
 
         os << "Document Broker polls "
                   << "[ " << DocBrokers.size() << " ]:\n";
@@ -2694,6 +2783,9 @@ private:
 
         MasterPortNumber = port;
         LOG_INF("Listening to prisoner connections on port " << port);
+#ifdef MOBILEAPP
+        LOOLWSD::prisonerServerSocketFD = socket->getFD();
+#endif
         return socket;
     }
 
@@ -2709,9 +2801,9 @@ private:
 #endif
             factory = std::make_shared<PlainSocketFactory>();
 
-
         std::shared_ptr<ServerSocket> socket = getServerSocket(
             ServerSocket::Type::Public, port, WebServerPoll, factory);
+#ifdef MOBILEAPP
 #ifdef BUILDLING_TESTS
         while (!socket)
         {
@@ -2721,7 +2813,7 @@ private:
                 ServerSocket::Type::Public, port, WebServerPoll, factory);
         }
 #endif
-
+#endif
         if (!socket)
         {
             LOG_FTL("Failed to listen on Server port(s) (" <<
@@ -2735,7 +2827,7 @@ private:
     }
 };
 
-LOOLWSDServer srv;
+static LOOLWSDServer srv;
 
 bool LOOLWSD::handleShutdownRequest()
 {
@@ -2758,6 +2850,7 @@ int LOOLWSD::innerMain()
     SigUtil::setTerminationSignals();
 #endif
 
+#ifdef __linux
     // down-pay all the forkit linking cost once & early.
     Environment::set("LD_BIND_NOW", "1");
 
@@ -2767,6 +2860,7 @@ int LOOLWSD::innerMain()
         Util::getVersionInfo(version, hash);
         LOG_INF("Loolwsd version details: " << version << " - " << hash);
     }
+#endif
 
     initializeSSL();
 
@@ -2783,6 +2877,7 @@ int LOOLWSD::innerMain()
         return Application::EXIT_SOFTWARE;
     }
 
+#ifndef MOBILEAPP
     // We use the same option set for both parent and child loolwsd,
     // so must check options required in the parent (but not in the
     // child) separately now. Also check for options that are
@@ -2819,11 +2914,15 @@ int LOOLWSD::innerMain()
         throw IncompatibleOptionsException("port");
 
     ClientRequestDispatcher::InitStaticFileContentCache();
+#endif
 
     // Start the internal prisoner server and spawn forkit,
     // which in turn forks first child.
     srv.startPrisoners(MasterPortNumber);
 
+// No need to "have at least one child" beforehand on mobile
+#ifndef MOBILEAPP
+
 #ifndef KIT_IN_PROCESS
     {
         // Make sure we have at least one child before moving forward.
@@ -2862,6 +2961,8 @@ int LOOLWSD::innerMain()
         Log::logger().setLevel(LogLevel);
     }
 
+#endif
+
     // Start the server.
     srv.start(ClientPortNumber);
 
@@ -2886,6 +2987,7 @@ int LOOLWSD::innerMain()
         // Wake the prisoner poll to spawn some children, if necessary.
         PrisonerPoll.wakeup();
 
+#ifndef MOBILEAPP
         const std::chrono::milliseconds::rep timeSinceStartMs = std::chrono::duration_cast<std::chrono::milliseconds>(
                                             std::chrono::steady_clock::now() - startStamp).count();
 
@@ -2900,8 +3002,12 @@ int LOOLWSD::innerMain()
             break;
         }
 #endif
+#endif
     }
 
+// No point in doing any orderly shutdown on mobile, we will never exit intentionally, the OS will
+// kill us.
+#ifndef MOBILEAPP
     // Stop the listening to new connections
     // and wait until sockets close.
     LOG_INF("Stopping server socket listening. ShutdownFlag: " <<
@@ -2975,22 +3081,27 @@ int LOOLWSD::innerMain()
         LOG_INF("Removing jail [" << path << "].");
         FileUtil::removeFile(path, true);
     }
+#endif // !MOBILEAPP
+
     return Application::EXIT_OK;
 }
 
+
 void LOOLWSD::cleanup()
 {
+#ifndef MOBILEAPP
     FileServerRequestHandler::uninitialize();
 
+#if ENABLE_SSL
     // Finally, we no longer need SSL.
     if (LOOLWSD::isSSLEnabled())
     {
         Poco::Net::uninitializeSSL();
         Poco::Crypto::uninitializeCrypto();
-#if ENABLE_SSL
         SslContext::uninitialize();
-#endif
     }
+#endif
+#endif
 }
 
 int LOOLWSD::main(const std::vector<std::string>& /*args*/)
@@ -3015,6 +3126,8 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
     return returnValue;
 }
 
+#ifndef MOBILEAPP
+
 void UnitWSD::testHandleRequest(TestRequest type, UnitHTTPServerRequest& /* request */, UnitHTTPServerResponse& /* response */)
 {
     switch (type)
@@ -3060,6 +3173,8 @@ void alertAllUsers(const std::string& msg)
 }
 #endif
 
+#endif
+
 void dump_state()
 {
     std::ostringstream oss;
@@ -3070,8 +3185,10 @@ void dump_state()
     LOG_TRC(msg);
 }
 
+#ifndef MOBILEAPP
+
 POCO_SERVER_MAIN(LOOLWSD)
 
-#endif // !MOBILEAPP
+#endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp
index 90cc932e5..369b8ab33 100644
--- a/wsd/LOOLWSD.hpp
+++ b/wsd/LOOLWSD.hpp
@@ -28,7 +28,11 @@ class ChildProcess;
 class TraceFileWriter;
 class DocumentBroker;
 
-std::shared_ptr<ChildProcess> getNewChild_Blocks();
+std::shared_ptr<ChildProcess> getNewChild_Blocks(
+#ifdef MOBILEAPP
+                                                 const std::string& uri
+#endif
+                                                 );
 
 /// The Server class which is responsible for all
 /// external interactions.
@@ -143,11 +147,12 @@ public:
     /// Autosave a given document
     static void autoSave(const std::string& docKey);
 
+    int innerMain();
+
 protected:
     void initialize(Poco::Util::Application& self) override;
     void defineOptions(Poco::Util::OptionSet& options) override;
     void handleOption(const std::string& name, const std::string& value) override;
-    int innerMain();
     int main(const std::vector<std::string>& args) override;
 
     /// Handle various global static destructors.
@@ -237,6 +242,11 @@ private:
 private:
     /// Settings passed from the command-line to override those in the config file.
     std::map<std::string, std::string> _overrideSettings;
+
+#ifdef MOBILEAPP
+public:
+    static int prisonerServerSocketFD;
+#endif
 };
 
 #endif
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 52ab41d16..951fe31d0 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -56,6 +56,8 @@ bool StorageBase::FilesystemEnabled;
 bool StorageBase::WopiEnabled;
 Util::RegexListMatcher StorageBase::WopiHosts;
 
+#ifndef MOBILEAPP
+
 std::string StorageBase::getLocalRootPath() const
 {
     std::string localPath = _jailPath;
@@ -77,9 +79,12 @@ size_t StorageBase::getFileSize(const std::string& filename)
     return std::ifstream(filename, std::ifstream::ate | std::ifstream::binary).tellg();
 }
 
+#endif
+
 void StorageBase::initialize()
 {
     const auto& app = Poco::Util::Application::instance();
+#ifndef MOBILEAPP
     FilesystemEnabled = app.config().getBool("storage.filesystem[@allow]", false);
 
     // Parse the WOPI settings.
@@ -128,6 +133,9 @@ void StorageBase::initialize()
     Poco::Net::Context::Ptr sslClientContext = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, sslClientParams);
     Poco::Net::SSLManager::instance().initializeClient(consoleClientHandler, invalidClientCertHandler, sslClientContext);
 #endif
+#else
+    FilesystemEnabled = true;
+#endif
 }
 
 #ifndef MOBILEAPP
@@ -179,7 +187,6 @@ std::unique_ptr<StorageBase> StorageBase::create(const Poco::URI& uri, const std
     // here much earlier. Also, using exceptions is lame and makes understanding the code harder,
     // but that is just my personal preference.
 
-#ifndef MOBILEAPP
     std::unique_ptr<StorageBase> storage;
 
     if (UnitWSD::get().createStorage(uri, jailRoot, jailPath, storage))
@@ -190,10 +197,6 @@ std::unique_ptr<StorageBase> StorageBase::create(const Poco::URI& uri, const std
             return storage;
         }
     }
-#else
-    if (false)
-        ;
-#endif
     else if (uri.isRelative() || uri.getScheme() == "file")
     {
         LOG_INF("Public URI [" << uri.toString() << "] is a file.");
@@ -263,6 +266,7 @@ std::unique_ptr<LocalStorage::LocalFileInfo> LocalStorage::getLocalFileInfo()
 
 std::string LocalStorage::loadStorageFileToLocal(const Authorization& /*auth*/)
 {
+#ifndef MOBILEAPP
     // /chroot/jailId/user/doc/childId/file.ext
     const std::string filename = Poco::Path(_uri.getPath()).getFileName();
     _jailedFilePath = Poco::Path(getLocalRootPath(), filename).toString();
@@ -311,6 +315,16 @@ std::string LocalStorage::loadStorageFileToLocal(const Authorization& /*auth*/)
 #else
     return _jailedFilePath;
 #endif
+
+#else // MOBILEAPP
+
+    // In the mobile app we use no jail
+    _jailedFilePath = _uri.getPath();
+    _isLoaded = true;
+
+    return _jailedFilePath;
+#endif
+
 }
 
 StorageBase::SaveResult LocalStorage::saveLocalFileToStorage(const Authorization& /*auth*/, const std::string& /*saveAsPath*/, const std::string& /*saveAsFilename*/)
diff --git a/wsd/TileCache.cpp b/wsd/TileCache.cpp
index e76d1c7db..52d923ffd 100644
--- a/wsd/TileCache.cpp
+++ b/wsd/TileCache.cpp
@@ -151,11 +151,9 @@ std::unique_ptr<std::fstream> TileCache::lookupTile(const TileDesc& tile)
 
     std::unique_ptr<std::fstream> result(new std::fstream(fileName, std::ios::in));
 
-#ifndef MOBILEAPP
     UnitWSD::get().lookupTile(tile.getPart(), tile.getWidth(), tile.getHeight(),
                               tile.getTilePosX(), tile.getTilePosY(),
                               tile.getTileWidth(), tile.getTileHeight(), result);
-#endif
     if (result && result->is_open())
     {
         LOG_TRC("Found cache tile: " << fileName);
commit 384a57092c72b5fa7ce87efebb3e476334840d13
Author:     Tor Lillqvist <tml at iki.fi>
AuthorDate: Wed Sep 12 22:18:08 2018 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Wed Sep 19 11:19:25 2018 +0300

    Make the "Online" source files actually show up in Xcode

diff --git a/Mobile/Mobile.xcodeproj/project.pbxproj b/Mobile/Mobile.xcodeproj/project.pbxproj
index 1bb123e3b..0d2062dff 100644
--- a/Mobile/Mobile.xcodeproj/project.pbxproj
+++ b/Mobile/Mobile.xcodeproj/project.pbxproj
@@ -24,7 +24,6 @@
 		BE5EB5C6213FE29900E0826C /* SigUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BE213FE29900E0826C /* SigUtil.cpp */; };
 		BE5EB5C7213FE29900E0826C /* Protocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BF213FE29900E0826C /* Protocol.cpp */; };
 		BE5EB5C8213FE29900E0826C /* FileUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5C0213FE29900E0826C /* FileUtil.cpp */; };
-		BE5EB5CA213FE2B100E0826C /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5C9213FE2B100E0826C /* Socket.cpp */; };
 		BE5EB5CF213FE2D000E0826C /* ClientSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */; };
 		BE5EB5D0213FE2D000E0826C /* TileCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5CD213FE2D000E0826C /* TileCache.cpp */; };
 		BE5EB5D22140039100E0826C /* LOOLWSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0826C /* LOOLWSD.cpp */; };
@@ -57,6 +56,7 @@
 		BEA2835621467FDD00848631 /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2835521467FDD00848631 /* Kit.cpp */; };
 		BEA283582146945500848631 /* ChildSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA283572146945500848631 /* ChildSession.cpp */; };
 		BEA2835A21470A1C00848631 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEA2835921470A1C00848631 /* WebKit.framework */; };
+		BEA2835D21498AD400848631 /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2835C21498AD400848631 /* Socket.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -69,20 +69,19 @@
 		BE00F89E21396585001CE2D4 /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../loleaflet/dist/images; sourceTree = "<group>"; };
 		BE00F8B4213ED543001CE2D4 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
 		BE00F8B6213ED573001CE2D4 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
-		BE5EB5B9213FE29900E0826C /* Log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Log.cpp; path = ../../../common/Log.cpp; sourceTree = "<group>"; };
-		BE5EB5BA213FE29900E0826C /* SpookyV2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyV2.cpp; path = ../../../common/SpookyV2.cpp; sourceTree = "<group>"; };
-		BE5EB5BB213FE29900E0826C /* Session.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Session.cpp; path = ../../../common/Session.cpp; sourceTree = "<group>"; };
-		BE5EB5BC213FE29900E0826C /* Util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Util.cpp; path = ../../../common/Util.cpp; sourceTree = "<group>"; };
-		BE5EB5BD213FE29900E0826C /* MessageQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageQueue.cpp; path = ../../../common/MessageQueue.cpp; sourceTree = "<group>"; };
-		BE5EB5BE213FE29900E0826C /* SigUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SigUtil.cpp; path = ../../../common/SigUtil.cpp; sourceTree = "<group>"; };
-		BE5EB5BF213FE29900E0826C /* Protocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Protocol.cpp; path = ../../../common/Protocol.cpp; sourceTree = "<group>"; };
-		BE5EB5C0213FE29900E0826C /* FileUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileUtil.cpp; path = ../../../common/FileUtil.cpp; sourceTree = "<group>"; };
-		BE5EB5C9213FE2B100E0826C /* Socket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = ../../../net/Socket.cpp; sourceTree = "<group>"; };
-		BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClientSession.cpp; path = ../../../wsd/ClientSession.cpp; sourceTree = "<group>"; };
-		BE5EB5CD213FE2D000E0826C /* TileCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TileCache.cpp; path = ../../../wsd/TileCache.cpp; sourceTree = "<group>"; };
-		BE5EB5D12140039100E0826C /* LOOLWSD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LOOLWSD.cpp; path = ../../../wsd/LOOLWSD.cpp; sourceTree = "<group>"; };
-		BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentBroker.cpp; path = ../../../wsd/DocumentBroker.cpp; sourceTree = "<group>"; };
-		BE5EB5D521401E0F00E0826C /* Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Storage.cpp; path = ../../../wsd/Storage.cpp; sourceTree = "<group>"; };
+		BE5EB5B9213FE29900E0826C /* Log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Log.cpp; sourceTree = "<group>"; };
+		BE5EB5BA213FE29900E0826C /* SpookyV2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpookyV2.cpp; sourceTree = "<group>"; };
+		BE5EB5BB213FE29900E0826C /* Session.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Session.cpp; sourceTree = "<group>"; };
+		BE5EB5BC213FE29900E0826C /* Util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Util.cpp; sourceTree = "<group>"; };
+		BE5EB5BD213FE29900E0826C /* MessageQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MessageQueue.cpp; sourceTree = "<group>"; };
+		BE5EB5BE213FE29900E0826C /* SigUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SigUtil.cpp; sourceTree = "<group>"; };
+		BE5EB5BF213FE29900E0826C /* Protocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Protocol.cpp; sourceTree = "<group>"; };
+		BE5EB5C0213FE29900E0826C /* FileUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileUtil.cpp; sourceTree = "<group>"; };
+		BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClientSession.cpp; sourceTree = "<group>"; };
+		BE5EB5CD213FE2D000E0826C /* TileCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileCache.cpp; sourceTree = "<group>"; };
+		BE5EB5D12140039100E0826C /* LOOLWSD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LOOLWSD.cpp; sourceTree = "<group>"; };
+		BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentBroker.cpp; sourceTree = "<group>"; };
+		BE5EB5D521401E0F00E0826C /* Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storage.cpp; sourceTree = "<group>"; };
 		BE5EB5D92140363100E0826C /* ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios.mm; path = ../../ios/ios.mm; sourceTree = "<group>"; };
 		BE5EB5DB2140480B00E0826C /* icudt62l.dat */ = {isa = PBXFileReference; lastKnownFileType = file; name = icudt62l.dat; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/icudt62l.dat"; sourceTree = "<group>"; };
 		BE8D77272136762500AC58EA /* Mobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mobile.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -113,9 +112,10 @@

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list