Author Topic: C for Android  (Read 30202 times)

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
C for Android
« on: July 11, 2012, 12:01:10 AM »
I installed the C4droid compiler and GCC plug-in. Here is my test Hello ScriptBasic compiled on my Samsung Galaxy Tab 2 10.1 tablet. Believe it or not, you can compile C programs on a non-rooted device. Using the /data/local/... gets around the requirement to use the /data/data/app_id directory structure for ownership and permissions management. I sure hope this doesn't change in future Android releases.

shell@android:/data/local/c4bin $ ls -l
-rwxrwxrwx app_101  app_101      3409 2012-07-11 00:51 c.out
shell@android:/data/local/c4bin $ ./c.out
Hello ScriptBasic
32|shell@android:/data/local/c4bin $
« Last Edit: July 11, 2012, 10:14:18 AM by support »

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #1 on: July 28, 2012, 11:57:33 AM »
It would be cool if I could get a ScriptBasic distribution going that was compiled native on Android. There are a lot of unknowns so I thought I would try getting BaCon working on Android first. Here is where I am with that effort.

I'm happy to report that sockets and console screen attributes seem to be working fine under Android. BaCon's runtime is about 45KB but the executables don't get much bigger even with user specific code. Other than REGEX not working, BaCon seems to work well under Android. This was just a proof of concept effort. If there is any real interest in this, I will put together an ADB install that includes the following.

  • bash for Android
  • C4droid + gcc plug-in
  • bacon.bash
  • getting started docs

Based on want I have going with SB, I should be able to create a BaCon install that allows the user to compile scripts and not have to root their device to do so.

BINDUMP


MASTERMIND
« Last Edit: July 28, 2012, 11:59:26 AM by support »

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #2 on: July 30, 2012, 03:00:22 AM »
I have seen the light.  :o

This is a SDL native Android Linux example using the Android native app glue API. I'm able to touch the screen and spin the cube in any direction. It's as fast as any desktop I've run the same OpenGL cube demo on. (smooth as silk) It runs in its own thread, with its own
event loop for receiving input events and doing other things.  From what I read, Java based application are single threaded only. I would think this would attract some interest from the gaming community.

I compiled this demo on my non-rooted SGT2_10.1 tablet.

Attached zip contains the demo in a .apk install package for android. (make sure you enable off market apps)



Code: [Select]
#include <jni.h>
#include <errno.h>

#include <EGL/egl.h>
#include <GLES/gl.h>

#include <android/sensor.h>
#include <android/log.h>
#include <android_native_app_glue.h>

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))

/**
 * Our saved state data.
 */
struct saved_state {
    float angle;
    int32_t x;
    int32_t y;
};

/**
 * Shared state for our app.
 */
struct engine {
    struct android_app* app;

    ASensorManager* sensorManager;
    const ASensor* accelerometerSensor;
    ASensorEventQueue* sensorEventQueue;

    int animating;
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    int32_t width;
    int32_t height;
    struct saved_state state;
};

/**
 * Initialize an EGL context for the current display.
 */
static int engine_init_display(struct engine* engine) {
    // initialize OpenGL ES and EGL

    /*
     * Here specify the attributes of the desired configuration.
     * Below, we select an EGLConfig with at least 8 bits per color
     * component compatible with on-screen windows
     */
    const EGLint attribs[] = {
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8,
            EGL_NONE
    };
    EGLint w, h, dummy, format;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, 0, 0);

    /* Here, the application chooses the configuration it desires. In this
     * sample, we have a very simplified selection process, where we pick
     * the first EGLConfig that matches our criteria */
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);

    /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
     * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
     * As soon as we picked a EGLConfig, we can safely reconfigure the
     * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
    eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);

    ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);

    surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
    context = eglCreateContext(display, config, NULL, NULL);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
        LOGW("Unable to eglMakeCurrent");
        return -1;
    }

    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    engine->display = display;
    engine->context = context;
    engine->surface = surface;
    engine->width = w;
    engine->height = h;
    engine->state.angle = 0;

    // Initialize GL state.
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
    glEnable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_DEPTH_TEST);

    return 0;
}

/**
 * Just the current frame in the display.
 */
static void engine_draw_frame(struct engine* engine) {
    if (engine->display == NULL) {
        // No display.
        return;
    }

    // Just fill the screen with a color.
    glClearColor(((float)engine->state.x)/engine->width, engine->state.angle,
            ((float)engine->state.y)/engine->height, 1);
    glClear(GL_COLOR_BUFFER_BIT);

    eglSwapBuffers(engine->display, engine->surface);
}

/**
 * Tear down the EGL context currently associated with the display.
 */
