Christians Tagebuch: ouya

The latest posts in full-text for feed readers.


Exclusive OUYA games

I collected a list of all games that were exclusively released on the OUYA gaming console.

All-time exclusives

Games that have never been ported to any other system - you need an OUYA to play them. Find them in the Exclusive category on my OUYA server.

Once exclusive

Games that were for some limited time only available on the OUYA, but got released on other platforms later. Find them in the VIP room category on the OUYA server.

Game name Other Platforms Source Notes
Amazing Frog PC (Steam) 15, 17, 18
Broken Age PC (Steam), Playstation, Apple App Store, Google Play 1 Only console on launch day
Chrono Blade Apple App Store, Google Play 14, 15 Demo only
Deep Dungeons of Doom OUYA (2013-04-11), Apple App Store (2013-06-04), Google Play 15, 19
Duck Game OUYA (2014), Nintendo Switch, Playstation 4, PC (Steam) (2015) 11, 13 new official site
Killing Floor: Calamity OUYA (2013-12), Nvidia Shield (2015-08), Google Play (2015-08) 27, 28, 29
Laza Knightez Windows, Mac OS 6
No Brakes Valet Windows, Apple App Store, Google Play 15, 16 new official site
Polarity PC (Steam), Apple App Store, Google Play 1, 15 new official site
Reagan Gorbachev Xbox One, PC (Steam, Humble Store) 2, 11
That Dragon, Chancer Mac, PC, Google Play, Apple App Store 4, 22 new official site
Toto Temple Playstation 4, Xbox one, WiiU, PC (Steam, Humble Store) 7, 8, 11
Towerfall Switch, PC (Steam), Playstation 4, Xbox One 9, 10, 14, 15
Whispering Willows Switch, PC (Steam), Playstation 4, Xbox One, Wii, Google Play, Apple App Store 11, 12 2 months exclusively on OUYA according to 12

Cancelled / Not exclusive

Some games were announced to be exclusively on OUYA but weren't actually, or were cancelled.

Game name Source Notes
Cascade 11, 23 Never released on the OUYA store. No mention of OUYA on homepage.
Fist of awesome 15 Kickstarter page says PC & Mac were there at least with ouya.
Human Element 1, 24 Cancelled
Neverending Nightmares 11 Released simulatenously on Windows, Mac, Linux, and Ouya. Kickstarter page: The Ouya Free The Games Fund exclusivity terms don't apply to computers.
PitchWreck 5, 25 Never released
Red. 15, 26 Released the same time on iOS and OUYA, 2013-03-13.
Yummy Circus 1, 3 Not on the ouya.tv games list. Was listed on their website as available on OUYA.

Sources

  1. Stuff.tv: Five exclusive games that'll make you want an Ouya
  2. TechnologyTell: Reagan Gorbachev Review: Taking the Reykjavik Summit by storm
  3. Phandroid: OUYA Exclusive: Yummy Circus puzzler gets demoed before launch
  4. Kotaku: The Powerfully Moving That Dragon, Cancer Is Now A Ouya Exclusive
  5. @playouya on Twitter: Pitchwreck
  6. Gambit Magazine: LAZA KNITEZ!! Launches March 12 Exclusively on OUYA
  7. daily dot: Ouya has a party in a box with ‘Toto Temple Deluxe’
  8. ouyaholic: Knightmare Tower Developers working on OUYA Exclusive
  9. Leo Sigh: TowerFall Review: It’s a Must Buy for the Ouya, It’s Awesome
  10. Destructoid: TowerFall ditches Ouya exclusivity with enhanced PC port
  11. GamesBeat: Six Ouya exclusives show the console's silly and serious side
  12. Whispering Willows homepage
  13. Wikipedia: Duck Game
  14. Pocketgamer: First impressions of Ouya
  15. Pocketgamer Youtube video: First impressions of Ouya
  16. Android Police: [New Game] No Brakes Valet Jumps From OUYA To The Google Play Store To Enable Your Ferris Bueller Fantasies
  17. OUYA… Why Amazing Frog? is on Steam Early Access
  18. OUYA wiki: Amazing Frog
  19. Thais Weiller: Deep Dungeons of Doom
  20. Indie Statik: How Some Students Found Hope In A Grain Of Sand: Monocle Man
  21. Wikipedia: Soul Fjord
  22. @playouya on Twitter: That Dragon, Cancer
  23. Youtube: OUYA Cascade game [W.I.P.] Brain Fly though [Unity] Level of detail test
  24. Wikipedia: Human Element
  25. Twitter: Neil Crofts: PitchWreck
  26. Twitter: Knife Media: Red release
  27. Engadget: Arcade shooter Killing Floor: Calamity arrives exclusively on Ouya
  28. Droid Gamers: Nvidia releases two new games for their Shield brand of devices: Killing Floor: Calamity and Windward
  29. Android Police: Killing Floor: Calamity, A Top-Down Adaptation Of The Popular First Person Shooter, Comes To Google Play

Published on 2021-10-13 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 ,


Podcastfolge "Die Ouya lebt!"

Ich war im Podcast "Besser Wissen" von Golem.de und habe mit Martin Wolf in der Folge Die OUYA lebt! über die OUYA, deren Untergang und die Rettung geredet.

Siehe auch: Initialer Blogpost, alle OUYA-Blogposts und ouya.cweiske.de

