Christians Tagebuch: android

The latest posts in full-text for feed readers.


Open Source Android collage creator

I finally found an open source Android application to create image collages (combining several images/photos into a single one): Image Toolbox. The source code is available on Github, the app is installable via F-Droid

Photo collage created with Image Toolbox

Image Toolbox's collage maker tool is available under Create -> Collage Maker. It lets you create collages from 2-10 images and has many layout options which can be switched on the fly.

You can zoom and rotate the single image's contents and move the visible image clip. Switching images with each other is no problem. The final image's aspect ratio can be changed, as well as the border radius, border color and output format.

Screenshot #1: Place and zoom images Screenshot #2: Collage settings

Published on 2025-05-18 in


Open Android contact addresses with OsmAnd

My Android phone runs the open source LineageOS (MicroG-flavored) and I use OsmAnd for maps and navigation.

One thing that bothered me was that when clicking addresses in the system "contacts" address book, the browser would open with Google maps - instead of OsmAnd, which would be much more helpful.

The solution is to let OsmAnd handle links to the maps.google.com domain:

  • Open apps menu
  • Long-press OsmAnd icon -> Click App info
  • Click Open by default
  • Click Add link
  • Checking for other supported links will take some sime
  • Scroll through the unsorted list until you find maps.google.com and select it
  • Click Add

Now contact addresses will open in OsmAnd.

OsmAnd app information: Open by default Checking for other supported links List of domains

Also on: Reddit.

Published on 2025-03-01 in


Restoring OUYA game purchases

With a bit of setup work, you can again play all the games you bought on your OUYA gaming console.

Back to trial

When the OUYA server shut down in July 2019, many users noticed that the games they paid for now went back to demo/trial mode:

So I just hooked up my ol' Mad Catz M.O.J.O., and was pretty surprised to find that a vast majority of my games that I purchased through the Ouya store no longer work, and act like I've never purchased them

(Sonic 4 episode 1, for example, just launches the "Trial" version now).

glow162, 2019-11-16 on reddit

Soul Power is one of my paid Ouya games that reverted to demo mode since the servers went down.

Would it be possible to recieve a different, working, version of the game if I show you my Ouya receipt?

Starfig the boyo, 2019-08-22 on Twitter

@x10interactive Hi! The Ouya version of So Many Me isn't working anymore, it's reverted to demo mode!

Starfig the boyo, 2019-08-21 on Twitter

Would it be possible to release some kind of patch to play Evocreo on the Ouya?

I bought a copy and no longer have access to it after the server shutdown

Chance Crane, 2019-08-22 on Twitter

@SquareEnixFR @SquareEnixMtl @SquareEnix @SquareEnixUSA

After #ouya shutdown, How can I keep playing Final Fantasy 3 as I bought it and the DRM now keeps me off ? Thanks.

LC, 2019-07-27 on Twitter

A long while back, I bought the Final Fantasy 3 remake on the Ouya. I really enjoyed it and got all the way up to the final dungeon. Things happened and I wasn't able to play it for a long time.

Then Razer shut down the Ouya servers and the game stopped working.

E. Zachary Knight 2019-12-02 on Twitter

I did buy Babylonian Twins and that one also went back to demo mode.

The shutdown casualty list thread on the OUYA Forum lists many games that reverted back to demo mode.

Nice developers

Some developers were very gracious and published a final game update before the store shut down that removed the DRM code and made the game fully free to play.

List of games I know got a final unlock release:

I'm very thankful for them doing that.

Other developers could not do that for various reasons. I contacted the developers of Bloo Kid 2. They would like to have helped me, but the machine that was used to develop and compile Bloo Kid 2 for Android/OUYA crashed and could not be restored :/

Purchases

OUYA's own Purchasing documentation describes how purchases happen on the OUYA:

  1. Game starts up and fetches previous purchases (receipts) from the store
  2. If the game has not yet been bought and the user clicks "buy", a purchase request is sent to the server. The server responds with yes/no and the game unlocks from demo to full version. The purchase is stored on the server and added to the list of receipts.

Encryption

OUYA's creators wanted to make it very hard to tamper with the purchase process. Purchase requests are sent encrypted to the server, and receipt responses are encrypted twice.

For that they needed two kind of key pairs:

Gamer key
Upon registration, the user's OUYA generates a private and a public RSA key. It sends the public key to the server that stores it.
Developer key (game key)
When a game is registered in the developer portal, a private key is generated for this game, and the developer gets the public key. It will be compiled into the game.

When buying a game, the purchase request is AES-encrypted. The AES key itself is encrypted with the game's public key. The store server has the private game key and can decrypt it.

The receipt list is encrypted twice: Data themselves are encrypted with the public gamer key, and the console has the private key to decrypt it. The second "inner" encryption was made with the private developer/game key, and the in-game public key is used to decrypt it (that is reverse to what private and public keys are normally used, but it works somehow).

The problem for my own OUYA server is that I do not possess the private keys of all of the 1200 games. I am not able to decrypt the purchase requests, and not able to encrypt the receipt lists in a way that the game can decrypt them.

Patching

I might not able to break purchasing, but I could unlock the individual games.

Bloo Kid 2

Bloo Kid 2 was the first game I tried. I already knew where to look for and modified isFullVersion in the smali code to always return true. Then I re-compiled the smali code, created the .apk and signed it.

But now I had the problem that my signature was different from the original signature, and Android refused to install the new game version over the old one. Even uninstalling the game while keeping the data (pm uninstall -k) did not work; Android refused to install the modified game with the new signature as long as it had data for the original signature :/

This would mean that people would lose all their progress and settings.

Comment by Jesús Higueras: At least on regular Android devices you can run pm uninstall -k and then restart the device. The data will still be there but the signature will no longer be cached, so you'll be able to install your modified version on top without losing data.

Babylonian Twins

Each game has a "purchase success" and an equal "purchase failure" handler. My idea was that upon game start, I would call the purchase success code with the right product key and be done with it.

I did that, and the game crashed - inside the C code that I could not inspect so easily. I even installed Ghidra to be able to look into the C code.

It took me three evenings to get the game to the point that it actually worked. The solution was to call the purchase success method from the purchase failure handler :) When calling it directly on startup, some things in the C code were not yet initialized and that caused the crash.

Here again I faced the impossible-to-upgrade and the keep-my-savegames problem.

I stopped the work because patching individual games does not scale.

Nocryption

The OUYA saviors very early had the idea to use Xposed to overwrite OuyaEncryptionHelper methods and prevent them from doing any encryption/decryption.

Unfortunately this helper is compiled into every application, and more often than not obfuscated with methods names like a.a.a.d.c. We would need a list that mapped that class name for each of the games, which would mean a lot of manual work.

While reading through the decompiled OUYA Framework source code and the game-specific implementations I saw something:

Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding");
instance.init(2, secretKeySpec, ivParameterSpec);
receipts = new JSONObject(new String(instance.doFinal(decode), "UTF-8"));

The framework and every game used Java's Cipher.doFinal(byte[] input) to actually execute the encryption or decryption operation. If it was possible to let doFinal() return the input bytes unmodified, then my server would get plain text purchase requests and could return plain text receipts!

It took a whole day of installing Xposed on the OUYA, learning how to build an Xposed module and write a pre-execution hook for Cipher.doFinal. The actual code is disappointing:

XposedHelpers.findAndHookMethod(Cipher.class, "doFinal", byte[].class, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) {
        byte[] input = (byte[]) param.args[0];
        param.setResult(input);
    }
});

The result was this:

Bloo Kid 2: Main menu Bloo Kid 2: Purchase confirmation Bloo Kid 2: Thanks for supporting winterworks GmbH! "Purchased" in OUYA's system menu

And all this without modifying the game apk itself! The savegames are safe!

How to use

Using my "plain-purchases" xposed module currently takes a bit of work:

  1. Follow the Root the OUYA instructions until you have the following:

    1. SuperSU (required by Xposed installer)
    2. Xposed installer with activated Xposed framework

    (Both are also available in Make -> Tutorials).

    Do not install ModCollection nor Google Play (they are not needed, but do no harm when installed).

  2. Download and install my ouya-plain-purchases xposed module. (Also available in Make -> Tutorials).
  3. Activate it in the Xposed installer by going to "Modules" and then use the touchpad to click the checkbox that activates the plain purchases module. The controller buttons cannot be used to activate the module.
  4. Reboot
  5. Configure your OUYA to use my server or Devin's server.

Xposed is enabled. All is fine. Xposed is not activated yet. This is not good. Xposed is not activated yet #2. Click 'Install/Update' Xposed module "OUYA plain purchases"