static void engine_term_display(struct engine* engine) {
    if (engine->display != EGL_NO_DISPLAY) {
        eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        if (engine->context != EGL_NO_CONTEXT) {
            eglDestroyContext(engine->display, engine->context);
        }
        if (engine->surface != EGL_NO_SURFACE) {
            eglDestroySurface(engine->display, engine->surface);
        }
        eglTerminate(engine->display);
    }
    engine->animating = 0;
    engine->display = EGL_NO_DISPLAY;
    engine->context = EGL_NO_CONTEXT;
    engine->surface = EGL_NO_SURFACE;
}

/**
 * Process the next input event.
 */
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
    struct engine* engine = (struct engine*)app->userData;
    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
        engine->animating = 1;
        engine->state.x = AMotionEvent_getX(event, 0);
        engine->state.y = AMotionEvent_getY(event, 0);
        return 1;
    }
    return 0;
}

/**
 * Process the next main command.
 */
static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
    struct engine* engine = (struct engine*)app->userData;
    switch (cmd) {
        case APP_CMD_SAVE_STATE:
            // The system has asked us to save our current state.  Do so.
            engine->app->savedState = malloc(sizeof(struct saved_state));
            *((struct saved_state*)engine->app->savedState) = engine->state;
            engine->app->savedStateSize = sizeof(struct saved_state);
            break;
        case APP_CMD_INIT_WINDOW:
            // The window is being shown, get it ready.
            if (engine->app->window != NULL) {
                engine_init_display(engine);
                engine_draw_frame(engine);
            }
            break;
        case APP_CMD_TERM_WINDOW:
            // The window is being hidden or closed, clean it up.
            engine_term_display(engine);
            break;
        case APP_CMD_GAINED_FOCUS:
            // When our app gains focus, we start monitoring the accelerometer.
            if (engine->accelerometerSensor != NULL) {
                ASensorEventQueue_enableSensor(engine->sensorEventQueue,
                        engine->accelerometerSensor);
                // We'd like to get 60 events per second (in us).
                ASensorEventQueue_setEventRate(engine->sensorEventQueue,
                        engine->accelerometerSensor, (1000L/60)*1000);
            }
            break;
        case APP_CMD_LOST_FOCUS:
            // When our app loses focus, we stop monitoring the accelerometer.
            // This is to avoid consuming battery while not being used.
            if (engine->accelerometerSensor != NULL) {
                ASensorEventQueue_disableSensor(engine->sensorEventQueue,
                        engine->accelerometerSensor);
            }
            // Also stop animating.
            engine->animating = 0;
            engine_draw_frame(engine);
            break;
    }
}

/**
 * This is the main entry point of a native application that is using
 * android_native_app_glue.  It runs in its own thread, with its own
 * event loop for receiving input events and doing other things.
 */
void android_main(struct android_app* state) {
    struct engine engine;

    // Make sure glue isn't stripped.
    app_dummy();

    memset(&engine, 0, sizeof(engine));
    state->userData = &engine;
    state->onAppCmd = engine_handle_cmd;
    state->onInputEvent = engine_handle_input;
    engine.app = state;

    // Prepare to monitor accelerometer
    engine.sensorManager = ASensorManager_getInstance();
    engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
            ASENSOR_TYPE_ACCELEROMETER);
    engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
            state->looper, LOOPER_ID_USER, NULL, NULL);

    if (state->savedState != NULL) {
        // We are starting with a previous saved state; restore from it.
        engine.state = *(struct saved_state*)state->savedState;
    }

    // loop waiting for stuff to do.

    while (1) {
        // Read all pending events.
        int ident;
        int events;
        struct android_poll_source* source;

        // If not animating, we will block forever waiting for events.
        // If animating, we loop until all events are read, then continue
        // to draw the next frame of animation.
        while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
                (void**)&source)) >= 0) {

            // Process this event.
            if (source != NULL) {
                source->process(state, source);
            }

            // If a sensor has data, process it now.
            if (ident == LOOPER_ID_USER) {
                if (engine.accelerometerSensor != NULL) {
                    ASensorEvent event;
                    while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
                            &event, 1) > 0) {
                        LOGI("accelerometer: x=%f y=%f z=%f",
                                event.acceleration.x, event.acceleration.y,
                                event.acceleration.z);
                    }
                }
            }

            // Check if we are exiting.
            if (state->destroyRequested != 0) {
                engine_term_display(&engine);
                return;
            }
        }

        if (engine.animating) {
            // Done with events; draw next animation frame.
            engine.state.angle += .01f;
            if (engine.state.angle > 1) {
                engine.state.angle = 0;
            }

            // Drawing is throttled to the screen update rate, so there
            // is no need to do timing here.
            engine_draw_frame(&engine);
        }
    }
}
« Last Edit: July 31, 2012, 10:32:54 PM by support »

kryton9

  • Guest
Re: C for Android
« Reply #3 on: August 02, 2012, 12:49:28 PM »
John remarkable progress you are making in the Android world. Thanks for sharing your discoveries and experiences. It is very exciting to see the things you are coming up with!

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #4 on: August 02, 2012, 02:38:14 PM »
Thanks!

Android Linux is like a prefab minimal security prison with unspoken rules and direction. Other then that, having a blast.

