The O2 Joggler is a OpenPeak tablet only available on UK.
It's a very interesting one because it has a LAN connector and is configured to boot on any bootable USB drive connected.
I took me several months (yes, seriously, it was a nightmare to buy a cheap joggler from a seller who ship to France ) but I finally bought mine on eBay.
There is a very active community of hackers around the Joggler :
Wiki, forum....
I'm not starting from nothing with a very difficult system !
FYI, Orange, in France, followed the same concept to create its own "tabbee".
Unfortunately, it is not as easy as the O2 joggler to hack.
I have no longer interest on the Joggler, Android is not stable enough on this device, so don't expect more update.
I need 2 things to experiment on Joggler
I found my PSU on ebay and by a PNY Attaché™ Evolutive 16Go (a MicroSD hidden in a USB connector)
Note after several months on use, I suspect the Attaché Evolutive to be bad product : I failed several times to dd, badblocks or copy file from it while it's possible when I move the MicroSD on a SD adapter.
My major requirement was : Ethernet (no Wifi!), sound and less lag as possible.
From all the Android port available, I selected the Miyu 1.2.3 Android 2.2.2
1.2.4 hasn't sound support and I suspect ICS to be slow on Joggler.
I so downloaded the image available on the forum since it includes a lot of fixes on Miyu 1.2.3 (english, system time sync and market)
For a first try, follow the direction on the same wiki page (write the image to a 4Go+ USB flash drive)
My goal is to understand how it works, so let make it the hard way !
First problem, this image is a 4Go+ disk image, including 3 partitions.
These 3 partitions are
I have 8Go so I decided to create the sdcard partition myself.
It's (a lot) easier to write the 4Go+ image to your USB drive then use gparted or fdisk to expand the last partition but I found it interesting to start from partition images.
To do this, I first had to extract them from the disk image, using their offsets.
Several tools exists (kpartx!!) but I want to do it with standard Linux tools : fdisk, dd (and mount)
fdisk -lu image.img
'l' list the partition
'u' ask to print sector info
Device Boot Start End Blocks Id System image.img1 63 1159167 579552+ b W95 FAT32 Partition 1 does not end on cylinder boundary. image.img2 1159168 3201023 1020928 83 Linux Partition 2 does not end on cylinder boundary. image3 3201024 7307263 2053120 b W95 FAT32 Partition 3 does not end on cylinder boundary.
if you have sfdisk, use
sfdisk -l -uS image.img
With the info we found, we can now extract partitions with:
dd if=image.img of=partition1.img skip=63 count=$[1159167-63+1]
dd if=image.img of=partition2.img skip=1159168 count=$[3201023-1159168+1]
dd if=image.img of=partition3.img skip=3201024 count=$[7307263-3201024+1]
You could skip the last one if you want to start from zero, but since it contains a lot of apk to use...
Let's mount them to check everything is alright
mkdir /mnt/android_part1
mkdir /mnt/android_part2
mkdir /mnt/android_part3
mount partition1.img /mnt/android_part1 -o loop
mount partition2.img /mnt/android_part2 -o loop
mount partition3.img /mnt/android_part3 -o loop
The important part is -o loop
I browse these mounts without problems, looking for every interesting bit.
Note 'Apps pack' on the SD card partition which contains a lot of apk tested working on Joggler.
Be free to add / remove some.
If you plan to make perfect copy of the partition, get the images' size for fdisk using ls -lh partition*.img
-rwxrwxrwx 1 root root 566M Mar 29 09:17 partition1.img -rwxrwxrwx 1 root root 997M Mar 29 09:17 partition2.img -rwxrwxrwx 1 root root 2.0G Mar 29 09:17 partition3.img
So, now I connect a 8Go USB drive on my laptop.
To find its device handle, I use dmesg | tail
[12239.238397] sd 6:0:0:0: Attached scsi generic sg3 type 0 [12239.246154] sd 6:0:0:0: [sdc] 15695871 512-byte logical blocks: (8.03 GB/7.48 GiB) [12239.250002] sd 6:0:0:0: [sdc] Write Protect is off [12239.250006] sd 6:0:0:0: [sdc] Mode Sense: 45 00 00 08 [12239.250008] sd 6:0:0:0: [sdc] Assuming drive cache: write through [12239.269992] sd 6:0:0:0: [sdc] Assuming drive cache: write through [12239.270000] sdc: sdc1 [12239.288169] sd 6:0:0:0: [sdc] Assuming drive cache: write through [12239.288175] sd 6:0:0:0: [sdc] Attached SCSI removable disk
My USB drive is on sdc.
To write partitions, I need to remove the existing one so BE SURE of your drive handle !
fdisk /dev/sdc
launches fdisk in interactive mode
press p to print the device table (I have 1 partition)
press d to delete a partition
press 1 to delete partition 1 (only if you have more than 1 partition)
press p to check the partition is delete
press w to write the table and so REALLY delete the partition
USB drive is now a raw device.
press n to create the first partition (system)
press p to make it primary
press 1 to tell it's the first one
press enter for default start cylinder
press +566M to define partition 1 size (or whatever you want, like +128M)
press t to ask for type change
press L to see the existing type (optional)
press b to ask for FAT32 change
press p to check if partition is created
press n to create the second partition (userdata)
press p to make it primary
press 2 to tell it's the second one
press enter for default start cylinder
press +997M to define partition 2 size (or whatever you want, like +1G)
press p to check if partition is created
press n to create the third partition (sdcard)
press p to make it primary
press 3 to tell it's the second one
press enter for default start cylinder
press enter for default end cylinder (full size)
press t to ask for type change
press b to ask for FAT32 change
press p to check if partition is created
press w to write partitions and quit
partprobe
will sync the partition info with the kernel
Method 1, if you create partition with exact size of image, you could load the partitions with dd
dd if=partition1.img of=/dev/sdc1
dd if=partition2.img of=/dev/sdc2
(optional)
Linux replace the newly created partitions in fdisk (with correct cylinder info)
Methode 2, If you create your own partitions, format, mount and copy
mkdosfs -n system /dev/sdc1
mkdir /mnt/android_system
mount /dev/sdc1 /mnt/android_system
cp -a /mnt/android_part1/* /mnt/android_system
mkfs.ext2 -L user /dev/sdc2
mkdir /mnt/android_user
mount /dev/sdc2 /mnt/android_user
cp -a /mnt/android_part2/* /mnt/android_user
Now copy the previous SD card data to the new one
mkdosfs -n sdcard /dev/sdc3
mkdir /mnt/android_sd
mount /dev/sdc3 /mnt/android_sd
cp -a /mnt/android_part3/* /mnt/android_sd
Et voilà! My USB drive is ready to be plug on Joggler with a ready-to go SD card
Note, in a second try, I simply create 3 partitions and copy the system partition only : a clean boot.
It took several minutes to boot, creating the userdata and basic sd card data.
After a first reboot, everything runs smoother.
I had to disable WIFI and localisation, prior to active Ethernet.
I then setup the Clock Sync.
And apk installation followed...
It's Android so it's only a matter of personal choice, mine was
- cifsManager to handle shared folder on network
- ES File explorer to handle file handling
- Alarm clock plus for music alarm, weather and night desk clock
- Fancy widgets for the HTC Sense like clock, but not working weather (still waiting for an alternative)
- Photo slides to make Joggler a photo frame, using photos from my NAS
- Screen filter to dim the screen when not it use (Joggler is on the bedroom!!)
- Upnplay to play music from my NAS upnp server and control my daughter sound system
The Android port was made by Mijuu from mporting and updated by various forum's members.
He was able to
To make the Joggler boot on USB isn't that hard when you know how it works.
Joggler uses a EFI firmware, it so looks on USB for a recovery device if needed.
If it find a EFI Shell script called boot.nsh, it will call it.
Note that I first thought (like a lot of people it seems) than startup.nsh was the script file needed.
I was logical since it's what you'll find on the official EFI document and some various others documents.
But, trying to follow the full boot process,
I couln't understand what the fs1:boot2
command meant.
I could make sense to find fs1:boot
(call boot.nsh on fs1, the USB device) but not fs1:boot2
!
Thanks to Torn Wuff for making it clear : startup.nsh isn't called on USB device. Easy to test, rename/delete it and you'll still be able to boot on Android !
So, let's go deeper, where goe this bad use of startup.nsh come from ?
Like I said earlier, the first answer is on the EFI official document :
'....in EFI, a file called "startup.nsh" automatically runs every time a shell environment is opened ...'
But it doesn't explain the fs1:boot2
...
To find the answer, let's look at the original Joggler firmware image (based on Miles' instructions)
I downloaded O2 latest firmware at http://o2.openpeak.co.uk/firmware/app-o2flash-26635.8686-S3-f1-reimage.tgz
Then I untared it (tar xvf
) and, of course, looked inside : it's more easy-to-hack firmware update I saw !
Basically, this tgz contains a bunch of files (like the raw framebuffer screen to show while updating) and the script (run) to launch the update...
You should now see where Miles' instructions come from ;)
Extracting payload/image.myg will give you a bzipped partimage file.
I so installed partimage (apt-get install partimage
on Debian) since fdisk doesn't like it...
partimage -z2 infoimage image.myg
.... segmentation fault ... WTF ?!
in fact, it seems something change on partimage or openpeak used their own...
Hopefully, it is on tools\bin folder so use this one
First we create a fake partition image using
dd if=/dev/zero of=myimage bs=1000 count=0 seek=500000
ps: i love the way he did it : write 0 bytes at position 500000*1000 (about 500M..while we only need 200M)
and mount it using mount...well..not exactly.... since myimage is a raw partition mount can't mount it
you need to format it first...but how if we can't mount the image... using the command behind the -o loop option : losetup
losetup /dev/loop0 myimage
ps : I didn't know this one so sorry if the description isn't perfect, it's how I understand it
mounted as /dev/loop0, a partition like could be /dev/sdc1, we can format it
mkfs.ext2 /dev/loop0
and so restore the partition
./partimage -z2 restore /dev/loop0 image.myg
So.. partimage restore image.myg on /dev/loop0 which is in fact myimage
myimage is now a restored partition, like usual.
Release it
losetup -d /dev/loop0
and mount it
mkdir /mnt/jogglerfs
mount myimage /mnt/jogglerfs -o loop
browse /mnt/jogglerfs and learn a lot !
If you browe bin/, you'll notice joggler use in fact busybox 1.17.1.
Useful if you need to call a command in shell.
If you browse boot/ you'll notice joggler use a 2.6.24 kernel
If you browse cfg/etc/Wireless, you'll notice joggler should be able to use a driver for WIFI for Ralink chipset.
if you browse dev/, you'll notice joggler use only one virtual console. Confirmed by etc/inittab.
if you browse etc/, you'll find some useful stuff like etc/fstab which explain that efi/ and media/ are in fact mount points
etc/X11/xorg.conf will tell you joggler use an Sharp LQ070Y3LG4A at 800x480 24bits with an Intel IEGDriver
etc/client.tag was a mistery before I looked in etc/init.d/boot.d scripts : it seems firmware was also used by swisscom, telio, telefonica and openenergy.
Did OpenPeak make a device for Brazil, Norway, US and UK ?!
if you browse openpeak/, you'll find all the apps (SWF file) for the stock O2 Joggler and the programs behind them
var/images seems to be the data for the geolocalisation
but wait...nothing about boot process !
In fact, like said before, look at etc/fstab : the boot script SEEMS to be in /dev/mmcblk0p1
So we need to dump /dev/mmcblk0p1
//TODO
Hopefully, someone already did it !
If you browse ftp://ftp.exotica.org.uk/pub/joggler/files/ , you'll find a dump of mmcblk0
I
if you don't want to use mount, dd again, the EFI 8686 S3 dump is also waiting you !
Else
apt-get install kpartx
modprobe dm-mod
kpartx -l mmcblk0.img
losetup /dev/loop1
mmcblk0.img
kpartx -av /dev/loop1
dd if=/dev/mapper/loop1p1 of=mmc_1.img
dd if=/dev/mapper/loop1p2 of=mmc_2.img
dd if=/dev/mapper/loop1p3 of=mmc_3.img
dd if=/dev/mapper/loop1p4 of=mmc_4.img
mkdir /mnt/mmc_1
mkdir /mnt/mmc_2
mkdir /mnt/mmc_3
mkdir /mnt/mmc_4
mount /dev/mapper/loop1p1 /mnt/mmc_1
mount /dev/mapper/loop1p2 /mnt/mmc_2
mount /dev/mapper/loop1p3 /mnt/mmc_3
mount /dev/mapper/loop1p4 /mnt/mmc_4
....<do stuff on /mnt/mmc_1>
umount /mnt/mmc_1
umount /mnt/mmc_2
umount /mnt/mmc_3
umount /mnt/mmc_4
losetup -d /dev/loop1
kpartx -d /dev/loop1
If you look inside, you'll find the original EFI bootloader (boot.efi) and the infamous startup.nsh
fs1:boot
fs0:boot
Yes, the stock firmware tries to launch a boot(.nsh/.efi?) from USB device before to launch its own boot(.efi) from eMMC
Wow! all this work to confirm something already known ?
Yes, but in the same time, I learnt a way to hack throught a closed device like the Joggler.
So a boot.nsh on USB should contains
fs1:<bootloader_wo_efi_extension>
in the case of the joggler, they almost all use a modified version of GRUB2.
But things change....Torne Wuff did it again : the official GRUB2 now support Joggler without modification.
But what is GRUB ? What it is needed for ?
GRUB loads in fact an Operating System (Linux, Dos, Windows...)
Based on a grub.cfg, GRUB will launch Android (or Linux) with parameters
set timeout = 0
since there is one and only choice (ie not multiboot), don't wait for user choice...difficult without keyboard
menuentry "Android"
define a boot entry called Android. If you could see the GRUB GUI, you'll have to select the "Android" entry
set root=(hd0,1)
any command following are from disk 0, 1st partition.
...disk 0 ? Why ? since we are on USB, we are on disk 1 (fs1) ...
I'm still looking for the meaning of this....
linux /android/kernel root=/dev/ram0 ro video=efifb:off processor.max_cstate=3 LANG=zh SRC=android DATA=/dev/sda2 SDCARD=/dev/block/sda3 DPI=160 ETH_MAC=00:11:22:33:44:55
boots a linux kernel, located at (hd0,1)/android/kernel
others commands following are in fact parameters sent to kernel
initrd /android/initrd.img
load initial RAM disk (on ram0 ????)
initrd.img doesn't contain a initrc nor an init so I don't know what it is used for...
Perhaps referencing the initial devices ?
//TODO