Небольшое приложение для облачных вычислений в Android

Доступ к файловой системе телефона под управлением Android через браузер

Технология облачных вычислений (cloud computing) требует как минимум двух компонентов: клиентской программы, которая выполняется на мобильном устройстве, и серверного программного обеспечения, работающего на сетевом сервере. В этой статье рассказывается о создании Android-сервиса, имитирующего сетевой сервер. Он откроет новые, неожиданные возможности вашего устройства. Поместив небольшое "облачко" в ваш карманный компьютер, вы превратите его в полезный локальный Web-сервер.

Билл Циммерли, специалист в области инженерии знаний, Рязанский государственный радиотехнический университет

Билл Циммерли (Bill Zimmerly) является специалистом в области инженерии знаний, а также программистом языков низкого уровня. Он имеет большой опыт работы с различными версиями программного обеспечения UNIX® и Microsoft® Windows®. Билл с огромным энтузиазмом и удовольствием занимается созданием новых технологий и рассказывает о них в своих статьях. Живет он в деревушке Хиллсборо, Миссури, где может наслаждаться чистым воздухом и прекрасной природой. Кроме того, неподалеку находятся несколько винных заводов. Связаться с ним можно по адресу электронной почты: bill@zimmerly.com.



18.02.2010

Android представляет собой специализированный дистрибутив операционной системы Linux®, созданный для реализации функциональности наиболее интеллектуальных смартфонов. Для разработчика любой объект в Linux, будь то устройство, электронная таблица или любимая песня, представляет собой файл. Таким образом, существует ряд общих методов для доступа, чтения, манипулирования и сохранения информационного содержимого всех этих объектов. Подобное единообразие является одним из фундаментальных принципов философии UNIX®: "все объекты представляют собой файлы".

Часто встречающиеся аббревиатуры

  • MIME: многоцелевые расширения почты интернета
  • HTML: язык разметки гипертекста
  • SDK: комплект разработчика программного обеспечения
  • WWW: Всемирная Паутина

Для удобства работы файлы группируются в иерархические структуры, называемые файловыми системами. Мобильные телефоны под управлением Android, как правило, имеют две файловые системы: одна из них располагается в постоянной памяти телефона, а вторая — на сменной SD-карте. Обе системы монтируются в виде подкаталогов корневого каталога (/). Было бы удобно иметь возможность работать с этими файловыми системами непосредственно через браузер. В этой статье рассматривается небольшое приложение, написанное на С, которое играет роль Web-сервера, предоставляя доступ к файловыми системам телефона под управлением Android. Таким образом, вы можете обращаться к файлам с вашего рабочего компьютера или при помощи встроенного в телефон браузера. При этом Web-страницы содержат гиперссылки для перемещения по иерархии каталогов и просмотра файлов.

Настройка рабочего окружения

Во-первых, убедитесь, что ваш Android-телефон позволяет выполнять такие действия, как, например, запуск терминала или выполнение команды su для получения доступа к административным функциями. В Интернете несложно найти информацию о том, как узнать, можно ли получить административные привилегии на вашем телефоне и как это сделать. Этот процесс иногда называют "побег из тюрьмы" (jail-breaking). Для получения более подробной информации обратитесь к разделу Ресурсы).

Сообщество разработчиков Android в основном использует два SDK. Наиболее распространенным из них является высокоуровневый SDK Android, позволяющий разрабатывать приложения на Java™ с использованием Eclipse для написания, тестирования и отладки кода. Другой, менее известный SDK, представляет собой набор исходных кодов ядра Android, хранящихся в репозитории git (ссылка на этот репозиторий приведена в разделе Ресурсы).

Поскольку в этой статье рассматривается низкоуровневый Web-сервер, который, как правило, размещается в каталоге system/bin телефона, необходимо загрузить и установить весь исходный код ядра Android, а также утилиты GNU для его сборки. Инструкции по загрузке всей платформы Android при помощи скрипта под названием repo, находятся на домашней странице проекта Android Kernel Source (см. Ресурсы).

Наше небольшое облачное приложение будет компилироваться для ARM-платформы, поэтому убедитесь, что на вашем компьютере установлены все необходимые для этого средства. Для их установки можно воспользоваться командой apt-get, как показано в листинге 1.

