Monday, 16 June 2014

Lenovo S650 with android 4.4.2 and google authenticator (Part 3)

The first part of the series documents the process of upgrading Lenovo S650 from the original 4.2.2 ROM to the new VibeUI ROM which is based on KitKat 4.4.2 and MyUI. The second one documents Google Authenticator issues and a viable alternative. This post lists a few other issues I ran into during the first days of using the new ROM.

Bluetooth file transfer facepalm

I wanted to transfer my updated KeePass database .passwords.kdb to my phone from my thinkpad, but received an error telling me the transfer has failed. After a few attempts I found my thinkpad shows the phone disconnected after the first attempt. Bluetooth file transfers were working fine with Lenovo S650 4.2.2 ROM. To eliminate the possibility that a software update broke bluetooth on the thinkpad, I quickly verified that file transfers are still working between my old Samsung Galaxy Y and my thinkpad.

Apparently, I went down into the garage to check that phone properly connects to my car radio - not being able to issue and receive calls from within my car would have been a major issue and a show stopper. As everything seemed to be just fine, way more stable compared to Samsung Galaxy Y, I returned upstairs to my thinkpad.

After further experiments I found that the thinkpad shows my phone disconnected after around 30 seconds, whether I attempt to initiate file transfers or not. This seems to be a feature and not a bug, a consequence of bluetooth low energy that was not present in the previous 4.2.2 ROM but is included in android 4.4 (4.3+ to be precise).

I have narrowed down the experiments and found the root cause: a stupid bug on the phone prevents me to transfer hidden files (file name starting with a period) to Lenovo 4.4.2 - I have simply renamed the file and successfully sent it to my phone. As I do not have other KitKat devices handy, I cannot test if this is local to Lenovo or a generic android "feature". This limitation is definitely not imposed by the OBEX protocol.

Google Maps 8.1.0 crashing

On the 7th of June, I updates Google Maps to 8.1.0 but later that day found navigation crashing after one or two minutes of operation. As I was on the road (driving) I did not have time to investigate the issue in depth. I have relaunched the application, after the next crash I forcefully stopped the application, later I even rebooted, and purged all application data, but none of these seemed to help in the long run. The issue seemed to be isolated and only affect navigation mode, so I was still able to use Maps, but with much degraded functionality - using directions without navigation and memorizing.

I had to take a pit stop, and purged the application completely, then reinstalled version 8.0.0 which I had backed up on my microSD card. This version is working without a glitch, I just have to ensure not to update to 8.1.0... First I thought there might be an issue with the stock Lenovo VibeUI / 4.4.2 ROM that only comes to surface with this new version of Maps. My recent experience with Google made me decide not to invest more time into tracking down the root cause. Version 8.0.0 serves me well, I decided to stay on this version for a while.

Later that day I have googled to check if others are having issues with 8.1.0, and found thread on xda-developers that perfectly describes my observations. The posts do not contain any solution or detailed investigation. The fact that this issue was observed on a Lenovo 850 ROM made me wonder again if this issue was Lenovo specific... I have also checked recent comments on Maps on Google Play and found many complaints about the recent update, but as the comments do not include the brand/model of the device, this did not help me further.

The bottom line is, going further into investigating the issue with 8.1.0 does not fit into my current schedule and I will stick to 8.0.0 until I find time and motivation to investigate.

Lenovo S650 with android 4.4.2 and google authenticator (Part 2)

The first part of the series documents the process of upgrading Lenovo S650 from the original 4.2.2 ROM to the new VibeUI ROM which is based on KitKat 4.4.2 and MyUI. This post lists a few issues I ran into during the first days of using the new ROM.

Google Authenticator issues

I have been using Google Authenticator's time based one-time passwords as a second authentication factor a few very critical applications for a rather long time. After my recent update, I noticed that I was unable to log in to a critical service as the verification code was rejected. First I thought there must be some sort of time synchronisation issue, so I synchronised the clock from within Google Authenticator application but my authentication attempts were being rejected. I deleted the configuration and re-imported the secret key, however, this did not help.