Published on 2024-04-05 in


Using a Stadia controller on my OUYA

The OUYA's servers were shut down in 2019, and Google shut down the servers for its Stadia game console in january 2023. I thought it would be cool to use the controller of one dead console on a resurrected dead gaming console :)

Google Stadia controller, 8BitDo adapter and OUYA developer console

Bluetooth

The Stadia controllers did connect directly to Google's internet servers via WiFi and only used Bluetooth for initial setup. After shutdown, Google provided a website that let you install a controller firmware update, finally making the controller a standard Bluetooth one.

The Stadia controller only supports Bluetooth Low Energy (BLE). The OUYA contains a AzureWave AW-NH660 chipset that is based on BCM4330, whose datasheet says it is forward-compatible with the impending Bluetooth Low Energy operating mode. Android supports BLE starting from version 4.3:

Bluetooth Low Energy (BLE), available in Android 4.3 and later, creates short connections between devices to transfer bursts of data

The OUYA runs Android 4.1, so you cannot use BLE controllers on an OUYA.

USB

The Stadia controller has a USB-C port. Connecting it to the OUYA's own USB-A port gives you a partially working controller: The d-pad, right thumb stick and L2+R2 do not work at all - only the left thumb stick works.

A custom key layout file is needed, just as I did before with a playstation controller.

Key layout file creation

Connect the controller via USB to your Android device and then run getevent -i in a terminal, e.g. via adb shell:

$ getevent -i
add device 2: /dev/input/event0
  bus:      0003
  vendor    18d1
  product   9400
  version   0111
  name:     "Google LLC Stadia Controller rev. A"
  location: "usb-tegra-ehci.2-1/input1"
  id:       "99200YCAC2LJ5L"
  version:  1.0.1
  events:
    KEY (0001): 0072  0073  00a4  0130  0131  0133  0134  0136
                0137  013a  013b  013c  013d  013e  0140  0141
                0142  0143
    ABS (0003): 0000  : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0
                0001  : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0
                0002  : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0
                0005  : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0
                0009  : value 0, min 0, max 255, fuzz 0, flat 15, resolution 0
                000a  : value 0, min 0, max 255, fuzz 0, flat 15, resolution 0
                0010  : value 0, min -1, max 1, fuzz 0, flat 0, resolution 0
                0011  : value 0, min -1, max 1, fuzz 0, flat 0, resolution 0
    MSC (0004): 0004
  input props:
    <none>

Here we see that the controller has 18 buttons (keys) and 8 axes.

Now run getevent without parameters, press the buttons and axes and make notes of their IDs:

$ getevent
[...]
/dev/input/event1: 0004 0004 00090001
/dev/input/event1: 0001 0130 00000001
/dev/input/event1: 0003 0000 0000007f
/dev/input/event1: 0003 0001 0000007f
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0004 0004 00090001
/dev/input/event1: 0001 0130 00000000
/dev/input/event1: 0003 0000 0000007c
/dev/input/event1: 0003 0001 0000007d
/dev/input/event1: 0000 0000 00000000

Here button A was pressed and released - it has the Linux key code 0x130. Doing that for all the buttons gives us this list:

A      0x130
B      0x131
X      0x133
Y      0x134
...    0x13a
===    0x13b
L1/LB  0x136
R1/RB  0x137
L3     0x13d
R3     0x13e
Stadia 0x13c

Now do the same for the axes:

D-Pad        left-right 0010
             up-down    0011
Left stick   left-right 0000
             up-down    0001
Right stick  left-right 0002
             up-down    0005
Left trigger            000a
Right trigger           0009

And this is all the information needed to write the key layout file:

Vendor_18d1_Product_9400.kl
# Google Stadia Controller via USB
key 0x130  BUTTON_A
key 0x131  BUTTON_B
key 0x133 BUTTON_X
key 0x134 BUTTON_Y

#L1
key 0x136 BUTTON_L1
#R1
key 0x137 BUTTON_R1

#L3 Stick
key 0x13d BUTTON_THUMBL
#R3 Stick
key 0x13e BUTTON_THUMBR

#Stadia symbol
key 0x13c HOME
#===
key 0x13b MENU
#...
key 0x13a BACK

#D-pad
axis 0x10 HAT_X
axis 0x11 HAT_Y

#Left stick
axis 0x00 X
axis 0x01 Y

#Right stick
axis 0x02 Z
axis 0x05 RZ

axis 0x0a LTRIGGER
axis 0x09 RTRIGGER

Copy that file into /system/usr/keylayout/:

$ adb push Vendor_18d1_Product_9400.kl /sdcard/
$ adb shell
$ su
$ mount -o remount,rw /system
$ mv /sdcard/Vendor_18d1_Product_9400.kl /system/usr/keylayout/

Simply unplugging and replugging makes Android load the custom key layout file instead of Generic.kl, and all buttons work.

Bluetooth with 8BitDo USB Wireless Adapter 2

8BitDo sells the USB Wireless Adapter 2, which bridges Bluetooth controllers to USB ports with the added benefit of letting you customize the button mappings. It supports Bluetooth Low Energy and - since firmware v1.04 - the Stadia controller:

Added support for Google Stadia Controller. (The controller is required to update to the Bluetooth mode firmware, it does not support vibration)