Листинг 1. Установка утилит для кросс-компиляции
    $ sudo apt-get install git-core gnupg \
    sun-java5-jdk flex bison gperf libsdl-dev \
    libesd0-dev libwxgtk2.6-dev build-essential \
    zip curl libncurses5-dev zlib1g-dev

Структура каталогов в процессе разработки

Исходный код ядра Android следует установить в каталог mydroid. Перейдите в ваш домашний каталог и выполните команду mkdir mydroid. Затем выполните команды  cd mydroid и repo sync.

Команда repo sync должна загрузить весь исходный код Android в каталог mydroid и создать в нем несколько важных дочерних каталогов, в том числе следующие:

  • Каталог mydroid/external. В нем вам необходимо создать директорию cloud, в которой будет размещаться исходный код нашего проекта (cloud.c).
  • Каталог out/target/product/generic/system/bin. После того, как утилита make закончит сборку системы Android, в нем вы найдете скомпилированную программу cloud.

Проект cloud-приложения для Android

Сразу после запуска приложение проверяет, были ли переданы параметры командной строки. В качестве необязательных параметров она принимает номер порта для прослушивания и домашний каталог. В случае отсутствия параметров сервер будет использовать стандартный порт 80, а в качестве домашнего каталога — ту директорию, из которой он был запущен.

После проверки параметров приложение инициализирует сокет TCP/IP для прослушивания запросов через нужный порт, а затем переключается в режим демона, ожидая запросы от браузера и обрабатывая их по мере поступления. Когда браузер запрашивает страницу по умолчанию нашего облачного сервера, сервер возвращает страницу с содержимым упомянутого выше домашнего каталога. Имена файлов известных типов и имена каталогов выводятся в виде ссылок. В WWW под известными типами файлов понимаются те, для которых указан тип MIME. К таковым, например, относятся мелодии звонков, хранящиеся в телефонах под управлением Android в виде файлов с расширением .ogg. Они имеют MIME-тип audio/ogg, который говорит браузеру о том, что данные файлы должны проигрываться через динамики (разумеется, браузер должен быть правильно настроен, чтобы поддерживать эту возможность).

В верхней части страницы присутствует ссылка "Parent Directory" (родительский каталог). С ее помощью можно перемещаться вверх по дереву каталогов файловой системы вплоть до корневой директории. При этом имена других каталогов также выводятся в виде ссылок; при нажатии на них вы спуститесь в соответствующую директорию и увидите находящиеся в ней файлы.

Таким образом, приложение cloud позволяет удобным образом просматривать файловую систему мобильных телефонов. При этом ее исходный код (см. Загрузка) может служить в качестве функционального шаблона, который вы можете изменять по своему усмотрению (в конце статьи приведено несколько советов по модификации исходного кода приложения). Кроме того, вы можете скомпилировать и запустить это приложение на своем рабочем компьютере и просматривать содержимое его файловой системы (инструкции можно найти по ссылке в разделе Ресурсы).


Исходный код на С

Исходный код любой программы обязан как минимум содержать ее название и имя ее автора. Эти атрибуты, а также заголовочные файлы и некоторые полезные константы показаны в листинге 2.

Листинг 2. Информация об авторе, заголовочные файлы и константы
    // Приложение для облачных вычислений на платформе Android,
    // написанное Биллом Циммерли на основе сервера NWEB
    // Найджела Гриффитса

    #include <dirent.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    #define TRUE      -1
    #define FALSE     0
    #define SBUF      1048576
    #define LBUF      4096
    #define LAPN      64
    #define ERROR     1
    #define LOG       2
    #define LOGGING   FALSE

В листинге 3 показаны глобальные переменные, доступные всем функциям приложения. Большинство из них представляют собой указатели на буферы памяти, которая выделяется при обработке запросов от браузера. После возвращения страницы браузеру память освобождается и передается обратно операционной системе телефона. На вычислительных устройствах, имеющих ограниченные ресурсы, своевременное освобождение памяти имеет приоритет перед многими другими соображениями.

Листинг 3. Глобальные буферы памяти
    char* about="</pre>Cloud is a simple application that enables "
                "web-based browsing of the Android file system "
                "and is intended for use by people who like to "
                "explore the lowest levels of their device. It "
                "runs on a rooted Android phone and is only for "
                "browsing the file system. See the IBM "
                "developerWorks article for a full description "
                "of this application.<pre>";

    char* mainbuf;
    char* theDir;
    char* thePort[8];
    char* theList;
    char* fstr;

    char logDir[LBUF];

    int ret;