Needless to say, after a few attempts I was rather nervous as I was under time pressure and worried about my stash... The same version of the application, 2.49, was working flawlessly before the upgrade so I was initially rather sure the error is somewhere on my side. Rather than falling into panic, I quickly searched and found my old Samsung Galaxy Y (android 2.3.6), where the same version, 2.49 was already installed, deleted the old configuration and carefully typed in the base32 representation of my secret key, making sure I do not mix up 0 with O and 1 with I respectively. (At this point I would like to draw attention to Base58 encoding which has an alphabet built with humans in mind, and does not contain characters which are easy to mix up...)

To my surprise I could log in using Google Authenticator on the Samsung device. After taking care of my time sensitive task and calming down, I continued searching for the root cause. The RFC6238 TOTP security token calculation used in Google Authenticator is very simple and publicly available, it only depends on the following two inputs:

  • The shared secret. First I double and triple checked the shared secret was the same on both devices. I gathered definitive evidence by peeking into the SQLite database located at /data/data/com.google.android.apps.authenticator2/databases/databases first via a hex editor, then via sqliteman on my thinkpad. Here is the catch, one can only do that on a rooted device. And definitely, from time to time, one might find himself in a situation where root access is needed for a legitimate purpose...
  • The number of 30 second periods elapsed since the Unix epoch which is based on system time. Although I have synced both devices and the timezone was also the same, I kept getting different tokens on the two devices. I experimented with the timezone settings, changing locale settings and manually setting different timezones but it did not help.

I decided to study the source code - the algorithm is rather simple and both inputs were known to be the same, yet the result were different. The source did not contain any magic, but at the same time I noticed the latest tag in the source repository was 2.21 whereas on both of my devices I had 2.49 - that was at least a bit suspicious. On the project page I found the following disclaimer: "This open source project allows you to download the code that powered version 2.21 of the application. Subsequent versions contain Google-specific workflows that are not part of the project."

I went on and found FreeOTP, a real open source implementation forked from Google Authenticator 2.21, maintained by RedHat. After taking a look at the source, I have installed it onto my S650 and imported my shared secret. Success. Open source rules. I uninstalled Google Authenticator.

Having found a working, very nice, true open source alternative, I have lost motivation to investigate further by decompiling Google Authenticator - unfortunately, I am rather busy these days with my primary duties. My hypothesis, without any proof, is the following: Version 2.49 of Google Authenticator might include some JNI based crypto-acceleration, or something else outside of the Java/Dalvik core libraries, that is not part of any standard, is not documented, therefore not included or works a bit differently in Lenovo ROM. Please leave a comment if you can prove or confute it.

Read on for other issues I encountered in the first few days. Of course, resolution or at least a workaround is provided where applicable.

Thursday, 22 May 2014

Lenovo S650 with android 4.4.2 and google authenticator

I have finally found some spare hours to upgrade my Lenovo S650 from the 4.2.2 based S650_S119_131014 ROM to S650_S912_VIBEUI_V1.5_1419_5_ST_1F49 which is based on 4.4.2. As a first step, I have studied the contents of the zip file, especially the updater-script at /META-INF/com/google/android/. It quickly became obvious that I would loose my root access after installing this update, which I wanted to avoid.

The rules I have set for myself do not allow rooting the phone via windows based third party applications (some of which are known to install some souvenirs), and the common path of using the windows-only MediaTek flashing tool in the rooting process is also out of scope for me. For private reasons I decided to not publish information on how to properly root the lenovo ROM via command line, without any closed source, suspicious third party app. Rather than that, let us assume that the original JellyBean system already has root access, and our goal is to retain this during the upgrade.

While setting the immutable flag on the su binary via chattr +i /system/xbin/su would retain root access during minor updates, this is useless if the system partition is formatted. In our case, all partition except sdcard{0,1} would be formatted as it can be seen in the updater-script.

Adding the binary to the itself zip and amending the updates-script with a command to set proper SELinux context, ownership and permissions come as an intuitive solution. This can be achieved by the following line:


set_metadata("/system/xbin/su", "uid", 0, "gid", 0, "mode", 6755, "capabilities", 0x0, "selabel", "u:object_r:su_exec:s0")