You may now enjoy all your OUYA games in their full glory again, half a year after the official server shutdown.

To unlock Final Fantasy III, the module needs to be installed as a system app.

Install xposed and the plain purchases module onto internal storage and not onto USB.

Takedown!

If you are a game developer and do not want your game unlocked on the couple of dozen OUYAs that are left on the world, send me an e-mail and I will remove the purchase receipt from my server. The game will then fall back to demo mode on all OUYAs.

Also on: Twitter, ouya.world.

Published on 2020-01-04 in ,


Android 4 controller problems

The OUYA was known for providing a custom input handling system, because the standard Android 4.1 one was not sufficient.

I never knew the exact cause, but yesterday I stumbled upon the archived PlayJam Games Network Controller Guidelines - it lists the bugs in detail:

1. D-pad event misidentification

Due to an overly simplistic implementation of the dpad translation code in Android, (up to and including Android 4.4), using onKeyDown() and onKeyUp() events with multiple controllers is not recommended. While onKey*() events work acceptably for single controllers, when multiple controllers are used it is possible for events from one controller to be misidentified as coming from another.

2. Controller identification

Android provides several different methods for identifying controllers, however they are not all equal in terms of functionality:

InputDevice.getId()
  • Guaranteed unique for the current power cycle
  • Not stable – They are simple incrementing integers that are assigned to each device as it connects – even if it is a device that has already been connected – as such it is guaranteed that a different value will be returned for a controller before and after a power cycle of that controller, (i.e. if it disconnects, its getId() will change).
InputDevice.getDescriptor()
  • Stable – The value for any controllers will stay the same through power cycles of the controller and/or the platform – the value itself is derived from physical properties of the device.
  • Not guaranteed unique – As the value is derived from a set of physical parameters of the device, it is possible for devices which share the same set of parameters to return the same value. This is generally not a problem for Bluetooth devices, as the MAC address of the Bluetooth client is part of the input to the id generator.
InputDevice.getName()
  • PlayJam provides managed naming of controllers – in that the controller with a specific player lit up will remain the same name – so the controller with light one on, (Player 1), will always return the device name of “GameStick Controller 1”. Note that the order of light assignment is currently related to the power up order of controllers – so turning off controllers and repowering in a different order will result in name changes – however the controller itself will still show the correct light for its name, (making the assignment clean to the user).

I guess that the OUYA developers implemented something like the GameStick people, which meant that all games that wanted to support multiple controllers had to use the OUYA SDK, or do all the work themselves.

Published on 2024-12-06 in


media.ccc.de extension for Miru app

I wanted to watch Chaos Communication Congress lecture videos during lunch, but found no Android app that would store which talks I had already seen and the progress in each video.

I only found one open source video app in the F-Droid repository that allows extensions: Miru. So I decided to build an extension for the media.ccc.de service that hosts the congress videos.

It was hard to get Miru running on the desktop, and in the end I had to patch it to get it compile on my machine.

The extension documentation lacked quite a bit in depth and I had to find out many things on my own by looking at other extensions and miru's source code.

After a day of work, I submitted the media.ccc.de extension for inclusion into the official extension repository, and it got merged only a few hours later.

Miru's navigational structure (List > TV Series details > Play) did not really fit the media.ccc.de structure, and I had to compromise quite a bit - details of talks are non-existent when viewed from the events detail page. Searching for talks gives much more details, though - but does not let you filter for a certain congress.

NewPipe

When writing the patch that adds Miru to the list of apps, I saw that NewPipe already supports media.ccc.de - I just did never notice it!

Screenshots

Miru overview Conference list Conference details #1 Conference details #2 with format selection Playing a video Filter window Searching conferences Searching lectures/talks Filtering lectures Lecture details #1 Lecture details #2

Published on 2024-11-25 in


Android 14: Modify system partitions

I own a Fairphone 4 with the stock camera apk that I extracted from official firmware in 2023-11. In 2024-04, Fairphone released a major camera update and I wanted to get it on my LineageOS-based system.

Problem

A forum post describes that the .apk extracted from the firmware fails to install:

adb: failed to install FPCamera.apk:
 Failure [
  INSTALL_FAILED_MISSING_SHARED_LIBRARY: Reconciliation failed...:
  Reconcile failed:
  Package com.fp.camera requires unavailable native shared library libtctcameraalgo_jni.tct.so;
  failing!]