Home away from home ...



Yes, this is what you think your seeing. Android with a Ubuntu buddy. (rooted system required)
« Last Edit: August 02, 2012, 05:40:45 PM by support »

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #5 on: August 03, 2012, 12:14:02 AM »
Too bad that Ubuntu ARM isn't binary compatible with Android. (at least the 9.04 version)

Quote
Ubuntu 9.04 "Jaunty Jackalope" ARMv5 "small" image

I think I need ARMv7 to share binaries.

Un-installing this is easy. Just delete the image file.

kryton9

  • Guest
Re: C for Android
« Reply #6 on: August 03, 2012, 04:07:57 PM »
You might want to share your work here also on these forums. They get lots of traffic and I am sure many would find all of this very useful John.
http://forum.xda-developers.com/index.php

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #7 on: August 04, 2012, 01:40:09 AM »
What would be cool is the ability to create Android Linux native C/C++ applications using the Android Java framework as a GUI API. Having Ubuntu ARM running side by side with Android Linux and not having to cross compile makes developing on a tablet doable. (Bluetooth keyboard a must!)

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #8 on: August 04, 2012, 05:23:29 PM »
Quote
You might want to share your work here also on these forums

Quote
Dear ScriptBasic,

Thanks for registering at xda-developers! We are glad you have chosen to be a part of our community and we hope you enjoy your stay.

All the best,
xda-developers

Thanks Kent!

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #9 on: August 05, 2012, 12:50:30 PM »
If you want to play with Ubuntu chroot images on your Android Tab, Linux Autoloader is a must have app.



Google play


Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #10 on: August 05, 2012, 01:24:50 PM »
I was able to get the LXDE Ubuntu GUI shell going on my Galaxy Tab 2 10.1 tablet.



kryton9

  • Guest
Re: C for Android
« Reply #11 on: August 05, 2012, 02:04:29 PM »
You are blowing me away with all that you have done!  Great screenshot.

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #12 on: August 05, 2012, 08:06:59 PM »
Unfortunately the LXDE shell was buggy and too frustrating to try and fix. I'm now running the BackTrack5 image. (Ubuntu ARM 10.04 LTS) The BackTrack5 project maintains the repository not Ubuntu for the distribution. It looks like a great platform for my Android development.









BackTrack 5 ARM installed package list

Note The FireFox example shows the true screen geometry as intended. (thanks Linux Autoloader) From what I know at the moment, BackTrack ARM has only known to work on the Motorola Zoom tablet. The SGT2_10.1 may be new territory.

« Last Edit: August 06, 2012, 03:29:36 PM by support »

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #13 on: August 06, 2012, 08:34:15 PM »
I have been testing Ubuntu services and Apache running local and the ssh server seem to work fine.



This is an example of connecting to the Ubuntu chroot image via ssh from my laptop. (wireless)

Code: [Select]
jrs@laptop:~/android/ubuntu$ ssh -i id_rsa.pub root@10.0.0.5
root@10.0.0.5's password:
Linux localhost 3.0.8-396106-user #1 SMP PREEMPT Sat Apr 14 07:54:34 KST 2012 armv7l GNU/Linux
Ubuntu 10.04 LTS

Welcome to Ubuntu!
 * Documentation:  https://help.ubuntu.com/

0 packages can be updated.
0 updates are security updates.

Last login: Mon Aug  6 19:17:11 2012 from 10.0.0.3
root@localhost:~# dhclient
Internet Systems Consortium DHCP Client V3.1.3
Copyright 2004-2009 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/ifb1/32:26:de:55:41:e2
Sending on   LPF/ifb1/32:26:de:55:41:e2
Listening on LPF/ifb0/be:9f:99:53:94:45
Sending on   LPF/ifb0/be:9f:99:53:94:45
Listening on LPF/wlan0/28:98:7b:dc:6a:b9
Sending on   LPF/wlan0/28:98:7b:dc:6a:b9
Sending on   Socket/fallback
DHCPDISCOVER on ifb0 to 255.255.255.255 port 67 interval 8
DHCPDISCOVER on ifb1 to 255.255.255.255 port 67 interval 7
DHCPREQUEST of 10.0.0.5 on wlan0 to 255.255.255.255 port 67
DHCPACK of 10.0.0.5 from 10.0.0.1
bound to 10.0.0.5 -- renewal in 47228 seconds.
root@localhost:~#
« Last Edit: August 06, 2012, 09:05:43 PM by support »

Support

  • Administrator
  • *****
  • Posts: 19
    • View Profile
Re: C for Android
« Reply #14 on: August 07, 2012, 09:45:32 PM »
I settled on a VNC client for Android. Jump Desktop (RDP & VNC) costs more than the rest but well worth the $9.99 price tag. It works really well with my Ubuntu chroot image.



On Thursday my Samsung USB & SD Connection Kit should arrive so I can use my mouse with the tablet. (Android/Ubuntu)