One should note that the zip file is a singed jar, and any tinkering would cause signature verification to fail. Although there are various approaches for bypassing signature verification, no magic is needed due to the fact that the current system is already rooted. Custom recovery images allow to install updates without a [valid] signature.

Custom recovery

Readers who have familiarized themselves with the previous post should already know how to 'flash a custom recovery' with a single line.

dd of=/dev/block/mmcblk0 if=recovery.img bs=1024 seek=36352

As an alternative, one can use Mobileuncle MTK Tools to install a custom recovery - if one renames the file to recovery.img and places it into the root of the SD card, the app will automatically pick it up.

I have used TWRP recovery 2.7.0.0. The Lenovo S650 come in two variants, which have different partition layouts. When using pre-built recovery images, make sure to use an image compatible with CN (Chinese) or ROW (Rest Of the World) partition layout according to your device.

The first thing after installing the custom recovery was to test it - taking a TWRP backup of the current system. Actually, testing the backup process is only half of the job, since the recovery process is slightly more important...

Superuser application

While this post is not going to cover the process of rooting, the basic concept of how root permission is granted is outlines. The su binary, unlike in traditional Unices, will not ask for credentials but instead, communicate with a graphical application that will display the details of the 'switch user' request and allow the end user to approve or reject the request via the touchscreen.

As any flaw of the su binary or the superuser application, intentional or unintentional, may critically impact the security of the device, one should consider if this capability is needed at all, and if so, which implementation to chose.

While SuperSU and ChainsDD Superuser are common choices, I decided to go with Koushik Dutta's Superuser. Unlike the other two it is open source, so I have taken some time to go through the source of both the native binary and the app. Additionally it features PIN protection and logging, which typically would not be available in the free versions of other alternatives.

I have downloaded the zip file, and studied the updater-script. I modified the 4.4.2 ROM by adding the binary and the application and changing the scripts to ensure proper metadata is set on the binary.

Google apps

I have downloaded a signed intallable zip of minimal Google Apps for 4.4.2 - this only takes a few megabytes and allows me decide which apps fo google to install later.

The point of no return

I have observed that while the ROM updater-script does not replace the recovery, it installs a script that runs on normal boot and patches the recovery. In worst case, this could mean that I end up with a non-rooted system and my custom recovery, that would allow me to alter the system (install unsigned updates), would be erased and replaced by Lenovo's restricted recovery image. That would have been game over for me.

I have copied the vanilla ROM, the superuser installer and GApps installer zips to the SD card, along with my modified "superuser-included" ROM zip and rebooted to recovery. I performed an advanced wipe selecting user data, cache and dalvik-cache to be erased and then attempted to install the modified ROM.

In the middle of the process, I received an error notifying me that update-binary had failed. The second attempt yielded the same results, leaving the system in an unknown state. I payed attention not to reboot a single time until I was sure the system was properly installed and rooted, or at least the custom recovery image was still in place.

I had to fall back to 'plan B' and installed the vanilla ROM, but instead of rebooting, quickly installed the superuser installer zip as well. Once done, I opened a shell and manually checked the presence and metadata of the su binary and the superuser application. Then I rebooted.

Make space and install GApps

On first boot, I realised there was almost no space on the system partition, so I removed some of the apps like Youyue, GameWorld and Baidu, then took the opportunity to uninstall some preintalled non-system apps like Weibo, QQ and Lakala. I intentionally retained many system apps by Lenovo - in some cases they are really useful and feature rich alternatives to some Google components.

If one is concerned about privacy and decides not to go with Lenovo apps, then the very same person should also be worried about installing any Google component onto his device... Instead of engaging in a religious debate, look at what kind of traffic the various components cause, and block according to your findings.

Once there was 100MB free space on the system partition, I installed the minimal google apps package and rebooted - and singed into my google account. Play store services worked fine, and nothing gave me significant headache... until I tried to use google-authenticator...

Read on, the second part of the series is already available.

Monday, 14 April 2014

Backing up a stock Lenovo S650/MT6582 phone from shell