The new camera app (v7.00.04.0007.7.0)requires a shared library that is not available on my LineageOS firmware.

Extracting libtctcameraalgo_jni.tct.so

I extracted the current FP4-TP2L-factory.zip firmware image just as described in my previous blog post with unzip, simg2img and lpunpack. Then I mounted all partitions and looked into their file lists; it was system_ext that contained the library at

system_ext_a/lib64/libtctcameraalgo_jni.tct.so

(40kiB, md5 hash 3daaf896f43a33c7a883f57c7c4be3d5).

How not to modify the system partition

After running adb root I remounted the system_ext partition to be writable:

$ adb shell mount -o rw,remount /system_ext

This was how you did it in the pre-Android 10 days, and it does not work anymore because of dynamic Android partitions which are just as large as they need to be to contain the data:

$ adb push libtctcameraalgo_jni.tct.so /system_ext/lib64/
libtctcameraalgo_jni.tct.so: 1 file pushed, 0 skipped. 53.5 MB/s (40792 bytes in 0.001s)
adb: error: failed to copy 'libtctcameraalgo_jni.tct.so' to '/product/lib64/libtctcameraalgo_jni.tct.so': remote write failed: No space left on device

$ adb shell
FP4:/ # df -h /system_ext/
Filesystem      Size Used Avail Use% Mounted on
/dev/block/dm-3 392M 390M  1.2M 100% /system_ext

I opened a thread on reddit and was told by TimSchumi that I should use adb remount. That command creates overlayfs mounts that lets you modify the system partitions by modifying an "overlay" directory, which is then loaded onto the actual partition.

I also found the magic_overlayfs Magisk module, but deemed that using native tools would be easier. It had a nice short explanation for the problem, though:

On Android 10+, system partitions might no longer be able to remount as read-write. For devices using dynamic partitions, it is nearly impossible to modify the system partiton as there is no space left.

Remounting

$ adb remount
AVB verification is disabled, disabling verity state may have no effect
Using overlayfs for /system
Using overlayfs for /system_ext
Using overlayfs for /product
Using overlayfs for /vendor
Using overlayfs for /odm
[libfs_mgr] __mount(target=/system,flag=MS_PRIVATE)=-1: Invalid argument
Remounted /system as RW
Remounted /system_ext as RW
Remounted /product as RW
Remounted /vendor as RW
Remounted /odm as RW
Remounted /vendor/dsp as RW
Overlayfs enabled.
Remount succeeded
Now reboot your device for settings to take effect

Simply rebooting, creating the lib64 directory in the upper layer of the overlay and pushing the .so file into it did not work:

$ adb reboot
$ adb shell mkdir /mnt/scratch/overlay/system_ext/upper/lib64/
$ adb push libtctcameraalgo_jni.tct.so /mnt/scratch/overlay/system_ext/upper/lib64/
$ adb shell
FP4:/ $ ls /system_ext/lib64
ls: /system_ext/lib64: Operation not permitted
1|FP4:/ $ ls -lah /system_ext/
total 63
drwxr-xr-x  2 root root  4.0K 2009-01-01 01:00 lib
d?????????  ? ?    ?        ?                ? lib64

FP4:/ $ ls -lah /system_ext/lib64/
total 5.0K
drwxrwxrwx 1 root root 3.4K 2024-11-13 21:49 .
drwxr-xr-x 1 root root 3.4K 2024-11-13 21:46 ..
-rw-r--r--  1 root root 256K 2009-01-01 01:00 com.qualcomm.qti.dpm.api@1.0.so
-rw-r--r--  1 root root 141K 2009-01-01 01:00 lib-imsvideocodec.so
-rw-r--r--  1 root root 259K 2009-01-01 01:00 lib-imsvt.so
-rw-r--r--  1 root root  15K 2009-01-01 01:00 lib-imsvtextutils.so
-rw-r--r--  1 root root  32K 2009-01-01 01:00 lib-imsvtutils.so
[...]
-????????? ? ?    ?       ?                ? libtctcameraalgo_jni.tct.so

After modifying the upper layer directory, I had to reboot the phone every time to make Android see the changes properly. The reboots fixed the permission problems.

Library registration

When libtctcameraalgo_jni.tct.so was at the right place, installation still failed with

Package com.fp.camera requires unavailable native shared library libtctcameraalgo_jni.tct.so

