F(x)tec Pro¹ with SailfishOS 3.2 community build

Table of Contents

I finally received my F(x)tec Pro¹.

After checking with the shipped Android that the device was not DOA and applying all updates, I reflashed it with SailfishOS

These are my notes on installing Sailfish OS community build.

boot splash

When I did the flashing, sailfishos-t5-release- was the current version. Obviously check the linked post and here for most recent image available if flashing at a later date.

What this post is about

  • Getting Sailfish OS on the F(x)tec Pro¹
  • allowing me to use Ansible with the Pro¹ being a host (the playbooks are run from one of my Fedora x86_64 machines)
  • grabbing some info from the device to compare to my previous SFOS devices
  • doing some well documented adjustements that were not yet part of the build

I am fine with using a community build that can not include some bits, hopefully Jolla will eventually make one available which, like all previous SFOS releases, I’ll most definitely will purchase to support the company.

Pages to Read

Check these three pages for updated information before flashing!

While I love SFOS and greatly appreciate the community efforts, information is spread all over the place. maemo.org is always my primary source, followed by together.jolla.com

Install Sailfish OS

Just follow the instructions, I am not going to needlessly duplicate them here. To be safe against future data loss, I have just pointed the Wayback Machine at the URL.

Command Log

These are the commands I used. You MUST read the guide linked above, the commands are just for my records and do not include steps done interactively on the phone.

µSD Card Preparation

Since tyhe instructions insist on a card no larger than 32GB and me not having any idea what filesystems besides vfat that TWRP build supports, I started with a vfat formatted SD card since I expect TWRP to read vfat.

If the SIM / µSD card tray was not so flimsy on the Pro¹ I would have done a few tests, but I am not willing to riosk breaking it on this new toy.

[root@workstation ~]# grep 3EA0-15EE /proc/mounts
/dev/sdd1 /run/media/pcfe/3EA0-15EE vfat rw,nosuid,nodev,relatime,uid=1000,gid=1000,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,showexec,utf8,flush,errors=remount-ro 0 0
[root@workstation ~]# fdisk -l /dev/sdd
Disk /dev/sdd: 29.83 GiB, 32010928128 bytes, 62521344 sectors
Disk model: SD  Transcend
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x80200802

Device     Boot Start      End  Sectors  Size Id Type
/dev/sdd1        2048 62521310 62519263 29.8G  c W95 FAT32 (LBA)

Install Needed Tools on Workstation

I use Fedora on my workstation, the needed tools are available in the standard repos.

[root@workstation ~]# dnf install android-tools

Expect to find them in any modern distro, the packe name might differ though. If you use Windows or MacOS, then you are on your own.

Unlock Bootloader

Remember to first allow this and USB debugging under Android’s developer settings, as desribed in the instructions.

[root@workstation ~]# fastboot devices
8911ce70	fastboot
[root@workstation ~]# fastboot flashing unlock
OKAY [  0.044s]
Finished. Total time: 0.044s

Flash TWRP

[root@workstation ~]# fastboot devices
8911ce70	fastboot
[root@workstation ~]# fastboot set_active a
Setting current slot to 'a'                        OKAY [  0.009s]
Finished. Total time: 0.010s
[root@workstation tmp]# fastboot flash boot twrp-3.3.1-qx1000.img
Sending 'boot_a' (31768 KB)                        OKAY [  0.797s]
Writing 'boot_a'                                   OKAY [  0.144s]
Finished. Total time: 0.943s

Flash SFOS via TWRP

Again, just follow the linked guide.

At the end of TWRP flashing, I got a ‘No OS installed warning’ warning which I ignored. Only ignore such warnings if, like me, you are comfortable reviving a dead phone as long as you manage to control the bootloader.

Sailfish booted up fine, but could not set the clock.

So I skipped Jolla account creation, compleetd the tutorial and set the clock to automatic in SFOS settings.

Use SailfishOS

From here on, it should behavelike any SFOS device. Obviously the commercial Jolla bits are not in the community build. e.g. the Android compatibility layer.

Only mind kernel updates for now! Check if the OTA you plan to install still needs you to dd the boot image to boot_a. With 20191218 and later images that should no longer be necessary

TODO: verify and update both here and at TJC after I applied my first new kernel via OTA.

Complete the Tutorial

It seems you can not skip the tutorial on first boot, complete it to gain control of you device. But, I find the version in shorter than on older builds. Let’s see how I feel when I see it for the Nth time ;-)

Enable Developer Mode

Follow Jolla’s instructions

Copy SSH Pubkey to Phone

user@workstation ~ $ ssh-copy-id -f -i ~/.ssh/id_USBkey.pub nemo@pro1

Enable ssh Access for root

I’ll ssh in directly as root. This saves me from having to make devel-su a valid become_method docs.