В программе используется простая таблица, устанавливающая соответствие между расширениями файлов и типами MIME, которые должны быть известны браузеру для корректного показа содержимого. Структура данных, показанная в листинге 4, используется функцией  mimeokay  с единственной целью: для того, чтобы глобальная переменная fstr указывала на тип MIME, соответствующий расширению файла, хранящемуся в переменной fext. Получив эту информацию, облачный сервер может отобразить имя файла в виде ссылки (либо без ссылки, если тип неизвестен). Кроме того, это позволяет передать MIME-тип браузере одновременно с передачей содержимого файла.

Листинг 4. Определение MIME-типов
    struct
    {
      char *ext;
      char *mimetype;
    }

    mimes [] = 
    {
      {".htm",  "text/html"  },  
      {".html", "text/html"  },
      {".xml",  "text/xml"   },
      {".gif",  "image/gif"  },  
      {".jpg",  "image/jpeg" }, 
      {".jpeg", "image/jpeg" },
      {".png",  "image/png"  },  
      {".log",  "text/plain" },
      {".conf", "text/plain" },
      {".rc",   "text/plain" },
      {".sh",   "text/plain" },
      {".prop", "text/plain" },
      {".txt",  "text/plain" },
      {".TXT",  "text/plain" },
      {".cpp",  "text/plain" },  
      {".c",    "text/plain" },  
      {".h",    "text/plain" },
      {".ogg",  "audio/ogg" },
      {0,0} 
    };

    void mimeokay(char* fext)
    {
      int buflen;
      int len;
      long i;

      buflen=strlen(fext);
      fstr = (char*) 0;
  
      for(i=0; mimes[i].ext != 0; i++)
      {
        len = strlen(mimes[i].ext);
    
        if(!strncmp(&fext[buflen-len], mimes[i].ext, len))
        {
          fstr=mimes[i].mimetype;
          break;
        }
      }
    }

В листинге 5 приведен необязательный фрагмент кода, который используется на этапах разработки и тестирования и отвечает за журналирование действий приложения в файле cloud.log. Наше приложение выполняется на относительно медленном устройстве, поэтому эту функциональность лучше отключать, за исключением тех случаев, когда вам действительно необходимо знать, как ведет себя код при его модификации. Если журналирование необходимо, то константа LOGGING в листинге 1 должна иметь значение TRUE. Если же приложение выполняется на мобильном телефоне, следует установить ее в значение FALSE, чтобы избежать серьезных потерь производительности.

Листинг 5. Журналирование
    void aclog(int type, char *s1, char *s2, int num)
    {
      int fd ;
      char aclogbuffer[LBUF];
      char logFile[LBUF];
    
      if(!LOGGING)
        return;
    
      switch(type)
      {
        case ERROR: 
          sprintf(aclogbuffer, "ERROR: %s:%s Error Number=%d, PID=%d", 
                  s1, s2,
                  errno, getpid());
          break;
        case LOG:
          sprintf(aclogbuffer, "INFO: %s:%s:%d", s1, s2, num);
          break;
      }	
    
      strcpy(logFile, logDir);
      strcat(logFile, "/cloud.log");
      
      if((fd = open(logFile, O_CREAT | O_WRONLY | O_APPEND,
                    0644)) >= 0)
      {
        ret=write(fd, aclogbuffer, strlen(aclogbuffer)); 
        ret=write(fd, "\n", 1);      
        close(fd);
      }
    
      if(type == ERROR)
        exit(3);
    }

В листинге 6 показано несколько функций, служащих для создания HTML-страниц, возвращаемых приложением. Следует учитывать, что все страницы качественно сделанного Web-сайта должны следовать общему стилю. В данном случае такой стиль определяется в функции buildbuf.