Right after unboxing my S650, before even booting into normal mode I wanted to clone the preloaded firmware. This device is my first personally owned android smartphone and I wanted to make sure I have a backup of the original state before tinkering or flashing a custom ROM. The rules, as implied by the above statement, were the following:

  • Flashing a custom recovery was not allowed.
  • The use of third party applications other than those that come preloaded on the Mediatek device was not allowed, as installing those would have 'tainted' the original state.
  • Linux only. Running any M$ Windows tool was strictly out of scope.
  • More of an unfortunate circumstance than a rule, but I did not have an external microSD card handy, so I had to rely using the internal storage.

I would not position myself as an android expert in any way, as this almost my first encounter of a modern android device. Trying to make use of the skills I have, I have taken a Linux centric approach. After all, my smartphone is just an ARM based mini computer with embedded NAND flash storage running Linux...

Before my phone arrived, I read a few articles on how a full backup could be taken, how recovery works and what the boot process of an android devices is like. This post is not going to cover these basics. My first idea was to boot my phone using a custom recovery image stored on my thinkpad, without actually flashing the recovery image. This involves rebooting the device into bootloader mode and connecting it to my thinkpad via USB.

Factory mode, Bootloader, fastboot and recovery

Having initiated the first boot with the power & volume up buttons pressed, I was confronted with a Chinese menu, which turned out to be not the recovery mode, but the factory mode with options similar to the following:

工厂模式
完整测试
单项测试
测试报告
清除e MMC
版本信息
重启手机 

The only familiar character sequence 'eMMC' suggested that option was responsible for wiping the whole internal storage, while the default selection would reboot the phone. A couple of days later I found a forum post that contained translation of these (or very similar) menu items.

The phone was connected to my thinkpad via a USB cable, but I did not have connectivity to the device, although I would have expected some sort of connection via the Android SDK.

After this, I rebooted into recovery mode via power, volume up & volume down buttons and realised that the stock recovery also does not provide any means to connect to the device from my thinkpad.

Finally I could reboot the device into bootloader mode (also known as fastboot mode). I had to start up the device normally, select 'Media device (MTP)' when configuring the mode of USB connection and enable USB debugging. I have found that 'Camera (PTP)' or 'Mass storage' modes do not allow the execution of Android De bug Bridge (adb) commands.

Once the device was connected, which I confirmed via adb devices, I could reboot the device into bootloader mode via adb reboot bootloader. The devices rebooted and printed that it entered fastboot mode. I confirmed that the output of adb devices does not list the device as ready for connection (as the device was in bootloader mode), and that fastboot devices outputs that the device is present and in fastboot mode.

From within bootloader mode, the command fastboot boot custom-recovery.img is should boot a custom recovery without actually flashing it. I my case, however, the device printed it downloaded the image successfully but I was left with a 'Booting ...' message and a frozen device, that did not do anything for twenty minutes, even did not respond to the power button.

I took out the battery, reinserted it an everything was back to normal. I thought the recovery image I tried to boot was not built for this phone or maybe it was corrupted, so I tried it with multiple images that were told to work with my S650. Nor the CWM, nor the TWRP image seemed to work. I had to take an alternative approach.

Backing up manually, using the shell

Eventually, I rebooted to normal mode and worked towards my goal via adb shell which gave me shell access so I could make use of my linux experience. Some commands essentially require root access - note that rooting an S650 is not covered in this post, but the ability to gain root access is assumed.

First of all, I had to discover how the eMMC storage was partitioned and which parts I need to take a backup of.


$ cat /proc/partitions
major minor  #blocks  name

   7        0      10290 loop0
 253        0     524288 zram0
 179        0    7597184 mmcblk0
 179        1          1 mmcblk0p1
 179        2      10240 mmcblk0p2
 179        3      10240 mmcblk0p3
 179        4       6144 mmcblk0p4
 179        5    1048576 mmcblk0p5
 179        6     131072 mmcblk0p6
 179        7    3145728 mmcblk0p7
 179        8    3202688 mmcblk0p8
 179       64       2048 mmcblk0boot1
 179       32       2048 mmcblk0boot0

