MarioDebian, mi devlog

Bitácora de un desarrollador newbie.

Mi primer app en android: RsyncDroid

Presento mi nueva aplicación (mejor no mirar el código) para android: RsyncDroid.

Es como si fuese un HolaMundo pero un poco más complejo, pero me ha servido para aprender un poco Java y sobre todo para ver su entorno de desarrollo basado en Eclipse. El debugger (ddms) es la leche y se puede estudiar muy bien lo que va haciendo nuestra aplicación mientras se ejecuta... me ha gustado.

Instalación

Lo primero es conseguir el binario de rsync, he preparado este script (necesita ser root del teléfono)

wget http://adqmisc.googlecode.com/svn/trunk/androidutils/rsync/rsync-3.0.6-arm-softfloat-linux-gnueabi.gz
zcat rsync-3.0.6-arm-softfloat-linux-gnueabi.gz > rsync

./adb push rsync /sdcard/rsyncdroid/rsync
./adb shell mount -o remount,rw /dev/block/mtdblock0 /system
./adb shell "cat /sdcard/rsyncdroid/rsync > /system/bin/rsync"
./adb shell chmod 755 /system/bin/rsync
./adb shell mount -o remount,ro /dev/block/mtdblock0 /system

Ahora instalaremos este apk: rsyncdroid.apk

./adb install -r ~/Desktop/rsyncdroid.apk
401 KB/s (18269 bytes in 0.044s)
    pkg: /data/local/tmp/rsyncdroid.apk
Success

Capturas de pantalla

El programa es muy sencillo, lo que hace es arrancar, parar y ver el estado del proceso rsync, si no existe la configuración usa una base en la que se comparte el contenido de la memoria SD. Es recomendable añadir algo como "hosts allow = xx.xx.xx.xx", para permitir el acceso sólo desde la IP que queramos (man rsyncd.conf).

La primera vez que lo ejecutemos nos pedirá el permiso de root (rsync se ejecuta en un puerto privilegiado).

Script para copia de datos

rsync -Pavz --no-g --no-p --no-numeric-ids \
    htcmagic::sdcard/ --delete /home/mario/htcmagic/backup/

Yo me he hecho un script un poco más complejo para (por la madrugada) hacer ping al teléfono y si está en la wifi de mi red hacer la copia incremental (creando enlaces duros) y borrando las copias de seguirdad que tengan más de 30 días.





Diferencias entre algo sencillo y algo enrevesado

Hoy me he puesto a intentar hacer una cutre aplicación para Android (que está tan de moda) y de paso a programar mis primeras líneas en JAVA. ¿Quén inventó ese lenguaje del diablo? Se merece las 7 plagas seguidas de una lapidación pública, y voy a ello con un ejemplo muy simple.

Vamos a intentar partir una cadena de texto por espacios, en Python:

>>> a="esto   es una cadena   de texto"
>>> a.split()
['esto', 'es', 'una', 'cadena', 'de', 'texto']

Nótese que entre alguna de las palabras hay más de un espacio.

Ahora vamos a hacerlo en JAVA:

public class test {
public static void main(String args[]) {
String a;
String [] aArray;
int i;
a="esto   es una cadena   de texto";
aArray=a.split(" ");
for (i=0; i<aArray.length; i++) {
System.out.println("index=" + i + " aArray=" + aArray[i]);
}
}
}

Que como resultado da:

index=0 aArray=esto
index=1 aArray=
index=2 aArray=
index=3 aArray=es
index=4 aArray=una
index=5 aArray=cadena
index=6 aArray=
index=7 aArray=
index=8 aArray=de
index=9 aArray=texto

No quiero ir de listillo, pero necesitar 6 veces más código para no hacerlo bien es como volver al esamblador. He intentado hacer aArray=a.trim().split(" ") pero ni con esas...seguro que hay una forma rebuscada de hacerlo, en python no hay que pensar tanto. Además es bastante más lento que python y eso que se ejecuta compilado en bytecode:

$ time python -c "a='esto   es una cadena   de texto'; print a.split()" >/dev/null
real	0m0.026s
user	0m0.020s
sys	0m0.004s
$ time java test > /dev/null
real	0m0.135s
user	0m0.064s
sys	0m0.016s




Compilando rsync en Android

Hace muy pocos días que he aterrizado en el mundo de android pero creo que voy avanzando poco a poco. Voy a publicar una minireceta de como compilar utilidades linux (sencillas) nativamente en Android. Antes de empezar sería bueno recordar que los binarios de Android se compilan para arquitectura ARM por lo que o usamos un emulador (tipo qemu) o un toolchain. Yo he usado el toolchain para compilar nativamente, con el emulador deberíamos compilar en estático y el binario ocupará bastante más. Vamos por pasos:

1.- Descargar el git de android, viene muy bien explicado aquí. Yo lo he descargado en mi $HOME/toolchain.

mkdir ~/toolchain
cd toolchain
wget http://android.git.kernel.org/repo
chmod +x repo
./repo init -u git://android.git.kernel.org/platform/manifest.git
./repo sync

2.- Hora de tomarse algo, descarga la friolera de 2.1 GiB, seguimos, hay que compilar la parte base (librerías)

make BUILD_TINY_ANDROID=true

3.- Tarda otro buen ratillo, ahora compilamos la parte oprofile (lo he compilado aquí porque así tenía a mano los includes de popt.h que son los únicos que he necesitado), cargamos el entorno de ayuda y compilamos el directorio actual y subdirectorios con "mm":

cd external/oprofile
. ../../build/envsetup.sh
mm 

4.- Ahora descargamos las fuentes de rsync (pueden valer las de Debian)

dget -u http://ftp.uk.debian.org/debian/pool/main/r/rsync/rsync_3.0.6-1.dsc
cd rsync-3.0.6

5.- La parte que más me ha costado ha sido entender los Makefile de Android que se llaman Android.mk. Este es mi Android.mk para rsync:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
flist.c\
rsync.c\
generator.c\
receiver.c\
cleanup.c\
sender.c\
exclude.c\
util.c\
main.c\
checksum.c\
match.c\
syscall.c\
log.c\
backup.c\
options.c\
io.c\
compat.c\
hlink.c\
token.c\
uidlist.c\
socket.c\
hashtable.c\
fileio.c\
batch.c\
clientname.c\
chmod.c\
acls.c\
xattrs.c\
progress.c\
pipe.c\
params.c\
loadparm.c\
clientserver.c\
access.c\
connection.c\
authenticate.c\
lib/wildmatch.c\
lib/compat.c\
lib/snprintf.c\
lib/mdfour.c\
lib/md5.c\
lib/permstring.c\
lib/pool_alloc.c\
lib/sysacls.c\
lib/sysxattrs.c\
zlib/deflate.c\
zlib/inffast.c\
zlib/inflate.c\
zlib/inftrees.c\
zlib/trees.c\
zlib/zutil.c\
zlib/adler32.c\
zlib/compress.c\
zlib/crc32.c
LOCAL_SRC_FILES += netbsd_getpass.c
LOCAL_STATIC_LIBRARIES := \
libpopt
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \
$(LOCAL_PATH)/../libdb \
$(LOCAL_PATH)/../libutil \
$(LOCAL_PATH)/../libop \
$(LOCAL_PATH)/../libabi
LOCAL_MODULE := rsync
include $(BUILD_EXECUTABLE)

El archivo netbsd_getpass.c lo he tomado de ~/toolchain/external/dropbear/netbsd_getpass.c ya que Android no debe tener la rutina getpass(), sólo se usa si la rutina getpassf() de rsync nativa falla.

6.- A compilar toca, sólo hay que ejecutar "mm" dentro del directorio rsync-3.0.6 y si todo va bien veremos al final:

target Executable: rsync (out/target/product/generic/obj/EXECUTABLES/rsync_intermediates/LINKED/rsync)
target Non-prelinked: rsync (out/target/product/generic/symbols/system/bin/rsync)
target Strip: rsync (out/target/product/generic/obj/EXECUTABLES/rsync_intermediates/rsync)
Install: out/target/product/generic/system/bin/rsync
make: se sale del directorio `/home/mario/toolchain'

7.- Para copiarlo al móvil (conectar el cable USB y activar el modo depuración USB en las preferencias)Necesitamos el SDK de Android.

cd ~/sdk/tools
sudo ./adb kill-server
sudo ./adb remount
sudo ./adb push ~/toolchain/out/target/product/generic/system/bin/rsync /system/bin
sudo ./adb shell chmod 755 /system/bin

Ya podemos abrir el terminal desde android (o desde adb shell) y ejecutar rsync para ver si se copio bien.

Se me ocurren miles de cosas sencillas (GScript + rsync) para tener las fotos publicadas en un blog, hacer copias de seguridad remotas (incrementales) o incluso usarlo para descargar contenido pudiendo perder la conexión temporalmente.

Rizando el rizo, estaría guapo hacer un pequeño frontend con las opciones más usadas y llamarlo desde una aplicación APK.

Como próximo objectivo compilar alguna otra cosa que hecho en falta (¿git? etc...)