Листинг 6. Вывод результатов в формате HTML
    void apname(void)
    {
      strcat(mainbuf, "Android Cloud Application");
    }
    
    void buildbuf(char* data)
    {
      mainbuf[0]=0;
      strcat(mainbuf, "<html>\n<head>\n<title>");
      apname();
      strcat(mainbuf, "</title>\n</head>\n");  
      strcat(mainbuf, "<body>\n<h3>");
      apname();
      strcat(mainbuf, "</h3>\n");
      strcat(mainbuf, "<a href=\"/About_\">About</a><br>\n");
      strcat(mainbuf, "<a href=\"/Home_\">Home</a><br>\n");
      strcat(mainbuf, "<hr>\n");
      strcat(mainbuf, "Dir: ");
      strcat(mainbuf, theDir);
      strcat(mainbuf, "<br>\n<hr>\n<pre>\n");
      strcat(mainbuf, data);
      strcat(mainbuf, "\n</pre>\n");
      strcat(mainbuf, "</body>\n</html>\n");
    }
    
    void htmlout(int fd, char* data)
    {
      fstr=mimes[0].mimetype;
      sprintf(mainbuf, "HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr);
      ret=write(fd, mainbuf, strlen(mainbuf));
      buildbuf(data);
      ret=write(fd, mainbuf, strlen(mainbuf));
    }
    
    void error404(int fd)
    {
      fstr=mimes[0].mimetype;
      sprintf(mainbuf, "HTTP/1.0 404 OK\r\nContent-Type: %s\r\n\r\n", fstr);
      ret=write(fd, mainbuf, strlen(mainbuf));
      buildbuf("404 Error - File not found!");
      ret=write(fd, mainbuf, strlen(mainbuf));
    }

В листинге 7 показано, как cloud-сервер возвращает содержимое файла известного MIME-типа. Обратите внимание, что браузер ожидает, что MIME-тип будет передан сервером в строковом поле Content-Type:. Функция, приведенная в листинге 7, вызывается после нажатия на ссылку с именем файла и возвращает его содержимое. Если чересчур изобретательный или злонамеренный пользователь вручную введет неправильное имя файла в адресной строке браузера, вызовется функция error404, которая вернет соответствующее сообщение.

Листинг 7. Возвращение содержимого файла
    void retfile(int fd, int hit)
    {
      int file_fd;
      long ret;
    
      mimeokay(mainbuf);
    
      if(fstr == 0)
      {
        error404(fd);
        return;
      }
    
      if((file_fd = open(&mainbuf[4], O_RDONLY)) == -1)
      {
        error404(fd);
      }
      else
      {  
        aclog(LOG, "SEND", &mainbuf[4], hit);
    
        sprintf(mainbuf, "HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr);
        ret=write(fd, mainbuf, strlen(mainbuf));
    
        while((ret=read(file_fd, mainbuf, SBUF)) > 0 )
        {
          ret=write(fd, mainbuf, ret);
        }
      }
    }

Процесс формирования основного списка файлов с гиперссылками показан в листинге 8. Как видите, создание ссылок выполняется многократно, поэтому соответствующий фрагмент кода разумно вынести в отдельную функцию  hyper. Благодаря переменной isDir  префикс /CD_ прибавляется к полному пути к файлу, чтобы сервер знал, что необходимо вывести содержимое каталога. Далее следует функция fileList, которая занимает центральное место в приложении.

Листинг 8. Функции для вывода содержимого каталогов
    void hyper(int isDir, char* name)
    {
      strcat(theList, "<a href=\"");
    
      if(isDir)
        strcat(theList, "/CD_");
    
      strcat(theList, (char*) theDir);
    
      if(strcmp(theDir, "/"))
        strcat(theList, "/");
    
      strcat(theList, name);
      strcat(theList, "\">");
      strcat(theList, name);
      strcat(theList, "</a>");
      strcat(theList, "\n");
    }

    char* fileList(void)
    {
      struct dirent **namelist;
      int n;
      long i;
      long j;
    
      theList[0]=0;
    
      n=scandir(".", &namelist, 0, (void*) alphasort);
    
      if (n < 0)
        perror("scandir");
      else
      {
        for(i=0; i<n; i++)
        {
          if(namelist[i]->d_type == DT_DIR)
          {
            if(!strcmp(namelist[i]->d_name, "."))
            {
              // strcat(theList, namelist[i]->d_name);
            }
            else if(!strcmp(namelist[i]->d_name, ".."))
            {
              if(strcmp(theDir, "/"))
              {
                strcat(theList, "<a href=\"");
                strcat(theList, "/CD_");
                strcat(theList, (char*) theDir);
    
                j=strlen(theList);
    
                while(j--)
                {
                  if(theList[j] == '/')
                  {
                    theList[j]=0;
                    j=1;
                  }
                }
                
                if(!strcmp(&theList[strlen(theList)-4], "/CD_"))
                {
                  strcat(theList, "/");
                }
    
                strcat(theList, "\">Parent Directory</a>");          
                strcat(theList, "\n");
              }
            }
            else
              hyper(TRUE, namelist[i]->d_name);
          }
          else
          {
            mimeokay(namelist[i]->d_name);
        
            if(fstr == 0)
            {
              strcat(theList, namelist[i]->d_name);
              strcat(theList, "\n");
            }
            else
              hyper(FALSE, namelist[i]->d_name);
          }
    
          free(namelist[i]);
        }  
    
        free(namelist);
      }
      
      return theList;
    }

В листинге 9 показана функция child, которая вызывается при обработке каждого запроса от браузера. У нее всего одна простая задача: выделить память под буферы, которые необходимы для обработки запроса, затем обработать их содержимое, после чего освободить память, чтобы не расходовать ее без необходимости. Память в мобильных телефонах представляет собой дефицитный и дорогой ресурс, и ее необходимо освобождать немедленно после того, как программа закончила обработку запроса.

Листинг 9. Функция child приложения-демона
    void child(int fd, int hit)
    {
      long i;
      long ret;
      char* cret;
    
      mainbuf=malloc(SBUF+1);
      theList=malloc(SBUF+1);
      theDir=malloc(LBUF+1);
      cret=getcwd(theDir, LBUF);
      
      ret=read(fd, mainbuf, SBUF);
    
      if(ret == 0 || ret == -1)
      {
        error404(fd);
      }
      else
      {
        if(ret > 0 && ret < SBUF)
          mainbuf[ret]=0;
        else
          mainbuf[0]=0;
    
        for(i=0; i<ret; i++)
          if(mainbuf[i] == '\r' || mainbuf[i] == '\n')
            mainbuf[i]='*';
    
        aclog(LOG, "request", mainbuf, hit);
    
        for(i=4; i < SBUF; i++)
        {
          if(mainbuf[i] == ' ')
          {
            mainbuf[i]=0;
            break;
          }
        }
    
        if(!strncmp(&mainbuf[0], "GET /\0", 6) ||
           !strncmp(&mainbuf[0], "get /\0", 6))
        {
          htmlout(fd, fileList());
        }
        else
        {
          if(!strncmp(&mainbuf[5], "About_", 6))
          {
            htmlout(fd, about);
          }
          else if(!strncmp(&mainbuf[5], "Home_", 5))
          {
            htmlout(fd, fileList());
          }    
          else if(!strncmp(&mainbuf[5], "CD_", 3))
          {
            if(chdir(&mainbuf[8]) == -1)
            {
              error404(fd);
            }
            else
            {
              if(strcmp(theDir, &mainbuf[8]))
                strcpy(theDir, &mainbuf[8]);
                
              htmlout(fd, fileList());
            }
          }
          else
          {
            retfile(fd, hit);
          }
        }
      }
    
      free(theDir);
      free(theList);  
      free(mainbuf);  
      sleep(1);
      exit(1);
    }

Функция main, играющая роль точки входа в приложение, показана в листинге 10. Она инициализирует сокет TCP/IP, через который будет ожидаться поступление запросов от браузера. Затем функция также инициализирует некоторые глобальные переменные, в частности, theDir, сохраняя в ней каталог запуска. Наконец, эта функция переключает приложение в режим демона (т. е. программы, постоянно присутствующей в памяти), в котором оно может обрабатывать запросы в фоновом режиме, не прерывая выполнение других процессов.

Листинг 10. Точка входа в приложение
    int main(int argc, char **argv)
    {
      char* str;
      char* cret;
    
      static struct sockaddr_in cli_addr;
      static struct sockaddr_in serv_addr;
    
      socklen_t length;
    
      int i;
      int port;
      int pid;
      int listenfd;
      int socketfd;
      int hit;
    
      cret=getcwd(logDir, LBUF);
    
      if(argc < 2)
      {
        strcpy((char*) thePort, "80");
        port=atoi((char*) thePort);
      }
      else
      {
        if(!strcmp(argv[1], "-?"))
        {
          printf("Usage: cloud [Port Directory]\n");
          exit(0);
        }
        strcpy((char*) thePort, argv[1]);
        port=atoi((char*) thePort);
    
        if(port < 0 || port > 60000)
          aclog(ERROR, "Invalid port number (try 1 --> 60000)", argv[1], 0);
    
        if(chdir(argv[2]) == -1)
        {
          printf("ERROR: Invalid directory %s\n", argv[2]);
          exit(4);
        }
      }
    
      if(fork() != 0)
        return 0;
    
      signal(SIGCHLD, SIG_IGN);
      signal(SIGHUP, SIG_IGN);
    	
      for(i=0; i<32; i++)
        close(i);
    	
      setpgrp();
    
      aclog(LOG, "Cloud Port/PID=", (char*) thePort, getpid());
        
      if((listenfd=socket(AF_INET, SOCK_STREAM, 0)) < 0)
        aclog(ERROR, "syscall", "socket", 0);
    	
      serv_addr.sin_family      = AF_INET;
      serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
      serv_addr.sin_port        = htons(port);
    
      if(bind(listenfd, (struct sockaddr*) &serv_addr,
              sizeof(serv_addr)) < 0)
        aclog(ERROR, "syscall", "bind", 0);
    
      if(listen(listenfd, 64) <0)
        aclog(ERROR, "syscall", "listen", 0);
    
      for(hit=1; ;hit++)
      {
        length=sizeof(cli_addr);
        
        if((socketfd=accept(listenfd,
                            (struct sockaddr*) &cli_addr,
                            (socklen_t*) &length)) < 0)
          aclog(ERROR, "syscall", "accept", 0);
    
        if((pid=fork()) < 0)
        {
          aclog(ERROR, "syscall", "fork", 0);
        }
        else
        {
          if(pid == 0)
          {
            close(listenfd);
            child(socketfd, hit);
          }
          else
          {
            close(socketfd);
          }
        }
      }
    }

Компиляция, развертывание и тестирование приложения

Нам осталось создать еще один файл, чтобы собрать наше облачное приложение при помощи файла сборки, поставляемого вместе с исходными кодами ядра Android. Создайте файл с именем Android.mk и скопируйте в него содержимое листинга 11 (этот файл также можно найти в архиве, ссылка на который приведена в разделе Загрузка).

Листинг 11. Файл Android.mk
    ifneq ($(TARGET_SIMULATOR),true)
    
    LOCAL_PATH:= $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES:= cloud.c
    LOCAL_MODULE := cloud
    LOCAL_STATIC_LIBRARIES := libcutils libc
    include $(BUILD_EXECUTABLE)
    
    endif  # TARGET_SIMULATOR != true

Далее перейдите в подкаталог external в каталоге, в котором находятся исходные коды ядра Android, и создайте в нем дочернюю директорию cloud. Теперь можно собрать новую версию ядра Android, включающую приложение cloud.

Переместитесь в корневой каталог с исходными кодами ядра Android и запустите команду make. Ее выполнение может занять определенное время, так что вы можете позволить себе расслабиться и выпить чашечку кофе.

Если все прошло хорошо и система была собрана удачно, то исполняемый файл сервера cloud должен находиться в каталоге out/target/product/generic/system/bin. При этом вам необязательно переустанавливать всю систему на вашем телефоне. Достаточно скопировать полученный файл на SD-карту памяти. В листинге 12 приведен пример того, как это можно сделать с вашего рабочего компьютера (в этом примере считается, что исходные тексты ядра Android находятся в каталоге mydroid).

Листинг 12. Сборка ядра Android и приложения cloud
    $ cd mydroid/external
    $ mkdir cloud
    $ cd cloud
    $ cp ~/src/tinycloud/cloud.c .
    $ cp ~/src/tinycloud/Android.mk .
    $ cd ../..
    $ make
    
    --- В течение долгого времени будут выводиться системные сообщения утилиты "make". ---
    
    $ cd out/target/product/generic/system/bin
    $ cp cloud /media/ANDROIDSDCARD/.

Учтите, что в этом примере подразумевается, что ваш телефон подключен к компьютеру, а его файловая система подмонтирована в точке /media/ANDROIDSDCARD. Кроме того, на вашем телефоне SD-карта может иметь другое имя. Его можно найти внутри директории /media (если вы используете ОС Ubuntu семейства Linux).

Доступ к командному интерпретатору (shell) телефона Android можно получить при помощи любой из бесплатных терминальных утилит, распространяемых через сервис Android Market. Приложение cloud обычно (но необязательно) находится в каталоге system/bin. В целях тестирования имеет смысл поэкспериментировать с его запуском из разных каталогов, поэтому создайте директорию cloud. в каталоге /data и скопируйте в нее исполняемый файл из /sdcard. Далее выполните команду chmod, чтобы сделать программу исполняемой, а затем запустите ее командой cloud. Примеры выполнения этих действий приведены в листинге 13.

Листинг 13. Тестирование cloud- приложения на телефоне под управлением Android
    $ su
    # cd data
    # mkdir cloud
    # cd cloud
    # cp /sdcard/cloud .
    # chmod 777 cloud
    # ./cloud
    # ps
    
    --- Список демонов, который должен включать "./cloud". ---

Нажмите кнопку Home для запуска браузера и обратитесь по адресу http://localhost. Вы должны увидеть результаты работы нашего облачного сервера в браузере Android. Щелкая по ссылками, вы можете перемещаться по файловой системе вашего телефона.

Теперь, если ваш телефон подключен к сети через Wi-Fi, вы сможете просматривать его файловую систему со своего компьютера. Для этого необходимо узнать IP-адрес телефона в Wi-Fi-сети, что можно сделать несколькими способами, например, проанализировав логи маршрутизатора Wi-Fi. Кроме того, можно вновь обратиться к программе Terminal и выполнить команду netstat -r. Результат должен быть аналогичен показанному в листинге 14.

Листинг 14. Использование команды netstat для получения IP-адреса телефона
    # netstat -r
    Proto Recv-Q Send-Q  Local Address    Foreign Address    ... 
    .
    .
    .
    tcp        0      0  192.168.0.3:80   192.168.0.5:58744  ...
    .
    .
    .

Наберите http://192.168.0.3/ (IP-адрес вашего телефона) в адресной строке браузера, и через мгновение вы получите доступ к файловой системе телефона, предоставленный нашим маленьким облачным сервером.

Этот сервер можно использовать для просмотра параллельно редактируемой Web-страницы. Для этого просто нажмите и удерживайте кнопку Home для запуска браузера или редактора. Запустив браузер, обновите страницу, чтобы увидеть сделанные изменения. Чередуя операции редактирования и просмотра, вы можете заниматься Web-дизайном, сидя, например, в приемной у стоматолога.


Варианты дальнейшего расширения проекта

Созданное нами приложение можно расширять в различных направлениях. Ниже приведены некоторые из вариантов.

  • Добавьте в меню отдельный пункт под названием Java, который позволит сразу переместиться в каталог с классами Java и просматривать их содержимое. Файлы классов представляют собой сжатые директории, поэтому их можно отображать в виде ссылок. Аналогичные расширения можно добавить для любых каталогов, содержащих интересующий вас программный код.
  • Добавьте страницу, которая будет выполнять те же функции, что и команда top. Она будет автоматически обновлять каждую минуту и выводить информацию о процессах, которая может быть получена из каталога /proc.
  • Напишите код, позволяющий осуществлять запросы к базам данных SQLite через Web-страницу.
  • Учитывая портативность телефона и то, что SD-карты могут вмещать целые HTML-презентации, вы можете использовать ваш телефон для показа слайдовых демонстраций, используя Web-браузер, встроенный в большинство современных презентационных устройств.

Определившись с вариантом расширения возможностей облачного сервера, вы сможете реализовать его, следуя общим советам, приведенным ниже.

  1. Измените функцию buildbuf, показанную в листинге 6, добавив новый пункт в меню, отвечающий за доступ к новой функции.
  2. Модифицируйте функцию child, приведенную в листинге 9, которая должна обслуживать запросы нового типа. Например, разберитесь, как реализован пункт меню About_ в обеих функциях (buildbuf и child), и вы убедитесь, что в добавлении новых возможностей нет ничего сложного.
  3. Наконец, напишите функцию, реализующую новую функциональность и добавьте ее вызов в функцию child.

Заключение

Всегда полезно знать как можно больше об используемых вами устройствах. При этом написание программ, которые помогут вам узнать эти устройства детальнее, может доставить немалое удовольствие. Создание приложение для облачных вычислений на телефоне под управлением Android – это, во-первых, интересно, а, во-вторых, помогает разобраться в том, что происходит внутри этих замечательных устройств.


Загрузка

ОписаниеИмяРазмер
Исходный код демонстрационного приложенияos-tinycloud-source.zip9 KБ

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Мобильные приложения
ArticleID=468735
ArticleTitle=Небольшое приложение для облачных вычислений в Android
publish-date=02182010