To be able to ssh in as root, you need to

  • enable developer mode in Jolla Settings
  • enable remote access in Jolla Settings
  • put your ssh pubkey in /root/.ssh/authorized_keys
  • chmod 0700 /root/.ssh/
  • chmod 0600 /root/.ssh/authorized_keys
user@workstation ~ $ ssh nemo@pro1
Last login: Sat Feb  1 11:38:40 2020
| Sailfish OS (Nuuksio)
[nemo@Pro1 ~]$ devel-su
[root@Pro1 ~]# cd
[root@Pro1 ~]# mkdir .ssh
[root@Pro1 ~]# chmod 700 .ssh
[root@Pro1 ~]# cd .ssh
[root@Pro1 .ssh]# cp /home/nemo/.ssh/authorized_keys .
[root@Pro1 .ssh]# ll
total 4
-rw------- 1 root root 773 Feb  1 14:31 authorized_keys


You may not need this, but like to control my gizmos with Ansible.

These steps should apply to any SFOS device, I have successfully used them with a previous one.

Install Python on SFOS

For Ansible to be able to control your Sailfish X device, you will need to install python.

user@workstation ~ $ ssh nemo@pro1
Last login: Sat Feb  1 14:31:46 2020 from
| Sailfish OS (Nuuksio)
[root@Pro1 ~]# pkcon refresh
Refreshing cache
Refreshing software list
[root@Pro1 ~]# pkcon install python
Testing changes
Finished                                                                [                                   ] (0%)
The following packages have to be installed:
 python-2.7.15+git5-1.6.3.jolla.armv7hl	An interpreted, interactive, object-oriented programming language
 python-libs-2.7.15+git5-1.6.3.jolla.armv7hl	Runtime libraries for Python
Proceed with changes? [N/y] y

Downloading packages
Installing packages
[root@Pro1 ~]#

Add Sailfish OS Device to Inventory

Obviously you will have to ensure that your phone is always reachable as pro1, do this via your network infrastructure.

pro1    ansible_user=root

Test Ansible Connectivity

user@workstation ~ $ ansible pro1 -m ping
[WARNING]: Platform linux on host pro1 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information.

pro1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    "changed": false,
    "ping": "pong"

View Ansible Facts

