Смотрю на Linux с другого ракурса: разбираюсь с особенностями ОС Android.
Автор статьи никого не призывает к правонарушениям и отказывается нести ответственность за ваши действия. Вся информация предоставлена исключительно в ознакомительных целях. Все действия происходят на виртуальных машинах и внутри локальной сети автора. Спасибо!
Вчера разбирался с Linux. Еще раз. На самом деле мне не сильно интересно вникать в Android, но с другой стороны, таким образом можно взглянуть на тот же Linux, но под другим углом. Возвращаемся к «Современным операционным системам» Э. Таненбаума.
Android является надстройкой ядра Linux. Первым процессом в Android запускается init. Он является корневым для остальных. Так же запускается дополнительный уровень процессов для работы Java под названием Dalvik (низкоуровневый процесс zygote). Процесс zygote первым запускает system_server, который содержит все важные службы операционной системы. Далее процессы запускаются по необходимости. Так же этот процесс позволяет решит ограничение Dalvik в скорости запуска приложений. Если вернуться к 15 дню, то можно лучше понять, как это работает. Если кратко, создание нового процесса происходит при помощи функции fork (который клонирует процесс zygote), а не exec. Таким образом процесс сразу готов к работе.
Это не единственный положительный момент использования процесса zygote. Такое решение позволяет экономить оперативную память, так как использование функции fork позволяет дочерним процессам совместно использовать уже задействованные страницы оперативной памяти.
Все службы system_server публикует в диспетчере служб (является дочерним процессом для init).
Про управление электропитанием в Android
Первое, это управление электропитанием. В Android есть такое расширение: блокировка сна (блокировщик приостановки).
Про механизм устранения дефицита памяти
У Android нет пространства подкачки, поэтому для устранения дефицита памяти, в ядро введен собственный механизм. Этот механизм более агрессивный, нежели в Linux и начинает работать при стремлении оперативной памяти к низким значениям. У процесса есть параметр oom_adj, который определяет вероятность завершения его при нехватке оперативной памяти. В первую очередь будет уничтожаться процесс с наивысшим показателем. Наименьшее значение будут иметь системные процессы и постоянно работающие прикладные процессы. Большее значение будут иметь процессы, взаимодействующие в данный момент с пользователем, видимые им и запущенные фоновые службы. И самое большое значение параметра oom_adj имеют запускающий и неиспользуемый процесс.
Про приложения для Android
Файл приложения имеет расширение apk и не является исполняемым. Это zip-архив, в котором хранятся файлы приложения. Основным файлом является манифест с расширением xml, в котором описываются различные действия при запуске кода.
Вместе с установкой нового приложения в Android, создается новый уникальный идентификатор (UID) и весь код приложения запускается с привилегиями этого пользователя. Таким образом приложение изолируется от основной системы и, вместе с тем, повышается надежность и безопасность.
Процесс system_server имеет UID равный 1000. Даже он не имеет доступа к файлам приложений. Но существует демон installd (рисунок 1), который обеспечивает такую возможность.
Как создается (клонируется) новый процесс, т.е. открывается приложение
Процесс zygote имеет root-права. При fork’е для нового процесса настраиваются права в соответствии с его UID. Далее завершается инициализация Dalvik для работы Java. После чего новый процесс «спрашивает» у диспетчера активностей об его (процесса) предназначении. Диспетчер активностей возвращает информацию о запускаемом приложении. Новый процесс загружает код. Диспетчер активностей отправляет новому процессу ожидаемую операцию. Приложение запустилось.
Вопросы по главе (Глава 10. Изучение конкретных примеров: Unix, Linux и Android)
Попробую ответить на предложенные вопросы из книги. Вероятно, неправильно. Чтобы позже вернуться к ним и проверить как изменилось понимание темы.
Объясните, как тот факт, что UNIX написана на языке C, упрощает ее перенос на новые машины. Высокоуровневый язык СИ достаточно прост для понимания (в отличии от Ассемблера, например), что позволяет большему числу людей участвовать в переносе UNIX на другие системы. Так сказать, количество, переходит в качество.
POSIX-интерфейс определяет набор библиотечных процедур. Объясните, почему в POSIX были стандартизированы библиотечные процедуры, а не интерфейс системных вызовов. Потому что системные вызовы на уровне ассемблера, а процедуры на более высоком уровне. Опять же это связано как-то с простотой понимания для человека/разработчика. Или, если вышесказанное неправильно, это сделано для улучшения совместимости с различным оборудованием.
При переносе на новые архитертуры Linux зависит от компилятора gcc. Назовите одно из преимуществ и один из недостатков такой зависимости. Преимущество – снова более хорошая совместимость. Недостаток – необходима разработка компилятора под другие архитектуры.
Каталог содержит следующие файлы (таблица). Какие файлы будут перечислены командой ls [abc]*e*? Первая буква может быть a, b или c, следующий символ любой, далее обязательно буква е и еще раз любой символ.
Что делает следующий конвейер оболочки Linux? grep nd xyz | wc –l. Вернет количество вхождений подстроки nd в файле xyz.
Напишите конвейер Linux, печатающий восьмую строку файла z в стандартный вывод. У меня такой вариант в голову пришел: head -n 8 info | tail -n 1
Зачем в операционной системе Linux проводится различие между стандартным выводом и стандартным потоком ошибок, если по умолчанию обоим соответствует терминал? Так как не всегда необходимо выводить, например, ошибки в терминал. Можно их перенаправить в файл.
Пользователь вводит с терминала следующие команды: a | b | c& d | e | f& Сколько новых процессов будет работать после того, как оболочка обработает эти команды? Два, c и f. Вроде подвоха нет.
Когда оболочка Linux запускает новый процесс, она помещает копии своих переменных окружения (например, HOME) в стек процесса, чтобы процесс мог определить свой домашний каталог. Если этот процесс в дальнейшем создаст дочерний процесс, получит ли созданный дочерний процесс эти переменные автоматически? Он получит копии этих переменных, изменение которых не повлияет на родительские переменные.
Сколько примерно понадобится времени, чтобы создать в системе UNIX дочерний процесс при следующих условиях: размер текста — 100 Кбайт, размер данных — 20 Кбайт, размер стека — 10 Кбайт, размер структуры задачи — 1 Кбайт, размер структуры пользователя — 5 Кбайт. Обработка эмулированного прерывания ядром занимает 1 мс, а компьютер может копировать 32-разрядное слово каждые 50 нс. Текстовые сегменты используются совместно, а сегменты данных и стека — нет. Спасибо за вопрос. Следующий.
По мере того как многомегабайтные программы становились все более распространенными, время, затрачиваемое на обработку системного вызова fork и копирование сегментов данных и стека вызывающего процесса, росло пропорционально росту размеров программ. Когда fork выполняется в Linux, адресное пространство родителя не копируется (как того требует традиционная семантика системного вызова fork). Как Linux препятствует выполнению дочерним процессом таких действий, которые могли бы полностью изменить семантику системного вызова fork? Копирование при записи. Наверное, это.
Почему отрицательные значения переменной nice может задавать только суперпользователь? Так как отрицательное значение означает наивысший приоритет.
Linux-процессы, не являющиеся процессами реального времени, имеют уровень приоритета от 100 до 139. Каков исходный статический приоритет и как для его изменения используется значение nice? Не знаю как ответить.
Имеет ли смысл забирать у процесса память, когда процесс переходит в состояние зомби? Почему да или почему нет? Процесс уже завершил свою работу и все что он хранит – код завершения для родительского процесса.
С каким аппаратным понятием тесно связан сигнал? Приведите два примера использования сигналов. Первое что пришло в голову – прерывания. Сигнал может посылаться пользователем – остановка процесса. Второй пример: сигнал системы о неисправности.
Как вы думаете, почему разработчики операционной системы Linux сделали для процесса невозможной отправку сигналов другим процессам, не входящим в его группу процессов? Для безопасности. Чтобы другие процессы не могли оказывать лишнее влияние.
Обычно системный вызов реализуется при помощи команды эмулированного (программного) прерывания. Может ли для этого на компьютере Pentium использоваться обычный вызов процедуры? Если да, то при каких условиях и как? Если нет, то почему? Не знаю.
Какие процессы, как правило, обладают более высоким приоритетом, демоны или интерактивные процессы? Если правильно понимаю, интерактивные процессы – это процессы реального времени, следовательно, они имеют более высокий приоритет.
При создании нового процесса ему должен быть присвоен уникальный номер PID. Достаточно ли для этого хранить в ядре счетчик, увеличивающийся на единицу при создании каждого нового процесса, и использовать этот счетчик как новый PID? Аргументируйте свой ответ. Вероятно, этого недостаточно. Если процесс завершается, то PID освобождается и его можно использовать для другого процесса. Так же PID имеет границы. Если каждый новый процесс будет инкрементировать счетчик, то рано или поздно значение выйдет за диапазон.
В структуре задачи для каждого процесса хранится PID родительского процесса. Зачем? Чтобы было кому возвращать код завершения.
На другие вопросы отвечу устно. К сожалению, на большое количество вопросов я не знаю ответ или не уверен. Постараюсь позже вернуться к этим вопросам еще раз. Необходимо прочитать раздел книги про память (2 и 3 главы). Оказались самыми сложными вопросами. Про уровень сложности последних вопросов вообще промолчу.
Как минимум, необходимо разобраться с главами «Управление памятью» и, возможно, «Файловые системы». А пока перейду к Windows. Посмотрим, какие еще сложные моменты всплывут.