The adapter can behave differently depending on its mode, which can be switched when holding ··· and the directional pad keys for 3 seconds. You will see the adapter's red LED flash.

Supported modes as of firmware 1.06:

··· + d-pad left
DInput mode (USB ID 2dc8:3105, "8BitDo 8BitDo Receiver")
··· + d-pad up
Xinput mode (USB ID 2dc8:3106, "8BitDo 8BitDo Receiver")
··· + d-pad down
PSC/PSX mode (USB ID 054c:0cda, "Sony Interactive Entertainment Controller")
··· + d-pad right
Mac mode (USB ID 054c:05c4, "8BitDo 8BitDo Receiver")
··· + LB (Left shoulder button L1)
Switch mode (USB ID 057e:2009, "Nintendo Co., Ltd. Pro Controller")

I opted to use Dinput mode (··· + d-pad left), and could use the Stadia USB key layout file without changes - I only had to give it a new name to match the USB IDs: Vendor_2dc8_Product_3105.kl!

Dive into Linux input mapping

On Android, multiple stages of input mapping take place:

  1. Controller reports button bits
  2. Linux input driver map those bits to key codes
  3. Android maps Linux key codes to Android key codes via key layout files

Controller key bits

On Linux and Android you can see the keys a controller supports by inspecting its device information:

$ cat /proc/bus/input/devices
I: Bus=0003 Vendor=2dc8 Product=3105 Version=0111
N: Name="8BitDo 8BitDo Receiver"
P: Phys=usb-tegra-ehci.2-1/input0
S: Sysfs=/devices/platform/tegra-ehci.2/usb2/2-1/2-1:1.0/input/input8
U: Uniq=E417D86076B0
H: Handlers=js0 event1
B: PROP=0
B: EV=1b
B: KEY=7fff0000 0 0 0 0 0 0 0 0 0

$ cat /sys/devices/platform/tegra-ehci.2/usb2/2-1/2-1\:1.0/input/input8/capabilities/key
7fff0000 0 0 0 0 0 0 0 0 0

This key bit mask value 7fff0000 in bits is:

1111111111111110000000000000000

which are 15 buttons/keys.

Linux key codes

The input driver selected by Linux then takes care of mapping the bits onto key codes. You can inspect this information in the /sys/ file system as well:

$ cat /sys/devices/platform/tegra-ehci.2/usb2/2-1/2-1\:1.0/input/input8/modalias
input:b0003v2DC8p3105e0111-e0,1,3,4,k130,131,132,133,134,135,136,137,138,139,13A,13B,13C,13D,13E,ra0,1,2,5,9,A,10,11,m4,lsfw

With the help of the Linux kernel sources input.c and input.h this can be decoded:

b0003 #bustype
v2DC8 #vendor
p3105 #product
e0111- #version
e0,1,3,4, #evbit
k130,131,132,133,134,135,136,137,138,139,13A,13B,13C,13D,13E, #keybit
r
a0,1,2,5,9,A,10,11, #relbit
m4, #mscbit
l #ledbit
s #sndbit
f #ffbit
w #swbit

The key codes that were used for the key map file above are already visible here.

Not a gamepad

During development of my key layout file I got the following message from the OUYA framework's input handler:

E/OuyaInputMapper(  548): onInputDeviceAdded device=5 not found
D/ControllerInputDeviceListener(  565): InputDevice 8BitDo 8BitDo Receiver (id: 5, desc: 9c597667366a6b3d65e77ad35e1bc1f757d19732) is not a gamepad...

It turned out that I had used Android key code values (2xx range) instead of Linux key codes (3xx/0x13x range) in the key layout file as keys. After correcting the codes to 0x130 and above, the controller was correctly detected as gamepad.

Orange light

When the Stadia controller is connected via USB to the OUYA and the Stadia button glows orange instead of white, then you have to reboot the OUYA.

This often happens when connecting the USB cable 5+ minutes after bootup.

Also on: Mastodon, Twitter.

Published on 2024-02-05 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 , ,


OUYA: Using own USB joysticks

I have some old Playstation 1 controllers that I'd like to use on my OUYA gaming console. Using them on the PC works via an PSX-to-USB adapter.

Plugging them into the OUYA unfortunately did not work; they were not detected as controllers - or at all, as it seemed. A Microsoft Sidewinder DualStrike did also not work.

USB device detection

Linux PC

Attaching the PSX adapter with controllers to a PC shows the following lsusb output:

ID 0810:0001 Personal Communication Systems, Inc. Dual PSX Adaptor

dmesg shows:

usb 2-1.2: new low-speed USB device number 120 using ehci-pci
usb 2-1.2: New USB device found, idVendor=0810, idProduct=0001
usb 2-1.2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
usb 2-1.2: Product: Twin USB Joystick
input: Twin USB Joystick as /devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1.2/2-1.2:1.0/input/input1460
input: Twin USB Joystick as /devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1.2/2-1.2:1.0/input/input1461
pantherlord 0003:0810:0001.05AC: input,hidraw2: USB HID v1.10 Joystick [Twin USB Joystick] on usb-0000:00:1d.7-1.2/input0
pantherlord 0003:0810:0001.05AC: Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>

Input device files in /dev/input/ get created for both joysticks; /dev/input/js0 and /dev/input/js1.

I can then use jstest or jstest-gtk to test the controllers and see all the buttons and axes working.