I then read that libraries need to be registered - pm list libraries did not list it.

In order to add library to vendor partition, you need to create text file which lists all added libraries. Since Android N (7.0) or later, apps are only allowed to access libraries on a specific whitelist of NDK libraries.

We can create counterpart file for vendor and create it in following path: /vendor/etc/public.libraries.txt.

I moved the library from system_ext/lib64 to vendor/lib64/ because that one already had a etc/public.libraries.txt that I could modify:

$ adb shell
1|FP4:/mnt/scratch/overlay/vendor/upper/etc # echo libtctcameraalgo_jni.tct.so >> public.libraries.txt

Then I rebooted, and all broke down. The phone was stuck at the "Fairphone" boot logo and would not advance any further.

Things I tried

Fastboot and recovery were available, but I did not find a way to disable the remount overlays from there.

The previously linked Implement dynamic partitions writes

For developers using eng or userdebug builds, adb remount is extremely useful for fast iteration. Dynamic partitions pose a problem for adb remount because there is no longer free space within each file system. To address this, devices can enable overlayfs. As long as there is free space within the super partition, adb remount automatically creates a temporary dynamic partition and uses overlayfs for writes. The temporary partition is named scratch, so don't use this name for other partitions.

I tried to delete the partition with fastboot, but that did not help:

$ fastboot delete-logical-partition scratch
Deleting 'scratch'                                 OKAY [  0.009s]
Finished. Total time: 0.009s

In recovery adb, I also tried to delete the scratch partition but did not even find it. lptools_new allows to list dynamic partitions:

FP4:/ # lptools_new_arm64  --get-info
Slot: 0
Suffix: _b
Path to super: /dev/block/by-name/super
Group: qti_dynamic_partitions_b
Arguments: --get-info

GroupInSuper->qti_dynamic_partitions_b Usage->5422981120 TotalSpace->6441402368
NamePartInGroup->odm_b Size->1589248
NamePartInGroup->product_b Size->617897984
NamePartInGroup->system_b Size->971485184
NamePartInGroup->system_ext_b Size->416059392
NamePartInGroup->vendor_b Size->699158528

FP4:/ # lptools_new_arm64  --get-info --group cow
Slot: 0
Suffix: _b
Path to super: /dev/block/by-name/super
Group: cow
Arguments: --get-info

GroupInSuper->cow Usage->5422981120 TotalSpace->6441402368
NamePartInGroup->odm_b-cow Size->1601536
NamePartInGroup->product_b-cow Size->620318720
NamePartInGroup->system_b-cow Size->975286272
NamePartInGroup->system_ext_b-cow Size->417689600
NamePartInGroup->vendor_b-cow Size->701894656

Listing the partitions with fastboot is not directly possible, but partitions can be inferred from the variables:

$ fastboot getvar all
(bootloader) partition-size:super:0x180000000
[...]
(bootloader) partition-type:product_b:raw
[...]

No scratch there, though.

Bitter end

After 3 days I decided to give up and reinstalled the whole operating system. The SeedVault backup automatically reinstalled most applications, but unfortunately some of the applications I use do not support backing up their data:

Conversations did support backups, though.

Published on 2024-11-17 in


Fairphone 4 problems

I'm using a Fairphone 4 smart phone, running the MicroG-enabled LineageOS instead of the default software (ROM).

Unfortunately, the phone has several shortcomings:

Ghost inputs

Sometimes the touch screen triggers scrolls, swipes and zoom gestures without anyone touching it.

Thousands of FP4 users had this problem, and it was fixed in the official Fairphone software version Fairphone OS version B.086:

Ghost touches: an issue that causes the user interface to move or jump without touching the screen.

Unfortunately the fix is not available on LineageOS 20 (2024-01-05), which means I still experience the problem.

I once disassembled the phone, "cleaned" the display contacts by blowing onto it and re-assembled it. Afterwards the ghost touches appeared less often.

Enabling "touch visualization" in the Android developer settings gave me this screenshot of ghost inputs:

Fairphone 4 ghost input screenshot

Touch screen does not work without touching the frame

Sometimes the touch screen does not work (does not recognize touches) when the phone is lying flat on a table or my lap. When touching the frame it becomes responsive again.

Other people also reported this problem:

All we know is that there is some empirical evidence that the FP4’s touchscreen now requires the phone to be connected to some larger conductive body to reliably work – Either the user also touching the phone’s chassis, or the phone being connected to something else by its USB cable (like while charging it).