user@workstation ~ $ ansible -m setup pro1
[WARNING]: Platform linux on host pro1 is using the discovered Python interpreter at /usr/bin/python, but future
installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information.
pro1 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [

Silence the Warning

For now I want Ansible to explicitly use Python 2.7 in the Pro1, so I added the following in host_vars/pro1.yml.

ansible_python_interpreter: /usr/bin/python2.7

Do not blindly add this, RTFM first and decide which behaviour you want for your use case. auto or auto_silent may better suit your use case.

Use The Right Ansible Modules and Roles

Note that you should enable/disable repos with ssu. e.g.:

ssu --help
ssu lr #list repo
ssu ar #add repo

Software should be installed with pkcon.

pkcon install <PackageName>

Neither of these seem to have corresponding ansible modules.

My Generic SFOS Playbook

Is still quite short at the moment (only nails down ssh access), I expect this to grow when doing a step manually starts to annoy me.

For now I simply added the new host to my old play sailfish.yml, it now reads as follows

- name: SailfishOS config

    - gemini
    - pro1
    - Xperia10II-DualSIM

  become: no # we ssh in directly as root with ssh key, to avoid dealing with devel-su

    - name: restart systemd-journald
        name:       systemd-journald.service
        state:      restarted
    - name: restart sshd
        name:       sshd.service
        state:      restarted

    # Ensure sshd config is set up to my liking, the disconnect after 15 mins is simply because I tend to forget for hours that I ssh-ed in and this will have a battery hit
    - name: SSHD | ensure AuthorizedKeysFile is configured
        path:         /etc/ssh/sshd_config
        regexp:       '^AuthorizedKeysFile'
        insertbefore: '^#AuthorizedPrincipalsFile none'
        line:         'AuthorizedKeysFile	.ssh/authorized_keys'
      notify: restart sshd

    - name: SSHD | ensure PasswordAuthentication is off
        path:         /etc/ssh/sshd_config
        regexp:       '^PasswordAuthentication'
        insertafter:  '^#PasswordAuthentication'
        line:         'PasswordAuthentication no'
      notify: restart sshd

    - name: SSHD | ensure that a response is requested from the client after 1 minute of inactivity
        path:         /etc/ssh/sshd_config
        regexp:       '^ClientAliveInterval'
        insertafter:  '^#ClientAliveInterval'
        line:         'ClientAliveInterval 1m'
      notify: restart sshd

    - name: SSHD | ensure that a client is disconnected after 3 missed response requests
        path:         /etc/ssh/sshd_config
        regexp:       '^ClientAliveCountMax'
        insertafter:  '^#ClientAliveCountMax'
        line:         'ClientAliveCountMax 3'
      notify: restart sshd

    # set either 'volatile' or 'persistent'
    # if you enable the use of persistent journal, then also see
    # https://together.jolla.com/question/4842/how-to-enable-more-detailed-and-persistent-logs-on-jolla-device/
    - name: Ensure journald.conf is NOT set to save to persistent storage
        path:             /etc/systemd/journald.conf
        section:          Journal
        option:           Storage
        value:            volatile
        no_extra_spaces:  True
        backup:           False
      notify: restart systemd-journald

    - name: Ensure journald.conf has a more reasonable setting than the default RuntimeMaxUse=1M
        path:             /etc/systemd/journald.conf
        section:          Journal
        option:           RuntimeMaxUse
        value:            10M
        no_extra_spaces:  True
        backup:           False
      notify: restart systemd-journald

    # While with the ini file entry Storage=persistent, systemd should create the target dir, ensure it is there like the above URL suggests
    # bounce the journald if the directory was changed
    - name: Ensure /var/log/journal is present
        path:   /var/log/journal
        state:  directory
        owner:  root
        group:  systemd-journal
      notify: restart systemd-journald

and then ran it;

pcfe@workstation pcfe.net (master) $ ansible-playbook -l pro1 sailfish.yml

PLAY [SailfishOS config] *****************************************************************************************
TASK [Gathering Facts] *******************************************************************************************
ok: [pro1]

TASK [SSHD | ensure AuthorizedKeysFile is configured] ************************************************************
ok: [pro1]

TASK [SSHD | ensure PasswordAuthentication is off] ***************************************************************
changed: [pro1]

PLAY RECAP *******************************************************************************************************
pro1                       : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Collect Info on the Pro1


Sadly the installed build does not use LVM. Shame I find having it greatly increases my flexibility in dealing with storage.

But at least / and /home/ being on the same partition and large means I do not need to resize as I did on my Gemini PDA and my Xperia SFOS devices.

[root@Pro1 ~]# df -h /home/nemo/
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda8             106G  1.2G  104G   2% /
[root@Pro1 ~]# df -h -x tmpfs -x devtmpfs
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda8             106G  1.2G  104G   2% /
/dev/sda8             106G  1.2G  104G   2% /data
/dev/sda6             3.0G  2.5G  490M  84% /system_root
/dev/sda2              27M  4.1M   22M  16% /mnt/vendor/persist
/dev/sde18            992M  548M  429M  57% /vendor
/dev/sde6              64M  368K   64M   1% /vendor/bt_firmware
/dev/sda6             106G  1.2G  104G   2% /system
/dev/sde9              12M   11M  1.4M  88% /vendor/dsp
/dev/sde5             110M  103M  7.1M  94% /vendor/firmware_mnt
overlay               106G  1.2G  104G   2% /system
overlay               106G  1.2G  104G   2% /system_root/system
/dev/sda8             106G  1.2G  104G   2% /vendor/lib64/librecovery_updater_msm.so
/dev/sda8             106G  1.2G  104G   2% /vendor/bin/netmgrd

While I did not quite expect to see this many block devices, I will not override the vendor’s setup.

[root@Pro1 ~]# lsblk
sda           8:0    0 113.6G  0 disk
|-sda1        8:1    0     8K  0 part
|-sda2        8:2    0    32M  0 part /mnt/vendor/persist
|-sda3        8:3    0     1M  0 part
|-sda4        8:4    0   512K  0 part
|-sda5        8:5    0   512K  0 part
|-sda6        8:6    0     3G  0 part /system_root
|-sda7        8:7    0     3G  0 part
`-sda8        8:8    0 107.5G  0 part /data
sdb           8:16   0     4M  0 disk
`-sdb1        8:17   0     4M  0 part
sdc           8:32   0     4M  0 disk
`-sdc1        8:33   0     4M  0 part
sdd           8:48   0   128M  0 disk
|-sdd1        8:49   0     4K  0 part
`-sdd2        8:50   0     1M  0 part
sde           8:64   0     4G  0 disk
|-sde1        8:65   0   512K  0 part
|-sde2        8:66   0     2M  0 part
|-sde3        8:67   0   512K  0 part
|-sde4        8:68   0   512K  0 part
|-sde5        8:69   0   110M  0 part /vendor/firmware_mnt
|-sde6        8:70   0     1M  0 part /vendor/bt_firmware
|-sde7        8:71   0     4M  0 part
|-sde8        8:72   0    32M  0 part
|-sde9        8:73   0    16M  0 part /vendor/dsp
|-sde10       8:74   0     1M  0 part
|-sde11       8:75   0   512K  0 part
|-sde12       8:76   0    64M  0 part
|-sde13       8:77   0     8M  0 part
|-sde14       8:78   0    64K  0 part
|-sde15       8:79   0   512K  0 part
|-sde16     259:0    0   512K  0 part
|-sde17     259:1    0   128K  0 part
|-sde18     259:2    0     1G  0 part /vendor
|-sde19     259:3    0   512K  0 part
|-sde20     259:4    0     2M  0 part
|-sde21     259:5    0   512K  0 part
|-sde22     259:6    0   512K  0 part
|-sde23     259:7    0   110M  0 part
|-sde24     259:8    0     1M  0 part
|-sde25     259:9    0     4M  0 part
|-sde26     259:10   0    32M  0 part
|-sde27     259:11   0    16M  0 part
|-sde28     259:12   0     1M  0 part
|-sde29     259:13   0   512K  0 part
|-sde30     259:14   0    64M  0 part
|-sde31     259:15   0     8M  0 part
|-sde32     259:16   0    64K  0 part
|-sde33     259:17   0   512K  0 part
|-sde34     259:18   0   512K  0 part
|-sde35     259:19   0   128K  0 part
|-sde36     259:20   0     1G  0 part
|-sde37     259:21   0    16K  0 part
|-sde38     259:22   0     4K  0 part
|-sde39     259:23   0     1M  0 part
|-sde40     259:24   0   256K  0 part
|-sde41     259:25   0   256K  0 part
|-sde42     259:26   0     4K  0 part
|-sde43     259:27   0  32.7M  0 part
|-sde44     259:28   0     4K  0 part
|-sde45     259:29   0     1M  0 part
|-sde46     259:30   0     8M  0 part
|-sde47     259:31   0     2M  0 part
|-sde48     259:32   0    64M  0 part
`-sde49     259:33   0   128K  0 part
sdf           8:80   0   1.5G  0 disk
|-sdf1        8:81   0     2M  0 part
|-sdf2        8:82   0     2M  0 part
|-sdf3        8:83   0     2M  0 part
`-sdf4        8:84   0     4K  0 part
mmcblk0     179:0    0  29.8G  0 disk
`-mmcblk0p1 179:1    0  29.8G  0 part
zram0       253:0    0     1G  0 disk [SWAP]

RAM Available to SFOS

[root@Pro1 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:          5.6Gi       1.4Gi       3.3Gi        23Mi       895Mi       4.1Gi
Swap:         1.0Gi          0B       1.0Gi


[root@Pro1 ~]# lscpu
Architecture:        aarch64
Byte Order:          Little Endian
CPU(s):              8
On-line CPU(s) list: 0-7
Thread(s) per core:  1
Core(s) per socket:  4
Socket(s):           2
Vendor ID:           Qualcomm
Model:               4
Model name:          Kryo V2
Stepping:            0xa
CPU max MHz:         2457.6001
CPU min MHz:         300.0000
BogoMIPS:            38.40
L1d cache:           32K
L1i cache:           32K
L2 cache:            1024K
Flags:               fp asimd evtstrm aes pmull sha1 sha2 crc32


[root@Pro1 ~]# uname -a
Linux Pro1 4.4.153-perf+ #12 SMP PREEMPT Mon Jan 20 11:37:27 CET 2020 aarch64 aarch64 aarch64 GNU/Linux

OS Customisations

Since I expect these to be part of the build soon, not in Ansible for now.

Replace Boot Splash

Done as per this tjc post.

Not planned to add in Ansible playbook unless I find a module that handles writing to a raw device, but even then doubtful. I will mosty certainly not do dd with the command or shell module.

HW Keyboard US-international

Done as per this tjc post I chose US, intl., with AltGr dead keys (custom version with extra characters).

Automatic Keyboard Backlight (automatic using mce)

I chose the automatic using mce mode as per this tjc post.

Hardware decoding of h.264 and h.265 (hevc) videos in native SFOS applications

As per this tjc post.

Left Unchanged

Using OpenRepos.net

First install File Browser, then Storeman. Simply follow the Guide: Sailfish X on Xperias. Thanks olf!

Install Patchmanager 3.0

As per Guide: Sailfish X on Xperias.

Patches Installed

  • Lockscreen Analog Clock by Ancelad
  • Ultimate statusbar patch by Anceland

The Analog Clock one allows for lock screen customisation, including a digital clock. The statusbar patch is installed but not enabled for now.

Test Results

The following functionality has been tested so far. I’ll amend the list as I use the device.

  • incoming call answered on handset, no issue, good audio quality (2020-02-01)
  • outgoing call initiated on handset, also fine
  • inbound SMS, no issue
  • GPS, got a fix after the expected while (I did expect first fix to take a whiel) and was able to navigate with Pure Maps
  • calDAV and cardDAV sync, no issues doing an initial sync with Kolab Now

Tests to run

  • phone calls with Bluetooth headset

Adaptations repo to contribute to