OUYA

Using adb to open a shell on the OUYA gives the following dmesg output:

[  331.002934] usb 2-1: new low speed USB device number 13 using tegra-ehci
<6>[  331.039183] usb 2-1: New USB device found, idVendor=0810, idProduct=0001
<6>[  331.046013] usb 2-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
<6>[  331.053437] usb 2-1: Product: Twin USB Joystick]]>

That was all. Nothing more - no more dmesg output, no input files in /dev/.

What now?

On the internet, many people used apps like usb/bt joystick center or tincore keymapper. The first has been removed from the google play store (I did not find an explanation why; the author did not respond to my e-mail), the second is still available.

But I did not want to use any of these tools. I can't look into them and do not know what they do. There just had to be a way to make it work properly.

Linux drivers

After some detours, I had the idea that Linux drivers could be missing.

The PC's dmesg output gave a hint which ones were used:

pantherlord 0003:0810:0001.05AC: input,hidraw2: USB HID v1.10 Joystick

The keywords are pantherlord, input and hidraw2.

input is a standard kernel module that is always enabled; otherwise no mouse/keyboard/joystick/touchpad would work.

pantherlord turned out to be the driver for the PSX adapter. The kernel sources tell us in drivers/hid/Kconfig:

config HID_PANTHERLORD
  tristate "Pantherlord/GreenAsia game controller"
  depends on USB_HID
  ---help---
    Say Y here if you have a PantherLord/GreenAsia based game controller
    or adapter.

There is also a HIDRAW driver, which supports

HID devices (from the USB specification standpoint) that aren't strictly user interface devices

OUYA kernel configuration

One can access the current kernel configuration at /proc/config.gz by copying from the OUYA:

$ adb pull /proc/config.gz
$ zless config.gz

And there I saw it:

# CONFIG_HIDRAW is not set
# CONFIG_HID_PANTHERLORD is not set
# CONFIG_HID_MICROSOFT is not set

The OUYA's Linux kernel had been built without support for my game controllers.

A custom OUYA linux kernel

So it turned out that the only way to get my arcade joystick and gamepad working was to compile support for them into the kernel.

While HID_PANTHERLORD could be compiled as a module (tristate in the Kconfig files), HIDRAW could not - I had to re-build the whole kernel, and not only compile & copy a single module.

The internet contained a single, but very helpful OUYA kernel compilation howto: Builing your own Ouya Kernel by Leonardo Pires, written mid of 2014. The original announcement of this HowTo seems to be Recompilando Kernel do OUYA - Por Leonardo Pires which links to a HowTo on Google Drive. The XDA forum post seems to be a low-quality and translated version of it.

I had to adjust it to the current OUYA firmware version and fix some errors in it. Here is the updated one that worked 2015-06-02:

Preparation

You have to enable ADB via the OUYA System / Debugging menu.

For the last step you have to be connected via USB to the device; uploading the kernel via network does not work.

Create a udev rules file for the OUYA so that you are able to communicate with the device over USB. Put the following into /etc/udev/rules.d/051-android.rules:

# ouya
SUBSYSTEM=="usb", ATTRS{idVendor}=="2836", MODE="0666"
# fastboot ouya
SUBSYSTEM=="usb", ATTRS{idVendor}=="0955", MODE="0666"

Install the Android debug bridge (adb) and make it recognize the OUYA as Android device:

$ sudo apt-get install android-tools-adb
$ echo "0x2836" >> ~/.android/adb_usb.ini
$ adb kill-server
$ adb devices
List of devices attached
012d3a4efac56789	device

In your home directory, create a directory ouya-kernel:

$ cd
$ mkdir ouya-kernel
$ cd ouya-kernel

Ramdisk

Flashing the OUYA with a new kernel requires a ramdisk file, and we can get it from the current firmware. At the time of writing this was 1.2.1427-r1.

$ wget http://devs-ouya-tv-prod.s3.amazonaws.com/ota/RC-OUYA-1.2.1427-r1_ota.zip
$ unzip RC-OUYA-1.2.1427-r1_ota.zip boot.img
$ wget http://www.enck.org/tools/split_bootimg_pl.txt -O split_bootimg.pl
$ perl split_bootimg.pl boot.img
$ gunzip boot.img-ramdisk.gz
$ mv boot.img-ramdisk ramdisk

split_bootimg.pl's homepage is http://www.enck.org/tools.html#split_bootimg.

Android NDK

We have to cross-compile the kernel for the ARM platform; and the NDK contains the correct tools for that.

android-ndk-r10e did not work for me; I got a unknown CPU architecture error during kernel compilation. android-ndk-r9d did work:

$ wget https://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2
$ tar xjvf android-ndk-r9d-linux-x86_64.tar.bz2

OUYA kernel + configuration

OUYA's kernel is on github, and we fetch it from there:

$ git clone git@github.com:ouya/ouya_1_1-kernel.git

Now we have to fetch the OUYA's kernel configuration file, which can be found at /proc/config.gz:

$ adb pull /proc/config.gz
$ gunzip -kc config.gz > ouya_1_1-kernel/.config

Now adjust the kernel configuration file in ouya_1_1-kernel/.config:

CONFIG_HIDRAW=y
CONFIG_HID_MICROSOFT=y
CONFIG_HID_PANTHERLORD=y

The kernel can be compiled now:

$ export CROSS_COMPILE=/home/cweiske/ouya-kernel/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
$ export ARCH=arm
$ cd ouya_1_1-kernel
$ make
.. wait an hour ..
$ cp arch/arm/boot/zImage ../

Installing the kernel

Make sure you're connected via USB to the OUYA.

Install the fastboot command:

$ apt-get install android-tools-fastboot
$ adb reboot-bootloader
$ fastboot devices -l
 012d3a4efac56789       fastboot usb:2-1.2

If fastboot gives you a no permissions warning, make sure that /etc/udev/rules.d/51-android.rules contains settings for vendor 0955 - the USB IDs change when rebooting into bootloader mode!

Now it's time to install the new kernel:

$ fastboot flash:raw boot ./zImage ./ramdisk
creating boot image...
creating boot image - 5742592 bytes
sending 'boot' (5608 KB)...
OKAY [  1.125s]
writing 'boot'...
OKAY [  1.854s]
finished. total time: 2.980s
$ fastboot reboot

If all went well, the OUYA boots up with the fresh kernel.

Success!

dmesg on the OUYA shows us that the joysticks are recognized now:

[  113.056632] usb 2-1: new low speed USB device number 2 using tegra-ehci
<6>[  113.104851] usb 2-1: New USB device found, idVendor=0810, idProduct=0001
<6>[  113.116743] usb 2-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
<6>[  113.124579] usb 2-1: Product: Twin USB Joystick
<6>[  113.145452] input: Twin USB Joystick as /devices/platform/tegra-ehci.2/usb2/2-1/2-1:1.0/input/input1
<6>[  113.156314] input: Twin USB Joystick as /devices/platform/tegra-ehci.2/usb2/2-1/2-1:1.0/input/input2
<6>[  113.167024] pantherlord 0003:0810:0001.0001: input,hidraw0: USB HID v1.10 Joystick [Twin USB Joystick] on usb-tegra-ehci.2-1/input0
<6>[  113.179213] pantherlord 0003:0810:0001.0001: Force feedback for PantherLord/GreenAsia devices by Anssi Hannula ]]>

Input mapping

The Playstation controllers did not work immediately. The axes (up/down, left/right) did work, but the keys did not. I had to provide my own key layout file for the joysticks.

Creating it was easy; I installed the KeyTest Android application (link is dead) which could be downloaded as pre-compiled .apk file (archived version).

Then I clicked all the buttons on the OUYA controller and wrote down the scan codes. Afterwards, I wrote down the scan codes of the Playstation controllers.

The resulting key layout file has to get the name Vendor_0810_Product_0001.kl.

# PSX controller mapping
# Dual PSX Adaptor / Twin USB Joystick
# idVendor=0810, idProduct=0001
# Linux HID_PANTHERLORD driver

# X cross
key 290   BUTTON_A
# O circle
key 289   BUTTON_B
# [] square
key 291   BUTTON_X
# /\ triangle
key 288   BUTTON_Y

key 294   BUTTON_L1
key 292   BUTTON_L2
key 295   BUTTON_R1
key 293   BUTTON_R2

key 296   BUTTON_SELECT
key 297   BUTTON_START

key 298   BUTTON_THUMBL
key 299   BUTTON_THUMBR

axis 0x00 X
axis 0x01 Y
axis 0x02 HAT_X
axis 0x03 HAT_Y
axis 0x04 RZ
axis 0x05 Z

Push it onto your OUYA into /system/usr/keylayout/:

$ adb push Vendor_0810_Product_0001.kl /sdcard/
$ adb shell
$ su
$ mount -o remount,rw /system
$ mv /sdcard/Vendor_0810_Product_0001.kl /system/usr/keylayout/

Now unplug and replug the USB controller - and it works!

Published on 2015-06-03 in , ,


OUYA usage statistics 2021 + 2022

My OUYA community server is running since 2019-11, and in 2021 I compiled the usage statistics for 2020. Time for the 2021 and 2022 numbers!

OUYA bootups
YearBootups
202010 398
202111 381
202214 658

Initial logins
YearInitial logins
2020733
2021673
2022858

Published on 2023-05-06 in


Network error on factory reset OUYAs

My own OUYA API server has been running since november last year. The game data files have been worked on: Previously missing games were added, wrong developer UUIDs fixed. Many of the games got product data, so that purchases can be restored now and games stuck in demo mode unlock to the full version now.

All went nicely until end of january, people with factory reset OUYAs came into the chat and asked for help because they could not get past the network configuration screen. All they got were the following error messages:

Unable to connect

Please check your Internet connection and try again.

and

Cannot establish a connection with the OUYA Servers. To turn on Wi-Fi, unplug your Ethernet cable and proceed. To retry ethernet, please check your connection and then unplug and re-plug your cable.

Unabe to connect Cannot establish a connection with the OUYA Servers.

The culprit

Luckily I own two OUYAs, so I did a factory reset on the development machine and tried the setup myself: It failed with the same error messages as reported.

The initial setup is managed by OUYAOOBE.apk, the Out Of the Box Experience application. I read the decompiled sources and soon found the culprit, ConnectivityChecker.java:

public Void doInBackground(Void... params) {
    Socket socket = null;
    boolean reachable = false;
    try {
        Socket socket2 = new Socket("devs.ouya.tv", 80);
        reachable = true;
        if (socket2 != null) {
            try {
                socket2.close();
                Socket socket3 = socket2;
            } catch (IOException e) {
                Socket socket4 = socket2;
            }
        }
    } catch (UnknownHostException, IOException e2) {
        // error handling
    }
    setResult(reachable);
    return null;
}

So OUYA's setup application has a hard-coded check to devs.ouya.tv, which was the name of the API server - and it does not use the ouya config override file ouya_config.properties. The DNS record still exists:

$ dig devs.ouya.tv
devs.ouya.tv.		60	IN	CNAME	tokyo-6663.herokussl.com.

But the host that the domain was aliased to does not exist anymore:

$ dig +short tokyo-6663.herokussl.com
$

Apparently Razer's Heroku contract was cancelled or not renewed, and the box that served the redirect from devs.ouya.tv to razer.com was shutdown forever.

The solution

It is possible to get past the network selection screen by letting the OUYA think that devs.ouya.tv still exists, and let it point to some IP address that has a HTTP and HTTPS server running.

Choose one of the following options:

1. Modify the internet router's DNS server

  1. Open your internet router's web interface and change the DNS server temporarily to 178.254.13.17.
  2. Finish the OUYA setup including registration.
  3. Change the router's DNS server setting back to the previous setting or the one provided by the ISP - otherwise you cannot open most web pages anymore.

2. Modify the OUYA DNS server

Summary: Temporarily change the OUYA's network configuration to use 178.254.13.17 as DNS server.

Wifi

  1. Connect to your Wi-Fi network. The OUYA shows "It seems we're unable to connect to the OUYA servers at the moment".
  2. Press Y to open the network settings.
  3. Select the connected Wifi network, and long press the green O button until the context menu appears. Select "Modify network".
  4. Activate "Show advanced options".
  5. Change the "IP settings" from "DHCP" to "Static".
  6. Change the "DNS 1" address to 178.254.13.17.
  7. Close the network settings and press O to continue.
  8. If you get a popup "Unable to connect", create the configuration file and reboot the OUYA.
  9. Once you registered and see the OUYA main menu, go to Manage -> Network Settings and change the network settings back to DHCP.

OUYA OOBE Wifi network selection OUYA OOBE Wifi server error OUYA OOBE Wifi configuration OUYA OOBE Wifi context menu

Ethernet

  1. The OUYA setup shows the network information (IP Address, Subnet mask, ...) and the message "Cannot establish a connection with the OUYA Servers."
  2. Write down the three addresses: IP Address, Subnet Mask, Router.
  3. Press Y to open the network settings. If , then configure the ethernet or wifi device.
  4. Change the "Connection Type" from "DHCP" to "Static IP".
  5. Manually enter the "IP address", "Netmask" and "Router".
  6. Change the "DNS address" address to 178.254.13.17.
  7. Save & close the network settings and press O to continue.
  8. If you get a popup "Unable to connect", create the configuration file and reboot the OUYA.
  9. Once you registered and see the OUYA main menu, go to Manage -> Network Settings and change the network settings back to DHCP.

OUYA OOBE Ethernet information OUYA OOBE Ethernet configuration OUYA OOBE Ethernet settings OUYA OOBE Ethernet IP address OUYA OOBE All static settings OUYA OOBE Custom DNS server

3. DNS mapping in your router

Some routers allow you to add own domain-name-to-IP-mappings. If your router is one of them, add a mapping for hostname devs.ouya.tv, status.ouya.tv and ouya-updates.s3.amazonaws.com to the IP of my server: 178.254.13.17.

4. Modify OUYA's /system/etc/hosts file

Each computer has a file /etc/hosts that allows you to define DNS mappings. On Android, that file is located at /system/etc/hosts.

This method will surely work, but takes the most steps. You need to have the "Android Debug Bridge" (adb) command line tool installed on your PC. Have a look at Cyanogen Mod CM11 and the Ouya, it has installation instructions for adb on windows.

  1. On your PC, run adb shell
  2. Type su to become the root user
  3. Make the system partition writable:
    mount -o rw,remount -t ext4 /dev/block/platform/sdhci-tegra.3/by-name/APP
  4. Use my server instead of the original one by modifying the hosts file:
    echo "178.254.13.17 devs.ouya.tv status.ouya.tv ouya-updates.s3.amazonaws.com" >> /system/etc/hosts

The connectivity check should work now without rebooting.

Unable to connect

If you still get the "Unable to connect" error, then you are missing the ouya_config.properties file.

Update 2023-04-03

Because I am moving to a new server, the IP address changed from 83.169.45.222 to 178.254.13.17.

Published on 2020-02-24 in , ,


Restoring OUYA Everywhere on Mad Catz Mojo

The OUYA gaming console amassed over 1200 games in its online store, most of which have been preserved on the Internet Archive and made available to OUYAs via the community server ouya.cweiske.de.

Other companies thought it would be great if their Android TV consoles would have access to this large library of games, and so OUYA Inc. announced the "OUYA Everywhere" program in 2014-03. The first partner was Mad Catz with its MOJO microconsole, and with firmware update MO0205-TS in 2014-06 they shipped the OUYA Everywhere installer and put it onto the Mojo's desktop:

OUYA icon on Mojo desktop