KurtF, 2023-08-26, Software update: FP4.SP2J.B.086.20230807

The Fairphone 3 already had this problem:

Seit ich das FP3+ habe funktioniert das Touch Display nicht, wenn ich es auf den Tisch lege. Wenn ich es in die Hand nehme, ist alles in Ordnung.

Lotta_Hund, 2021-05-06, FP3+ Touch Display funktioniert nicht, wenn es liegt

Bad speaker sound

I can't listen to podcasts via the Fairphone 4's built-in speakers because the sound is awful. My ring tone and message notification sounds also sound very tinny.

This hardware problem is known and acknowledged by the Fairphone developers:

Time to call it. It’s a hardware problem that we could mitigate in software by artificially reducing the volume of the top speaker. We believe that a blanket volume reduction will be perceived negatively by the majority of users, so we opted to leave it as it is.

The workaround described above (Accessibility Settings > Mono > balance all the way to the left) works in most cases. [...]

We’ve learned a lot from this investigation and we’ll use these lessons when designing future products.

Yasen_Tomov, 2023-06-08, Check for and replace blown speaker

For me the workaround is to use the Android accessibility settings to downmix all sounds to mono and move them to the right speaker (bottom of the phone), completely bypassing the right speaker (top of the phone).

Accessibility settings (German: Bedienungshilfen) Sound adjustments (German: Audioanpassung)

Bad compass

I love to use SkyMap (F-Droid) to see which stars are visible in the sky at night.

Unfortuantely the compass on the Fairphone 4 is so bad that the map just jumps around and shows a totally different direction when rotating the phone for a couple of degrees.

Compass app on Fairphone 4 #1: 149° Compass app on Fairphone 4 #2: 264°

As usual, other people have the same problem:

In almost all cases, the orientation error ranges from 45 to 180 degrees.

ChristianH, 2023-01-25, FP4: The compass is unreliable

Moving the phone in a "8"-pattern several times while Skymap or the compass app is open did improve accuracy quite a bit, but I have to recalibrate every time I use Skymap.

Compass calibration pattern

Published on 2024-02-25 in ,


Fairphone 4: Stock camera on LineageOS

I bought a used Fairphone 4 and installed LineageOS with MicroG on it after unlocking the bootloader. One of the original Fairphone apps I wanted to use was the stock camera app "FPCamera.apk" (com.fp.camera). At first I extracted it from the official firmware download FP4-TP1V-factory.zip with the help of simg2img (from android-sdk-libsparse-utils) and lpunpack:

$ unzip FP4-TP1V-factory.zip images/super.img
$ file super.img
super.img: Android sparse image, version: 1.0, Total of 1572864 4096-byte output blocks in 226 input chunks.

$ simg2img super.img super.nonsparse.img
$ file super.nonsparse.img
super.nonsparse.img: data
$ binwalk super.nonsparse.img
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1048576       0x100000        Linux EXT filesystem, blocks count: 277, image size: 283648, rev 1.0, ext2 filesystem data, UUID=f9a4283a-08b7-55e3-b63b-e404b5acb5ac, volume name "odm"
[...]

$ lpunpack super.nonsparse.img extracted
Extracting partition [odm_a] .... [ok]
Extracting partition [odm_b] .... [ok]
Extracting partition [product_a] .... [ok]
Extracting partition [product_b] .... [ok]
Extracting partition [system_a] .... [ok]
Extracting partition [system_b] .... [ok]
Extracting partition [system_ext_a] .... [ok]
Extracting partition [system_ext_b] .... [ok]
Extracting partition [vendor_a] .... [ok]
Extracting partition [vendor_b] .... [ok]

$ cd extracted
$ file system_a.img
system_a.img: Linux rev 1.0 ext2 filesystem data, UUID=2aa70c42-cce6-5610-9956-5fcc24a421ec (extents) (large files) (huge files)

$ mkdir system_a
$ sudo mount -o ro system_a.img system_a
$ cp system_a/system/priv-app/FPCamera/FPCamera.apk .

Then I installed FPCamera.apk onto the LineageOS Fairphone with adb install. Upon starting the camera app, I asked for some permissions and then said:

Permissions denied. You can change them in Settings > Apps.

I already had given it all permissions it asked for and that were selectable: Camera, Microphone, Location.