$ cat /proc/dumchar_info
Part_Name Size StartAddr Type MapTo
preloader    0x0000000001400000   0x0000000000000000   2   /dev/misc-sd
mbr          0x0000000000080000   0x0000000000000000   2   /dev/block/mmcblk0
ebr1         0x0000000000080000   0x0000000000080000   2   /dev/block/mmcblk0p1
pro_info     0x0000000000300000   0x0000000000100000   2   /dev/block/mmcblk0
nvram        0x0000000000500000   0x0000000000400000   2   /dev/block/mmcblk0
protect_f    0x0000000000a00000   0x0000000000900000   2   /dev/block/mmcblk0p2
protect_s    0x0000000000a00000   0x0000000001300000   2   /dev/block/mmcblk0p3
seccfg       0x0000000000020000   0x0000000001d00000   2   /dev/block/mmcblk0
uboot        0x0000000000060000   0x0000000001d20000   2   /dev/block/mmcblk0
bootimg      0x0000000000600000   0x0000000001d80000   2   /dev/block/mmcblk0
recovery     0x0000000000c00000   0x0000000002380000   2   /dev/block/mmcblk0
sec_ro       0x0000000000600000   0x0000000002f80000   2   /dev/block/mmcblk0p4
misc         0x0000000000080000   0x0000000003580000   2   /dev/block/mmcblk0
logo         0x0000000000300000   0x0000000003600000   2   /dev/block/mmcblk0
ebr2         0x0000000000080000   0x0000000003900000   2   /dev/block/mmcblk0
expdb        0x0000000000a00000   0x0000000003980000   2   /dev/block/mmcblk0
android      0x0000000040000000   0x0000000004380000   2   /dev/block/mmcblk0p5
cache        0x0000000008000000   0x0000000044380000   2   /dev/block/mmcblk0p6
usrdata      0x00000000c0000000   0x000000004c380000   2   /dev/block/mmcblk0p7
fat          0x00000000c37a0000   0x000000010c380000   2   /dev/block/mmcblk0p8
bmtpool      0x0000000001500000   0x00000000febf00a8   2   /dev/block/mmcblk0
Part_Name:Partition name you should open;
Size:size of partition
StartAddr:Start Address of partition;
Type:Type of partition(MTD=1,EMMC=2)
MapTo:actual device you operate

As it could be seen, most of the relevant data is on /dev/block/mmcblk0 and there are critical areas on the flash storage that are not mapped to any partition. An obvious solution was to use the almightly dd command and calculate proper count and skip parameters based on the output above.

It should be noted that the content of the preloader that is mapped to /dev/misc-sd is directly available under /dev/preloader.


dd if=/dev/preloader of=preloader

dd if=/dev/block/mmcblk0 of=mbr.img bs=1024 count=512 skip=0
dd if=/dev/block/mmcblk0 of=ebr1.img bs=1024 count=512 skip=512
dd if=/dev/block/mmcblk0 of=pro_info.img bs=1024 count=3072 skip=1024
dd if=/dev/block/mmcblk0 of=nvram.img bs=1024 count=5120 skip=4096
dd if=/dev/block/mmcblk0 of=protect_f.img bs=1024 count=10240 skip=9216
dd if=/dev/block/mmcblk0 of=protect_s.img bs=1024 count=10240 skip=19456
dd if=/dev/block/mmcblk0 of=seccfg.img bs=1024 count=128 skip=29696
dd if=/dev/block/mmcblk0 of=uboot.img bs=1024 count=384 skip=29824
dd if=/dev/block/mmcblk0 of=bootimg.img bs=1024 count=6144 skip=30208
dd if=/dev/block/mmcblk0 of=recovery.img bs=1024 count=12288 skip=36352
dd if=/dev/block/mmcblk0 of=sec_ro.img bs=1024 count=6144 skip=48640
dd if=/dev/block/mmcblk0 of=misc.img bs=1024 count=512 skip=54784
dd if=/dev/block/mmcblk0 of=logo.img bs=1024 count=3072 skip=55296
dd if=/dev/block/mmcblk0 of=ebr2.img bs=1024 count=512 skip=58368
dd if=/dev/block/mmcblk0 of=expdb.img bs=1024 count=10240 skip=58880
dd if=/dev/block/mmcblk0 of=android.img bs=1024 count=1048576 skip=69120
dd if=/dev/block/mmcblk0 of=cache.img bs=1024 count=131072 skip=1117696