Forward 8 years later, and Ryo on the OUYA saviors discord chat server tries to get the OUYA community server working with his Mojo but fails in the end. User Toast offers to send his spare Mojo to me so I can look into the problem, which I happily accept. A couple of weeks later it arrives and I can have a first look at it.

OUYA Everywhere installer

After a factory reset I see that the Mojo firmware does not contain the "OUYA Everywhere" software but on the "OUYA Everywhere installer" which tries to download, install and launch the actual OUYA software. The installer requests an API endpoint /api/v1/partner_builds that my documentation did not know of, and thus my server does not support.

OUYA installer says no

With the help of the awesome jadx-gui I reverse engineer the JSON file format that the installer expects. The API endpoint tells the installer what to do: Install or uninstall .apk files, show a message, start an application or exit. A first test shows a popup:

OUYA everywhere installer shows a test popup

Since I factory reset the Mojo, I don't have the previously downloaded ouya everywhere apk files anymore :( A XDA forum thread contains early files (version 1.2.145), and a post on page 3 the latest version 1.2.897. So I built a JSON that tells the Mojo to install the OUYA OOBE (setup), OUYA framework and the OUYA launcher packages and starts the latter.

This was all it took: A single file on my server with the correct content, and now all Mojo owners can play OUYA games again!

OUYA everywhere installer is installing OUYA launcher menu

Setup

The Mojo must be told to use the new server by putting a file ouya_config.properties in the folder /sdcard/. Contents of the file can be found on ouya.cweiske.de.

When this is done, simply open the OUYA icon on the Mojo's desktop and the OUYA OOBE setup will greet you.

My xposed module works on the Mojo as well, so most of the games can be unlocked.

OUYA Anywhere

The first beta of OUYA Everywhere 1.2.145 could be installed and started on all devices, but later ones only ran on on whitelisted consoles like the Mojo. This first version has been dubbed "OUYA Anywhere" by the community.

Today when looking at the latest source code I found that the "is this device supported" check has another condition:

//tv.ouya.console.launcher.home.HomeActivity
if (!DeviceInfoReceiver.getInstance().checkIsSupportedDevice()
    && !SystemProperties.getDebug()
) {
    DeviceNotSupportedDialog.show(this);
    return;
}

Debugging can be enabled by putting the line DEBUG=1 into the ouya_config.properties file.

With that extra configuration line, I am able to use the OUYA launcher on my Nexus 7 tablet with Android 11:

OUYA launcher 1.2.897 running on Nexus 7

We have some problems, though:

  • There is a graphical glitch that affects all active buttons.
  • Installing games will not work on Android 8+ because Google changed the permissions required for that task.
  • Also there is no touch support, which means you need to have a controller paired.

Downloads

Published on 2022-09-15 in


Square Enix' red herring

To get games to unlock on the defunct OUYA gaming console, I wrote an Xposed module that disables encryption for purchase receipt requests and responses that the games send and receive.

While it worked for many games, users reported that Final Fantasy III crashes when my plain-purchases module is enabled. adb logcat shows the following stacktrace:

E/AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main
   java.lang.SecurityException: 1466 does not have permission:android.permission.CLEAR_APP_USER_DATA to clear datafor process:de.cweiske.ouya.plainpurchases
       at android.os.Parcel.readException(Parcel.java:1425)
       at android.os.Parcel.readException(Parcel.java:1379)
       at android.app.ActivityManagerProxy.clearApplicationUserData(ActivityManagerNative.java:2889)
       at com.android.commands.pm.Pm.runClear(Pm.java:1126)
       at com.android.commands.pm.Pm.run(Pm.java:116)
       at com.android.commands.pm.Pm.main(Pm.java:75)
       at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
       at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235)
       at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:135)
       at dalvik.system.NativeStart.main(Native Method)

Final Fantasy 3 is not the only game that shows this behavior; many Square Enix games exhibit this behavior.

Investigation

FF3 for Android/OUYA contains a native library lib__57d5__.so which seems to be the source of the problem. Fortunately for me, the Xposed author had a look at that library before:

Ok, whatever Final Fantasy does there: It looks like some very dirty coding.

  • com/square_enix/android_googleplay/FFIV_GP/MainActivitya loads lib__57d5__.so and then calls native function MainActivityb.a(I)I with some random (?) integer constants
  • Actually already the library loading fails because somewhere during the initialization, it calls sh -c pm clear <package> for the Xposed modules, which fails with a permission error and crashes the process
  • [...]