adb logcat showed that it asks for another permission WRITE_EXTERNAL_STORAGE:

CAM_PermissionUtils: checkPermissions, [android.permission.WRITE_EXTERNAL_STORAGE]
ActivityTaskManager: START u0 {act=android.content.pm.action.REQUEST_PERMISSIONS pkg=com.android.permissioncontroller cmp=com.android.permissioncontroller/.permission.ui.GrantPermissionsActivity (has extras)} from uid 10190
CompatibilityChangeReporter: Compat change id reported: 174042980; UID 10190; state: DISABLED
CAM_QuickActivity: onCreate return,  by permission check!

It turns out that Android 13 does not allow apps to ask for that permission anymore as described in Android Developers: Granular media permissions and WRITE_EXTERNAL_STORAGE:

Note: If your app targets Build.VERSION_CODES.R (Android 11) or higher, this permission has no effect.

So the Fairphone camera app has a higher target but the code was not adjusted - on the Fairphone OS, this is not needed because Camera is a system app with pre-allowed permissions in system/etc/permissions/privapp-permissions-platform.xml.

The solution is to manually give the permission via adb:

$ adb shell pm grant com.fp.camera android.permission.WRITE_EXTERNAL_STORAGE

The Fairphone Camera app expects "Google Photos" to be installed, otherwise you cannot view the taken photos. Installing the camera proxy app solved that problem.

Screenshot of the Fairphone 4 stock camera app

Published on 2023-11-11 in


Unlocking Final Fantasy III on OUYA

One of the few OUYA games that my ouya-plain-purchases Xposed module did not unlock was Final Fantasy III: Its developers wrote code that makes the game crash when a running Xposed module is found.

Now nearly two years after my investigation, OUYA Saviors member ZacharyFoxx found a solution: Convert the Xposed module from a normal user-installed app into a system app.

The only difference between them is that user applications are installed in /data/app/, while system apps are located in /system/app/. The /system/ partition is mounted read-only on the OUYA, so it takes some more steps to move it.

HowTo

If plain purchases is not already installed, use the OUYA interface and go to Make > Tutorials and install it.

If you already enabled the plain purchases module, you have to disable it at first in the Xposed settings.

Now connect your OUYA via USB to your computer and use adb to execute the following steps:

$ adb shell
$ su
$ mount -o rw,remount -t ext4 /dev/block/platform/sdhci-tegra.3/by-name/APP
$ cp /data/app/de.cweiske.ouya.plainpurchases-1.apk /system/app/
$ rm /data/app/de.cweiske.ouya.plainpurchases-1.apk
$ mount -o ro,remount -t ext4 /dev/block/platform/sdhci-tegra.3/by-name/APP
$ exit
$ exit
$ adb reboot

The issue can finally be closed.

Update 2023-11: One user mentioned that he had to disable the OUYA Xposed "Mod Collection" to get it working (after rebooting).

Published on 2023-01-10 in , ,


Blackview BV4900S

I got a used Blackview BV4900S Android smartphone and wanted to prepare it properly so it can be used.

Reinstalling original firmware

Firmware download

The Blackview website does not have a download section: I had to contact customer support via e-mail (customerservice1@) to get the firmware file and installation tool.

They sent a link to the firmware file BV4900s_EEA_L620_V1.3_20220518V10 - uploaded to Mega instead of their own website... Another link was for the firmware install tool UpgradeDownload_R26.21.4101.7z. The instructions they sent were for a different tool, though.

Flash tool

The BV4900S has a Spreadtrum Unisoc SC9863A chipset, unlike the BV4900 and BV4900 Pro which both have a MediaTek chipset.

The official tool to flash .pac firmware files on Unisoc phones is SPD Flash Tool, the executable is named UpgradeDownload.exe.

On Windows 7 I had to install the Spreadtrum SPD drivers that I got from AndroidFileHost: SPD_Driver_R4.20.4201.zip. The SPD Flash Tool site has them as well, but their download was abysmal slow.

The official SPD version SPD_Upgrade_Tool_R27.23.1902.zip did not work on my Windows 7 installation; it failed with CFWDL-driver error. Instead I used the SPD version R26.21.4101 I got from Blackview, which worked fine.