dd if=/dev/block/mmcblk0 bs=1024 count=3145728 skip=1248768 | gzip > usrdata.img.gz
#dd if=/dev/block/mmcblk0 of=fat.img bs=1024 count=3202688 skip=200192

#dd if=/dev/block/mmcblk0 of=bmtpool.img bs=1024 count=21504 skip=4173760.1640625

A final note on the last few commands

At the time of taking the backup, I did not have an external sdcard, so I had to use the FAT partition of the device, which was 3GB in size. Obviously, as an immediate consequence, the related line is commented out, as trying to write the image of the FAT partition to the FAT partition itself would not be the brightest idea, would it? The content of this partition can be simply accessed and copied over to a PC by selecting USB connection mode 'Storage device'.

Further, backing up the usrdata partition, which in size is similar to the partition to which the backup was stored, needed a small trick. Given that the partition was almost empty (confirmed via df), I gzipped the image on the fly to make sure, and ended up with a 315MB compressed image.

I did not find much information on bmtpool. It is not mapped to a partition and has a start address which is not aligned to 512 bytes, so it could not be properly backed up via Windows based SP FlashTool according to multiple sources. Actually, nobody seems to have missed the contents of this section.

Tinkering with the raw backups

Some of the backed up files represent the raw copy of whole partitions, these can be directly loop-mounted on linux. Others such as boot.img or recovery.img need another approach.

Based on my experience with initramfs and kernel images, I initially tried to uncompress them via gunzip and cpio, but looking at them via a hex editor revealed that these are amended by a special header. I have quickly googled up a perl script from clockworkmod which was built for unpacking recovery images, but soon it turned out that MT6582 MediaTek devices use a special format that can be unpacked via this script.

Just out of curiosity, I studies the directory structure of the boot and recovery images and confirmed that my smartphone is indeed just a special linux device...

Restoring manually

Restoring is straightforward. Use the same dd commands, but swap the value of if and if, and replace skip with seek. And do make sure to slightly modify the command for usrdata.img.gz, using gunzip. This one is left as an exercise for the reader.

Sunday, 21 July 2013

Changing UIDs of service accounts on Linux

About a month ago I was setting up a proprietary identity management solution on headless Linux servers. During the installation process I tried to keep the number of installed packages and libraries to the bare minimum, to create an as-lean-as-possible setup as opposed to the bloated 'typical' deployments.

This goal in tandem with my choice to use the most up to date version of the target Linux distribution resulted in an 'advanced' installation procedure using the command line. While it was no surprise that the graphical installshield wizard did not start due to missing libraries on the headless server, it surprise me that non-GUI installation failed each time during setting up service accounts.

Having tried various combinations, disabling SELinux, and even creating the service account manually before re-running the installer, it still kept failing. A quick search on the internet did not yield any useful hint, but looking deeper, so I investigated further. Enabled debug logging for the installshield wizard, then extracted the embedded Java installer from the blob, and found that various native binaries are unpacked and executed during the installation process.

One of these binaries was linked against an older version of a shared library (libstdc++.so.5) that was not available in any of the packages any more. As a quick and dirty workaround I quickly created a symlink with that name pointing to libstdc++.so.6, and confirmed this resolved the problem.

The installation was successful, however, it left me with a technical user and group that I did not fancy.


$ grep ldap /etc/passwd /etc/group
/etc/passwd:idsldap:x:502:501::/home/idsldap:/bin/ksh
/etc/group:idsldap:x:501:root

  • First and foremost, I prefer technical accounts to have numberic UIDs from the range reserved for system accounts, as opposed to having them created as normal users. This range varies by distribution, RedHat & SuSE based distros reserve UIDs smaller than 500 for system accounts while Debian based ones create normal users with the first available UID after 999.
  • If I have the control over the numeric values, I prefer to introduce some semantics into the naming convention, like creating the technical user for an LDAP server with UID 389. This is just a cosmetic point with no real impact, but as I had to change the UID anyway...
  • Last but not least, I very strongly dislike if the group which is the dedicated primary group of a service account, uses the same name as the service user but a different numeric ID.