To summarize: A strange native library in FF seems to get all /data/app/*-?.apk entries from the memory mapping file and tries to clear the data for them.

So the lib tries to clear the application user data for all apks that somehow linger in the memory of the FF3 game. It does not do this directly, but by opening a shell and using the android package manager command line tool pm:

$ sh -c pm clear packagename

After reading the sources of pm I came to the following call stack:

final fantasy 3
+ lib__57d5__.so
  + sh -c pm clear $package
    + android.app.ActivityManagerProxy::clearApplicationUserData
      + ?? IPackageDataObserver - transact(CLEAR_APP_DATA_TRANSACTION)
           something with binder
        + ??? PackageManager::clearApplicationUserData()
          + com.android.server.pm.PackageManagerService::clearApplicationUserData
            (final String packageName, final IPackageDataObserver observer, final int userId)

The pm cli tool does not directly call the package manager, but - to my limited understanding - uses some Android IPC mechanism to call the one authorative instance of the actual package manager.

Attempt #1: Hack package manager service

At first I wrote an xposed module that hooked into PackageManagerService::clearApplicationUserData and simply said "success" when the data of my own module were to be cleaned:

 iPackageDataObserverClass = Class.forName("android.content.pm.IPackageDataObserver");
                            Class[] paramTypes = {String.class, boolean.class};
                            Method onRemoveCompletedMethod = iPackageDataObserverClass.getMethod("onRemoveCompleted", paramTypes);
                            Object[] params = {packageName, true};
                            try {
                                onRemoveCompletedMethod.invoke(observer, params);
                                //observer.onRemoveCompleted(packageName, true);
                            } catch (Exception e) {
                                XposedBridge.log("Observer no longer exists.");
                            }
                        }
                        //end dance
                    }
                }
            }
        );
    }
}]]>

The unaccessible IPackageDataObserver made it a bit hard to call the right methods, but it was still relatively easy. Unfortunately, it did not work at all because it was too late: ActivityManagerProxy.clearApplicationUserData() already does the permission checks!

Attempt #2: Hack activity manager proxy

My goal was to hook into ActivityManagerProxy that does the IPC call to the package manager.

This proved to be extremely hard for me because hooking into command line tools with IXposedHookCmdInit is not supported anymore by Xposed: See XDA: Hook cmds (PM) and the XPosed API changelog for 2.6:

IXposedHookCmdInit is deprecated now, initCmdApps() won't be called anymore unless an undocumented file has been created. Only two modules used it, both got rid of it without any loss of functionality.

Rolling back my OUYA's XPosed from version 2.6.1 (API v31) to 2.5.1 (API v50) worked, but then I faced the most difficult problem: I could not compile the code, because the compileOnly de.robv.android.xposed:api dependency is only available for API version 53 and higher - and 52 was the last one with support for command line tool hooks :/

It took quite some time to find an older XposedBridgeApi jar file, but eventually one turned up: XposedBridgeApi-52.jar. Moving that to the module's lib/ directory let me compile the module with the cli hook! Now I faced a very strange error:

I/Xposed: Running ROM 'JZO54L-OUYA' with fingerprint 'OUYA/ouya_1_1/ouya_1_1:4.1.2/JZO54L-OUYA/1427:user/test-keys'
I/Xposed: Loading modules from /data/app/de.cweiske.ouya.plainpurchases-2.apk
I/Xposed:   Loading class de.cweiske.ouya.plainpurchases.PlainPurchases
I/Xposed: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
        at dalvik.system.DexFile.defineClass(Native Method)
        at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:211)
        at dalvik.system.DexPathList.findClass(DexPathList.java:315)
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:58)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
        at de.robv.android.xposed.XposedBridge.loadModule(XposedBridge.java:441)
        at de.robv.android.xposed.XposedBridge.loadModules(XposedBridge.java:407)
        at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:121)
        at dalvik.system.NativeStart.main(Native Method)

The source of the problem was that I moved XposedBridgeApi-52.jar into the lib/ folder, which meant it got compiled into the xposed module jar file. Now on the OUYA, there were suddenly two implementations of the bridge API, and the JVM could not decide which was the right one.

I moved it into a different directory, told gradle/Android Studio to use it for compilation only and could load the mod without problems!

 iPackageDataObserverClass = Class.forName("android.content.pm.IPackageDataObserver");
                        Class[] paramTypes = {String.class, boolean.class};
                        Method onRemoveCompletedMethod = iPackageDataObserverClass.getMethod("onRemoveCompleted", paramTypes);
                        Object[] params = {packageName, true};
                        try {
                            onRemoveCompletedMethod.invoke(observer, params);
                            //observer.onRemoveCompleted(packageName, true);
                        } catch (Exception e) {
                            XposedBridge.log("Observer no longer exists.");
                        }
                    }
                    //end dance
                }
            }
        );
    }
}]]>

Success?

Running pm clear ... from shell as limited user worked flawlessly and gave exit code 0 and no exceptions! Now I had beaten Square Enix! I started Final Fantasy 3 via shell:

$ adb shell am start -n com.square_enix.android_OUYA.FFIII/com.square_enix.FFIII_J.MainActivity

... and FF3 stopped as it had before:

I/Xposed: clearApplicationUserData: de.cweiske.ouya.plainpurchases
D/AndroidRuntime: Shutting down VM
I/AndroidRuntime: NOTE: attach of thread 'Binder_3' failed
D/dalvikvm: JIT code cache reset in 0 ms (86452 bytes 1/0)
D/dalvikvm: Debugger has detached; object registry had 1 entries
D/Zygote: Process 1572 exited cleanly (1)
I/ActivityManager: Process com.square_enix.android_OUYA.FFIII (pid 1572) has died.
W/ActivityManager: Force removing ActivityRecord{420f33f0 com.square_enix.android_OUYA.FFIII/com.square_enix.FFIII_J.MainActivity}: app died, no saved state

lib__57d5__.so did not care about pm's exit code, it always stops when it detects that XPosed is running.

I'm very sure that the SecurityException was just a red herring to make people spend time with a pretty difficult problem that has nothing to do with the actual problem.

/me tips his hat to the lib__57d5__.so developers.

Update 2023-01-10: We have a solution.

Published on 2020-02-26 in , , ,