The installation steps were:

  1. Install SPD drivers
  2. Extract SPD Flash Tool and run UpgradeDownload.exe
  3. Load the .pac file
  4. Click the "Play" button in SPD Flash Tool
  5. On the off-state phone, hold Power and Volume Down with one hand and then plug in the USB cable.
  6. Flashing will start automatically; you will see a progress bar in the tool.

SPD Flash Tool: Downloading SPD Flash Tool: Done

When loading a .pac file, SPD Flash Tool actuall extracts its contents into a subdirectory, in my case PAC_s9863a1h10_DownloadFiles_BV4900s_EEA_L620_V1.3_20220518V10_718_19C9C_0:

BV4900s_EEA_L620_V1.3_20220518V10.pac contents
boot.img
cache.img
dtbo.img
fdl1-sign.bin
fdl2-sign.bin
FileList.ini
gnssbdmodem.bin
gnssmodem.bin
odmko.img
PackInfo.csv
persist.img
PM_sharkl3_cm4_v2.bin
prodnv.img
s9863a1h10.xml
SC9600_sharkl3_pubcp_modem.dat
sharkl3_cm4.bin
sharkl3_pubcp_deltanv.bin
sharkl3_pubcp_DM_DSP.bin
sharkl3_pubcp_LTEA_DSP.bin
sharkl3_pubcp_nvitem.bin
sml-sign.bin
socko.img
super.img
teecfg-sign.bin
tos-sign.bin
u-boot-sign.bin
u-boot-spl-16k-sign.bin
unisoc_HD_720_1440_24bit.bmp
'unisoc_HD_720_1440_24bit.bmp(1)'
userdata.img
vbmeta_product.img
vbmeta-sign.img
vbmeta_system_ext.img
vbmeta_system.img
vbmeta_vendor.img

s9863a1h10.xml contains the partition list.

Rooting BV4900S

Being a cheap chinese smart phone, there is no Lineage OS port for it. So I had to take the stock firmware, but at least wanted root access to I could install an ad blocker.

I wanted to install Magisk to get root. The boot image was extracted by SPD Flash Tool, and the Magisk App was able to patch the boot image. But: Flashing the boot image is not possible.

Fastboot

I found two ways to access fastboot:

  1. Enable ADB via the Android system preferences developer settings. Then run adb reboot fastboot.
  2. When the phone is powered off, hold Power and Volume up until the Blackview logo appears. You are in recovery mode now. From there you can switch to fastboot.

recovery on BV4900S fastboot on BV4900S

Unlocking bootloader

Flashing the boot image fails because the boot loader is locked:

$ fastboot flash boot ../magisk_patched-26300_weTYA.img
Sending 'boot_a' (65536 KB)                        FAILED (remote: 'Download is not allowed on locked devices')
fastboot: error: Command failed

In Android developer settings I enabled "OEM unlocking" and then tried to unlock the bootloader, but all commands failed:

$ fastboot flashing unlock
FAILED (remote: 'Unrecognized command flashing unlock')
fastboot: error: Command failed

$ fastboot flashing unlock_critical
FAILED (remote: 'Unrecognized command flashing unlock_critical')
fastboot: error: Command failed

$ fastboot getvar unlocked
unlocked: no

Other Spreadtrum devices could be unlocked by fetching some token and signing the custom firmware with it. The command does not work on this phone:

$ fastboot oem get_identifier_token
...
OKAY [  0.001s]
finished. total time: 0.001s

$ fastboot oem invalidcommand
...
OKAY [  0.001s]
finished. total time: 0.001s

Blackview support says they do not support unlocking their devices. I asked on XDA for help but don't really expect any outcome.

For now I am stuck; the BV4900S cannot be unlocked.

USB IDs

dmesg output:

Normal USB IDs
usb 1-2: new high-speed USB device number 63 using xhci_hcd
usb 1-2: New USB device found, idVendor=18d1, idProduct=4ee8, bcdDevice= 4.04
usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-2: Product: BV4900s
usb 1-2: Manufacturer: Chinoe
usb 1-2: SerialNumber: BV4900sEEA00001817
Fastboot USB IDs
usb 1-2: new high-speed USB device number 64 using xhci_hcd
usb 1-2: New USB device found, idVendor=1782, idProduct=4ee0, bcdDevice= 4.14
usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-2: Product: Unisoc Phone
usb 1-2: Manufacturer: Unisoc
usb 1-2: SerialNumber: BV4900sEEA00001817

Published on 2023-10-22 in ,