This post will cover the commands I applied to fix the UID and GID of the service user and group. File ownership is automatically fixed, but only for the files under the home directory (and mail spool) of the user, so additional commands were needed to also fix file ownership or files located elsewhere.


$ find / -user idsldap | less
$ usermod -u 389 idsldap
$ find / -user idsldap | less # you see that ownership is only updated under the home directory and mail spool
$ find / -user 502 | less # the old uid is still present on other files
$ find / -user 502 -exec chown idsldap {} \;
$ find / -user 502 | less # almost done, but by default, symbolic links are dereferenced, therefore not affected.
$ find / -user 502 -exec chown -h idsldap {} \;
$ find / -user 502 # none - confirms we are done.

$ find / -group 501 | less
$ groupmod -g 389 idsldap
$ find / -group 501 -exec chgrp -h idsldap {} \;
$ find / -group 501 # confirm we are done
$ find / -group idsldap | less # this gives the same output the first group related command

While most people probably would not put any effort into changing UIDs but rather leave it that way or reinstall from scratch, I do believe that this case was worth investing a bit of extra time.

Saturday, 22 June 2013

OpenCL, Python and Ubuntu 12.10 (Part 2)

Using multiple OpenCL devices for computation intensive tasks might turn out to be a bit more challenging. Distributing load between heterogeneous GPUs is straightforward, however, ensuring that one gets the cumulative performance of all the GPUs to the same level as the sum of the individual devices is a bit tricky. At least with the drivers that ship with Ubuntu 12.10.

The current case that motivated this post is tweaking a configuration with multiple AMD GPUs of different generations. There is much controversial information available on whether an X session is required or not, whether to use crossfire cables or not, and whether dummy-plugs are required or not. It also seems to be less certain if and how cards of different generations play together.

Having searched the internet for utilities that help in debugging OpenCL related issues I decided to create my own version, that is not extremely chatty but provides a quick overview of the devices recognised along with their most important performance related parameters. The code is based on a script I found on a forum, extended and customized to match my needs.


#!/usr/bin/python

# 2013-04-03 03:35:03 

import sys
import os
import time
import platform
import imp

def getPyOpenCLPath():
    try:
        file, pathname, descr = imp.find_module('pyopencl')
    except:
        pathname = 'Not found'
    return str(pathname)

path = getPyOpenCLPath()

print 'opencl-info @ %s' % time.asctime()
print 'Operating System: %s %s' % (platform.system(), platform.dist())
print 'Python Version: %s (%s)' % (platform.python_version(), platform.architecture()[0])
print 'PyOpenCL Path: %s' % path

if path == 'Not Found':
    print 'Exiting' 
    sys.exit()

try:
    import pyopencl
    import pyopencl.version
except:
    print 'Unable to load PyOpenCL! OpenCL not supported?'
    sys.exit()
 
print 'PyOpenCL Version: %s' % pyopencl.VERSION_TEXT

try:
    platforms = pyopencl.get_platforms()
except:
    print 'Cannot get platform.'

if len(platforms) == 0:
    print 'No OpenCL platforms found!' 
    sys.exit()

count = 0

