How Android works, Part 3
In this article, I'll talk about the components that make up applications for Android, and about the ideas behind this architecture.
How Android works, part 1
How Android works, Part 3
Web vs desktopIf you think about the differences between modern web applications and "ordinary" desktop applications, you can, among the shortcomings, highlight several advantages of the web:
Web applications are portable between architectures and platforms, like Java.
Web applications do not require installation and are always updated, just like Android Instant Apps .
In addition, web applications exist as pages that can link to each other - both within the same site and between sites. At the same time, a page on one site does not have to be limited to a link only to the main page of another, it can refer to a specific page within another site (this is called deep linking ). Referring to each other, individual sites are combined into a common network, the web.
Multiple copies of one page - for example, several profiles in a social network - can be simultaneously opened in several tabs of the browser. The browser interface is designed to switch between simultaneous sessions (tabs), and not between individual sites - within one tab you can navigate through the links (and back and forth through history) between different pages of different sites.
All this is contrasted with the "desktop", where each application runs separately and often independently of others - and in this respect, how Android applications are structured is much closer to the web than to "traditional" applications.
Activities & intentsThe main kind of application components for Android is activity . Activity is one "screen" of the application. Activity can be compared to a page on the web and with an application window in the traditional window interface.
About windows Actually, the windows in Android, too, is at a lower level - the window manager level. Every activity usually has its own window. Most activity windows are deployed on the entire available screen, but:
First, Android supports multi-window mode - split-screen, picture-in-picture and even freeform.
Secondly, Android supports the connection of several displays.
Thirdly, activity can intentionally occupy a small part of the screen Theme_Dialog).
For example, in an email application, there may be activities such as Inbox Activity, Email Activity, Compose Activity, and Settings Activity.
Like the pages of a single site, the activity of one application can be started both from each other, and independently from each other (by other applications). If the web page is accessed via a URL (link), then the Android activity is launched through intentions.
Intent is a message that tells the system what to do (for example, open this URL, write a letter to this address, call this phone number or take a photo).
An application can create such an intent and pass it to the system, and the system decides which activity (or other component) will implement it. This activity is started by the system (in the existing application process or in the new one, if it is not already started), this intent is transmitted to it, and it executes it.
The standard way to create intent is through the the corresponding class in the Android Framework. To work with activity and intent from the command line in Android, there is an commandam - a wrapper over the standard class Activity Manager:
# pass -a ACTION -d DATAIntents can be explicit and implicit. Explicit intent indicates the identifier of the particular component that you want to run-most often it's used to start another activity from one activity inside one application (the intent may not even contain other useful information).
# open the site
$ am start -a android.intent.action.VIEW -d http://example.com
# make a phone call
$ am start -a android.intent.action.CALL -d tel:+7-916-271-05-83
Implicit intent must necessarily indicate the action to be taken. Each activity (and other components) indicates in the application manifest what intentions they are willing to handle (for example, ACTION_VIEW for links to the https: //example.com domain). The system selects the appropriate component among the installed components and launches it.
If the system has several activities that are ready to process the intent, the user will be given a choice. This usually happens when several similar applications are installed, for example, several browsers or photo editors. In addition, the application can explicitly ask the system to display a selection dialog (in fact, the transmitted intent then wraps around the new intent with ACTION_CHOOSER) - this is usually used to create a beautiful dialog Share:
In addition, activity can return the result to the activity that caused it. For example, activity in a camera application that can handle the intent to "take a photo" ACTION_IMAGE_CAPTURE) returns the taken photo to the activity that created this intent.
In this application, containing the original activity, you do not need permission to access the camera.
Thus, the correct way to use an Android application to take a photo is not to require permission to access the camera and use the Camera API, but to create the desired intent and allow the system camera application to take a photo. Similarly, instead of using the permission READ_EXTERNAL_STORAGE and direct access to user files, it is worth giving the user the opportunity to select a file in the system file manager (then the original application will be allowed to access this file).
<blockquote> A unique aspect of the Android system. For example, if you want the user to capture a photo with the device, what's yours? You do not need to incorporate or even link to the code from the camera app. Instead, you can simply start the activity in the camera app. When complete, the photo is even returned to your app. <Tgsrbq> In this case, the "system" application is not necessarily the one that was preinstalled by the manufacturer (or the author of the Android build). All installed applications that can handle this intent, in this sense are equal to each other. The user can choose any of them as the default application for such intentions, and can choose the desired one each time. The selected application becomes "system" in the sense that the user chose to perform exactly all tasks (that is, intentions) of this type that occur in the system.
The very permission to access the camera is only needed for applications that implement their camera interface - for example, the actual camera application, the application for video calls or augmented reality. Conversely, an ordinary messenger access to the camera "so you can send photos" is not needed, as you do not need access to make calls to the application of a large bank.
This logic obeys even such "parts of the system" as, for example, the home screen (launcher, launcher). Loncher is a special application with its own activities (which use special flags likeexcludeFromRecents and launchMode = "singleTask").
Pressing the "home" button creates an intent of the category "HOME", which then goes through the usual mechanism of processing intentions - including, if several remote controllers are installed in the system and no one is selected as the default launcher, the system displays a selection dialog.
The "launch" of the application from the launcher also happens through intent. Loncher creates an explicit intent of the category LAUNCHER, which is "processed" by running the main activity of the application.
An application can have several activities that support such an intent, and be displayed several times in the locker (you may need to specify a different taskAffinity for them). Or not have one and not be displayed in the batch at all (but still displayed in the full list of installed applications in the settings). "Ordinary" applications do so rarely; The most famous example of this behavior is Google Play Services.
Many operating systems are divided into the actual operating system and applications installed on top, nothing about each other not knowing and not able to interact. The system of components and intentions of Android allows applications, still absolutely nothing about each other not knowing, to make up for the user one integrated system user experience - installed applications implement parts of one large system, they are a system. And this, on the one hand, is transparent to the user, on the other - it presents unlimited possibilities for customization.
In my opinion, it is very beautiful.
Tasks & back stackAs I said, in the browser the user can switch between the tabs, but between the tabs, the history of each of which can contain many pages of different sites. Likewise, in Android, a user can switch between tasks that are displayed as cards in recents screen . Each task is a back stack - several activities that are "superimposed" on each other.
When one activity launches another, the new activity is placed on top of the old one. When the top activity in the stack is completed - for example, when the user presses the system button "back" - the previous activity on the stack is displayed again on the screen.
Each stack can include activity from different applications, and multiple copies of one activity can be simultaneously opened within different tasks or even within the same stack.
When you start a new activity, you can specify special flags, such assingleTop, singleTask, singleInstance, andCLEAR_TOP, which modify this mechanism. For example, browser applications usually allow the launch of only one copy of their main activity, and to switch between open pages implement their own system of tabs. On the other hand, Custom Tabs is an example of an activity in the browser (most often Chrome), which behaves almost "as usual" , that is, it shows only one page, but allows you to open several copies of your own at the same time.
App lifecycleOne of the main limitations of embedded and mobile devices is a small amount of RAM (RAM). If modern flagship devices are already equipped with several gigabytes of RAM, then in the first smartphone on Android, HTC Dream (which is also T-Mobile G1), released in September 2008, it was only 192 megabytes.
The problem of limited memory is further complicated by the fact that mobile devices, unlike "regular" computers, do not use swap-partitions (and swap-files) - including because of low (in comparison with SSD and HDD) access speeds to SD-cards and built-in flash memory, where they could be placed. Beginning with KitKat version 4.4, Android uses zRAM swap, that is, it effectively squeezes the underused portions of memory. Nevertheless, the problem of limited memory remains.
If all processes are a black box for the system, the best possible behavior strategy in the event of a lack of free memory is to forcefully terminate (kill) some processes, which makes Linux Out Of Memory (OOM) Killer. But Android knows what's going on in the system, he knows which applications and which components are running, which allows for a much more "smart" memory release scheme.
First, when the free memory finishes, Android explicitly asks the application to free unnecessary memory (for example, reset the cache) by calling the methodsTrimMemoryonLowMemory. Secondly, Android can efficiently garbage collection in background applications, freeing up memory that they no longer use (at the Java level), without slowing down the current application.
But the main mechanism for releasing memory in Android is the completion of the least used applications. The system automatically selects the applications that are least important to the user (for example, those from which the user has long left), gives their components a chance to free up resources by calling methods such as anDestroy, and completes them, completely freeing up the memory and resources they use.
If the user returns to the activity of the application, completed by the system due to lack of memory, this activity is started again. In this case, the restart is transparent for the user, since the activity saves its state when onSaveInstanceState finishes) and restores it at the next start. Implemented in the Android Framework widgets use this mechanism to automatically save the state of the interface (UI) on restarting - up to the text entered in EditText, cursor position, scroll position, etc. The application developer can additionally implement saving and restoring some other data specific for this application.
I emphasize that Android can restart applications not completely, but component-wise, leaving the unused parts complete - for example, from two copies of one activity one can be restarted and the other one to remain complete.
From the user's point of view, this mechanism is similar to using swap: in both cases, when you return to the unloaded part of the application, you have to wait a little while it loads again - in one case, from the disk, in the other - it is recreated by the saved state.
It is this mechanism of automatic restart and restore of the state that creates a feeling for the user that applications are "always running", eliminating the need to explicitly start and close applications and save the data entered into them.
ServicesApplications may need to perform actions that are not directly related to any activity, including continuing to make them in the background when the entire activity of this application is completed. For example, an application can download a large file from the network, process photos, play music, synchronize data, or simply maintain a TCP connection to the server to receive notifications.
Such functionality can not be implemented simply by launching a separate thread - this would be for the system a black box; including, the process would be completed at the completion of all activities, regardless of the state of such background operations. Instead, Android suggests using one more kind of component - the service .
The service is needed to inform the system that in the process of the application, actions are performed that are not part of the activity of this application. The service itself does not mean creating a separate thread or process - its entry points are run in the main application thread. Typically, the service implementation runs additional threads and manages them independently.
Services in many respects are similar to activity: they are also launched with the help of intentions and can be completed by the system when there is a shortage of memory.
Launched services can be in three states:
Foreground service is a service that performs an action, the state of which is important to the user, for example, downloading a file or playing music. This service is obliged to display a notification in the system notification curtain (examples: download status, current song title and playback control). The system considers such a service to be about as important to the user as the current activity, and will complete it only as a last resort.
Background service - a service that performs a background action, the state of which is not of interest to the user (most often, synchronization). Such services can be completed with a lack of memory with a much greater probability. In older versions of Android, a large number of simultaneously running background services often became the cause of "brakes"; starting with version 8.0 Oreo, Android seriously restricts the use of background services, forcibly completing them a few minutes after , as the user exits the application.
Bound service - the service that processes the incoming Binder connection. Such services provide some functionality for other applications or systems (for example, WallpaperService and Google Play Services). In this case, the system can automatically start the service when clients connect to it and stop it when they are turned off.
The recommended way to perform background actions is to use JobScheduler , the system's background work scheduling mechanism. JobScheduler allows the application to specify the startup criteria for the service, such as:
Availability of the network. Here, the application can indicate whether this service requires a network connection, and if so, whether it is possible to work in roaming or when using a metered connection.
Connecting to a power source, which allows the services to be performed, not "planting a battery".
Idle (idle), which allows the services to run while the device is not in use, without slowing down the work during active use.
Content updates - for example, the appearance of a new photo.
The period and the deadline for launching - for example, cleaning the cache can be done daily, and the synchronization of events in the calendar - every hour.
JobScheduler plans to execute (implemented as a call through Binder) registered services in it according to the specified criteria. Since JobScheduler is a system-wide mechanism, it takes into account, when planning, the criteria of registered services for all installed applications. For example, it can start services in turn, instead of simultaneously, to prevent a sharp load on the device during use, and schedule periodic execution of several services in small groups (batch) to prevent constant power-on / off of radio equipment.
About TCP connection As you can see, using JobScheduler can not replace one of the options for using background services - maintaining a TCP connection to the server to receive push notifications. If Android provided the application with this capability, the device would have to keep all applications that connect to their servers running all the time, and this, of course, is impossible.
The solution to this problem is special push-services, the most famous of which is Firebase Cloud Messaging from Google (formerly Google Cloud Messaging ).
The client part of FCM is implemented in the Google Play Services application. This application, which is specifically excluded from the usual restrictions on background services, supports one connection with Google servers. The developer, who wants to send a push notification to his application, forwards it via the server part of the FCM, after which the Play Services application receives the message and sends it to the application to which it is intended.
This scheme allows, on the one hand, instantly deliver push notifications to all applications (without waiting for the next synchronization period), on the other hand, do not keep many applications running simultaneously.
Broadcast receivers & content providersIn addition to activity and services, Android applications have two other kinds of components that are less interesting for discussion: broadcast receivers and content providers.
Broadcast receiver is a component that allows an application to receive broadcasts , a special kind of messages from the system or other applications. Initially, broadcasts, as the name suggests, were mainly used to send broadcast messages to all subscribing applications - for example, the system sends an AIRPANE_MODE_CHANGED message when the airplane mode is turned on or off.
Now, instead of subscribing to such broadcasts asNEW_PICTURE and NEW_VIDEO, applications should use JobScheduler. Broadcasts are used either for rarer events (such as BOOT_COMPLETED), or with explicit intent, that is, as a message from one application to another.
Content provider is a component that allows an application to give other applications access to the data it manages. An example of the data that can be accessed in this way is the user's contact list.
In this case, the application can store the data itself in any way, including on the device in the form of files, in this database (SQLite) or request them from the server over the network. In this sense, the content provider is a unified interface for accessing data, regardless of the form of their storage.
Interaction with the content provider is much like accessing a remote database through the REST API. The client application requests data via a URI (for example,
content: //com.example.Dictionary.provider/words/42) via ContentResolver. The server application determines to which particular data set the request was made using the UriMatcher, and executes the requested action (query, insert, update, delete).
It is on top of content providers that the Storage Access Framework is implemented, allowing applications that store files in the cloud ( for example, Dropbox and Google Photos) to grant access to them to other applications without taking up space on the device with a full copy of all files stored in the cloud.
In the next article, I'll talk about the process of loading Android, about the contents of the file system, about how the user and application data are stored, and about root access.
|Vote for this post
Bring it to the Main Page