Android Internals updated
Vikash Kumar
Kernel
What is a kernel? A kernel is a computer program that is the core of a
computer’s operating system. It has complete control of everything inside of
the system. It’s the first program to be loaded on startup and it handles the
rest of the startup process. It handles the CPU, memory, manages input-
output devices, and communicates with other processes in the operating
system through system calls. System calls occur when other processes
want to do something that is hardware related.
Get more development news like this Subscribe
Comments
The modifications on Android from the original kernel came from the fact
that Android runs on phones, which have limited memory, and is not always
connected to a power source.
Out of memory killer: this was created to help kill apps that users
leave running. Because Android also run on low-end devices, it must
make the effort clean up unused apps before it runs out of memory to
a catastrophic level.
Wakelocks: Allows Android to sleep, and consume as little energy as
possible.
Init
The next step, in our list of architecture is the init. The init process is a
binary that’s picked up by the kernel run on startup. It is also the root of all
other processes, which will be created from this process, spawning
everything else.
Another way of looking at it is a list of instructions and settings about what
other processes to wake up, and how they need to be configured. Most of
the things that init will start up are called daemons.
Daemons are processes that will run in the background. Some that might
look familiar to you are adbd or installd that’s being used to install apps.
1
Zygote
The Zygote is a special process; a special daemon. It’s the base of all other
Java or Kotlin based applications. It contains a readily available runtime
environment/virtual machine that’s ready to run the app.
When we write Java, it is precompiled, and it’s changed and managed by
someone before running on an environment. We know this as Dalvik, and
this environment has things like garbage collection, memory allocations,
heap, stack, etc. All these things exist within Zygote.
Dalvik is helpful on Android because we do not have to pre-initialize
anything, and as a result, saves us start-up time.
Processes and UIDs
In Linux, apps run under the same user. Apps that run that way on Linux
can share common resources; they can share memory and files, but
Android decided against this. Instead, a sandbox is created for each
process and app running on the phone.
This is accomplished by pretending that every app is a different user, as
such, they get their own user ID (UID). They cannot corrupt each other’s
memory, and they cannot write into each other’s files. This makes Android
very secure.
When apps need to be able to interact with each other, they use Binder.
Binder
Binder allows inter-app communication in a safe way.
Considering the following ConnectivityManager code:
ConnectivityManager connectivityManager = (ConnectivityManager)
MyApplication.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
The result of the network information is coming from the system service.
You may wonder why the call cannot simply be in the app.
2
The reason is that it’s doing complex things such as asking the Wi-Fi driver
or asking other hardware components about their situation. If this was to be
handled internally, it would lack many of the permissions, so putting this in
a centralized service makes sense.
Suppose I encounter a bug, and want to see the source code of the above
method:
public class ConnectivityManager {
private final IConnectivity Manager mService;
...
public NetworkInfo getActiveNetworkInfo() {
try {
return mService.getActiveNetworkInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
...
This is merely a wrapper around an interface, so digging deeper:
interface IConnectivityManager
3
{
Network getActiveNetwork();
Network getActiveNetworkForUid(int uid, boolean ignoreBlocked);
NetworkInfo getActiveNetworkInfo();
NetworkInfo getActiveNetworkInfoForUid(int uid, boolean
ignoreBlocked);
NetworkInfo getNetworkInfo(int networkType);
NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean
ignoreBlocked);
NetworkInfo[] getAllNetorkInfo();
Network getNetworkForType(int networkType);
Network[] getAllNetworks();
NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int
userId);
We find an interface - it’s not actually not speaking directly to the activity
manager, but going through a Binder.
4
Our app is not directly talking to the other app. Instead, it’s going through a
journey down to the kernel, then up again to send our message with the
result.
The Binder Java class has two main methods:
public boolean transact(int code, Parcel data, Parcel reply, int flags)
protected boolean onTransact(int code, Parcel data, Parcel reply, int
flags) throws RemoteException
The sender will call transact and the recipient will get onTransact, which
passes a code, a Parcel, which is all the data, and maybe the method
arguments that we wanted to send.
5
On the recipient side, we open these up to see what we got and figure out
what we want to do with it.
The AIDL tool comes in and it serves as the bridge between the actual
method and a transaction and it generates. It auto-generates a lot of code.
One is the proxy which is the sender and one is the stub which is the
recipient. This is an example of how the proxy would look.
@Override public android.net.Network getActiveNetwork() throws
android.os.RemoteException
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.net.Network _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getActiveNetwork, _data,
_reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result =
android.net.Network.CREATOR.createFromParcel(_reply);
6
else {
_result = null;
finally {
_reply.recycle();
_data.recycle();
return _result;
In the middle of there is the transact method which is the actual Binder.
This is the real implementation:
7
System Server
The system server is the heart of Android, and it’s responsible for all things
Android. It’s one process, and it’s written in Java. It tells Zygote, to fork,
create the system server, and run the Java code on a new instance.
It has three managers:
Activity Manager
Window Manager
Package Manager
The window manager is responsible for windowing and being in charge of
all things windows. It keeps tracks of window activities and it keeps track of
what is visible. It is also responsible for transitions between activities for an
overall good UI experience.
The package manager is responsible for installing new applications. It’s
responsible for resolving the correct activity when I send out an intent.
8
The activities manager is the heart of the heart of Android. It is responsible
for everything: all the activities that we create along with the services, and
content providers are managed by the activities manager.
Processes and Activities
Every app sits in a different process, but all activities that are going to be
created for that app is created in the same process. For a simple example,
we have activity manager monitoring one app so it has one task and it
keeps records of all the activities that it has. The activity record shows what
state they are, in this case, resumed because it’s the top activity.
If I add another activity from it, say navigate in my app to a secondary
activity, another record would be added to the same stack, and another
activity would be added to the same process and the states have changed
because there is a secondary app activity resumed and the one below it is
no longer active.
The main function of the activity manager service is to manage the lifecycle
of all our apps. The one top rule that they have could only be one resumed
app up at all times.
The activity manager is also responsible for telling the window manager to
create a surface for an app or remove a surface for an activity.
In activity manager service, there are two methods that are
applied: adjustLocked and computed. Those are the methods that are
going to be get called whenever anything changes, and whenever any
activity gets created, resumes, or stops.
Questions