for i,p in enumerate(platforms):
    print ''
    print '[cl:%d] %s' % (i, p.name.replace('\x00','').strip())
    for k in ['vendor', 'profile', 'version']:
        print '    %s %s' % ((k + ':').ljust(16), getattr(p,k))
    print ''

    devices = platforms[i].get_devices()
    if len(devices) > 0:
        # Iterate through devices
        for j,d in enumerate(devices):
            count += 1
            print '    [cl:%d:%d] %s' % (i, j, d.name.replace('\x00','').strip())
            print '        type:                %s' % pyopencl.device_type.to_string(d.type)
            print '        memory:              %d MB' % (d.global_mem_size//1024//1024)
            print '        compute units:       %s' % d.max_compute_units
            print '        max clock:           %s MHz' % d.max_clock_frequency
            print '        max work group size: %s' % d.max_work_group_size
            print '        max work item size:  %s' % d.max_work_item_sizes
            # Iterate through device info
            #for name in filter( lambda x: not x.startswith('_'), dir(d)):
            #    try:
            #        print(name + ': '+ str(getattr(d, name)))
            #    except:
            #        print(name + ': (skipped)')

After trials and errors and a bit of tinkering I was able to set up the environment to run fine without an X session, without crossfire cables and without any dummy plug, and yield optimal performance. Documenting the configuration details are beyond the scope of this post, however the script above is provided to help others in OpenCL related debugging and optimisation.

Saturday, 18 May 2013

Tracking down TrackPoint issues (Part 2)

This post in a follow up on Tracking down TrackPoint issues. I have noticed few days ago, that hot-plugging a USB mouse "does not work". I normally do not plug a mouse into my thinkpad, so this did not come to my attention so far.

After seeing my cursor would not move after plugging in the mouse, I decided to gather more information, starting with dmesg to verify the device is connected and recognized. Then, I inspected the output of xinput list and found that the mouse is listed as a floating slave. Manually running xinput enable "HID 04b3:3107" fixed the situation, it attached the floating device as a slave to "Virtual core pointer".


⎡ Virtual core pointer                     id=2 [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer               id=4 [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad               id=12 [slave  pointer  (2)]
⎜   ↳ TPPS/2 IBM TrackPoint                    id=14 [slave  pointer  (2)]
⎜   ↳ HID 04b3:3107                            id=15 [slave  pointer  (2)]
⎣ Virtual core keyboard                    id=3 [master keyboard (2)]
    ↳ Virtual core XTEST keyboard              id=5 [slave  keyboard (3)]
    ↳ Power Button                             id=6 [slave  keyboard (3)]
    ↳ Video Bus                                id=7 [slave  keyboard (3)]
    ↳ Video Bus                                id=8 [slave  keyboard (3)]
    ↳ Sleep Button                             id=9 [slave  keyboard (3)]
    ↳ Integrated Camera                        id=10 [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard             id=11 [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons                   id=13 [slave  keyboard (3)]

After restarting my X session - logging out and back in - with the mouse already connected I found it to be enabled and working correctly.

My conclusion was that the device got connected but not enabled after hot-plugging. I revisited my custom hotplug command in .local/bin/touchpad-config (see the previous post referred to above). This script was executed whenever on startup, and then, whenever a device is added or removed. Obviously, the touchpad and trackpoint related commands do not need to be run when an external mouse is connected. They are also needless when any device is disconnected.

I was searching for a way to detect which device is being added or removed and preform different logic based on that and came across this example in the GNOME git repository on github. It clearly demonstrated how device information and action is handed over to the script and allowed me to enhance my script with logging so I could see what was happening under the hood.

Eventually, it turned out that my script was only executed a couple of times on startup, but not invoked at all after that when the mouse was hot-plugged. It boiled down to be caused by some cruft in my Xorg configuration, left over after having explored Optimus related tweaks covered in my other posts. I had to change Option "AutoEnableDevices" "false" in xorg.conf.

Although the original issue was fully resolved by the before mentioned change in to xorg.conf, the sub-optimal .local/bin/touchpad-config was still bugging me so I altered it to only execute the commands relevant for the event that triggered the script. I ended up with the following hotplug-script, which is working flawlessly in my environment:


#!/bin/sh

action=$2
shift 4
device=$@

log () {
 echo "$1" >> /tmp/hotplug-cmd.log
}

log "$action '$device'"

if [ x"$action" = xadded -o x"$action" = xpresent ]; then
 case $device in
  "SynPS/2 Synaptics TouchPad")
                 synclient PalmDetect=1 PalmMinWidth=5 \
    TapButton3=2 HorizTwoFingerScroll=1
   log "configured touchpad"
                 ;;
         "TPPS/2 IBM TrackPoint")
                 xinput disable "<default pointer>" 
                 xinput enable "TPPS/2 IBM TrackPoint"
   log "disabled <default pointer>, enabled trackpoint"
                 ;;
         *)
                 log "nop"
                 ;;
 esac
fi

Note that the script above still includes logging which may be safely removed.