I am searching for some information about how are apps launch on android. I want ot found infromation what make zygote and about fork() . Do you know some usefull web-sites or books?
I have written a two part series to explain Android Application launch process on my blog -
http://multi-core-dump.blogspot.com/2010/04/android-application-launch.html
http://multi-core-dump.blogspot.com/2010/04/android-application-launch-part-2.html
I hope you will find it useful.
There is a nice explanation in this presentation. It's written partially in Korean, but the most part of information in English.
Here is an concise(the process is very complex so a concise one still won't be a short one) yet precise answer based on AOSP 9.0.0.
Every Android Java process is forked from Zygote, so first is how Zygote starts.
init process is the first process in linux, it start the executable "app_process", whose internal is :
(entry point of app_process)int main
->void AndroidRuntime::start
startVm //start Java VM
startReg //register common native functions
//call java method ZygoteInit.main from native code
env->CallStaticVoidMethod
Then here is the most important java method: ZygoteInit.main, we get here from the above native code "env->CallStaticVoidMethod ".
This is also the first method in the call stack when you set a break point in main Activity's onCreate and start debuging your application and break there. But in fact your application never get to the beginning of ZygoteInit.main, it is executed from the beginning only in app_process(or say Zygote).
//Java code
->ZygoteInit.main
//Android application never get here(the beginning)
//start system server process which contains AMS/WMS,etc
forkSystemServer
//for Zygote, runSelectLoop never return
//for Android application, runSelectLoop returns a Runnable
//whose run() method will just execute ActivityThread.main
//which is considered as the real main entry of Android application
//since it contains the message loop
caller = zygoteServer.runSelectLoop
->zygoteServer.runSelectLoop
//this is the main loop of Zygote who is a
//server that receive process-creating requests
//from client processes and fork them
loop forever
//Zygote wait here for other process's requests to start new Java process
Os.poll(pollFds, -1);
//after wake up upon requests arrive, process the request
final Runnable command = connection.processOneCommand(this);
->ZygoteConnection.processOneCommand
read and parse process-start request command from client process
//the native linux fork() is executed in this methdod
//after it returns, we can decide which process we are in
//from pid's value just like the native fork()
pid = Zygote.forkAndSpecialize
//if in child
return handleChildProc
->ZygoteConnection.handleChildProc
return ZygoteInit.zygoteInit
->ZygoteInit.zygoteInit
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();//JNI method
//native code
->AppRuntime::onZygoteInit()
sp<ProcessState> proc = ProcessState::self();
//starting thread pool which contains binder threads
proc->startThreadPool();
return RuntimeInit.applicationInit
->RuntimeInit.applicationInit
return findStaticMain
->RuntimeInit.findStaticMain
//MethodAndArgsCaller is a Runnable,
//whose run() is constructed so that
//it just call ActivityThread.main()
//it is ActivityThread since there is a string parameter
//whose content is "android.app.ActivityThread" from the client process's request
return new MethodAndArgsCaller
//if in parent process i.e. Zygote
return null
//if in forked child process
return command;
//if in parent process i.e. Zygote
continue to run the loop
//Zygote never get here
//for Android application, now caller contains a MethodAndArgsCaller which is a Runnable
//whose run() calls ActivityThread.main and never return
//since ActivityThread.main runs the main message loop
caller.run();
When you start an Activity, finally you get into in Activity Manager Service(AMS, which is in system server process). If the process for that Activity is not created yet, AMS will send process-start request request to Zygote server (in the zygote process described above,started by init process), the process is like:
//in AMS (system server process)
final String entryPoint = "android.app.ActivityThread";
return startProcessLocked(....,entryPoint, ....);
->startProcessLocked
->Process.start
->ZygoteProcess.start
->ZygoteProcess.startViaZygote
->ZygoteProcess.zygoteSendArgsAndGetResult
//send the request to Zygote server through sockets
//note that "android.app.ActivityThread" is send to Zygote server as a parameter
At this time, the above listed Zygote code will wake up from
Os.poll(pollFds, -1);
and fork the child process, and after this, the parent process i.e. Zygote will again execute poll waiting for the next request, and the forked child process will return from runSelectLoop and execute ActivityThread.main as described in the above code listing.
So the exact entry point of the new process will be after the native fork() deep down in Zygote.forkAndSpecialize, in a native function called ForkAndSpecializeCommon to be exactly, then all the way up through a return route up to
caller = zygoteServer.runSelectLoop
in ZygoteInit.main. So although the call stack of an Android application start at ZygoteInit.main, the code executed in ZygoteInit.main begins after the call to runSelectLoop instead of the beginning of ZygoteInit.main.
About Activity: in fact Activity has nothing to do with entry point or start up process. An Activity is started when AMS send an Activity-start request to a process at any time. So Activity start process always begin in the main message loop when the start request is received, it is driven by message from AMS and is fully decoupled from the application start process.
Related
I am using Delphi 10.2 to create Android app that uses Rest components to read returning data from post form. When I press on a button to load the data it load them normally after about 3 seconds freeze. The problem if the user try to click (or touch) any control on the form the app exit immediately after the 3 seconds freeze but if the user did not touch the app the data was loaded normally !
What is the reason for that and how I should fix it ?
The code I use for the button is
RESTRequest1.Execute;
I use 3 components RESTClient , RESTRequest and RESTResponse
and here is the code I use to get the data:
procedure TfrmMain.RESTRequest1AfterExecute(Sender: TCustomRESTRequest);
var
return_response: string;
begin
if RESTResponse1.StatusCode = 200 then begin
//fill years
return_response := RESTResponse1.Content;
memo1.text := return_response;
end;
end.
On mobile platforms you should always use ExecuteAsync because it does not run in the same thread as the UI. Execute instead runs on the same thread as the UI so it freezes while the request is processing. Android closes the app if it is not responsive (= freezed) after some seconds, and this is your problem!
To be more precise, here's the doc:
The use of the ExecuteAsync method is strongly recommended on mobile
platforms. iOS (and likely Android) will terminate an application if
it considers the main thread to be unresponsive, i.e. if a running
request takes more than a second or two to return
You can find more info here.
The function ExecuteAsync, as you can see in the doc, has an useful parameter which takes an anonymous procedure. The code of this procedure will be called once the ExecuteAsync has finished his task. Here's an example:
RESTRequest1.ExecuteAsync(
procedure
begin
ShowMessage('Finished!');
end;);
This is very easy and also you don't need to type the other parameters since they alrady have a value by default. Again, if you look at the doc you'll see for example ASynchronized: Boolean = True;, so setting the second parameter after the anonymous proc to True would be not relevant.
I have been reading all I can find trying to figure out the software architecture behind Android's BINDER IPC mechanism. From what I understand, BINDER sits in Kernel-space and temporarily gives user-space applications an allocation of shared memory through which messages can be relayed between processes.
Where I begin to lose my grip is how the actual implementation works - specifically related to parcels.
I was looking on the net and found an implementation of an arbitrary service provided by Android, like Network/Wifi/Notificaiton/Battery, ect (Docs). From my reading I've learned that a user-space program should not instantiate a service class itself, but rather get a reference to one though Context.getSystemService(Context.X). As such, I took this as an indirect way of saying that Android already has the service running, or at least has the resources to start it when needed. The implementation was essentially laid out something like:
Battery.class
BatteryManager.setBatteryState(){
Parcel parcelLocal = Parcel.obtain();
parcelLocal.writeInterfaceToken("android.power.BatteryManager");
parcelLocal.writeInt(1/0); //Depending on requested state
BinderObject.transact //Send the data using BINDER
CheckForExceptions(); //Upon return, check for exceptions
ReadResponse(); //If none, read the response from the target
DoAppropriateAction(); //Whatever we need to do after setting the state
parcelLocal.recycle(); //Return the parcel resource
}
At first it seems simple: When the user does something like:
BatteryMonitor bMonitor = Context.getSystemService(Context.POWER_SERVICE);
bMonitor.setBatteryStatus(1);
Then the user's instance will use the BINDER mechanism to communicate with the system's actual service controller (Which is an instance of the same class?). But, however, the code shown above IS the implementation for the system's battery monitoring service, so who is actually receiving the BINDER data?
TL;DR: If this is all very confusing, which it very well may be as I tried to condense a thousand lines of code into 10, the summary is: When a user intends to control the state of hardware - such as Network/Wifi/Location/Notifcations(the touchscreen) - what is actually going on within Android and who is really controlling the hardware associated with these abstracted services?
Note: The above code is completely fabricated and was intended to only show general structure.
Most System Services run as threads within the system_server process. At boot, they pass an invitation-to-call (see calls to addService() in SystemServer.java) to servicemanager which then is able to distribute the invitation to apps calling getSystemService.
Once things are rolling, you can think of the whole setup as a kind of client-server architecture where your app is the client (remote or proxy side) and the server (local or stub side) is the system service that you're talking to. The client and server communicate through the inter-process communication (IPC) subsystem known as binder. There are different parts to the binder: Framework components perform the marshalling and unmarshalling of parcels, while the kernel driver does the actual memory copies to/from ioctl calls and keeps track of who's been invited to call at the process and thread level.
Apps interface with the binder via a proxy. For example, when you use LocationManagerService, you get an instance of android.location.ILocationManager. One of the methods in the Proxy class is getLastLocation():
...
#Override public android.location.Location getLastLocation(android.location.LocationRequest request, java.lang.String packageName) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.location.Location _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((request!=null)) {
_data.writeInt(1);
request.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
_data.writeString(packageName);
mRemote.transact(Stub.TRANSACTION_getLastLocation, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.location.Location.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...
Here you can see that the transaction code TRANSACTION_getLastLocation is written to the interface along with any necessary data, and a result is read. On the stub side, there's an onTransact() method running in the service's process space which processes all of the incoming transactions according to the transaction code:
...
case TRANSACTION_getLastLocation:
{
data.enforceInterface(DESCRIPTOR);
android.location.LocationRequest _arg0;
if ((0!=data.readInt())) {
_arg0 = android.location.LocationRequest.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
java.lang.String _arg1;
_arg1 = data.readString();
android.location.Location _result = this.getLastLocation(_arg0, _arg1);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
...
In a nutshell, the system_service process acts on behalf of the caller. This allows it to do what are usually privileged operations on hardware or other system resources. The security is based on 1) the app having the invitation to call (obtained from service_manager via getSystemService) and 2) passing whatever checks the service itself implements, such as checking ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION in the case of LocationManagerService (declared in the manifest and approved at install-time by the end-user).
UPDATE: In the case of location service, these hardware operations entail getting the actual NMEA data from the GPS hardware. The way this is currently accomplished is via the GpsLocationProvider class which interfaces to native code via JNI. This native code (com_android_server_location_GpsLocationProvider.cpp) is where the hardware device is opened (via an abstraction layer held in a hw_module_t struct), location callbacks are made (e.g., location_callback()), etc. All of this runs within the system_server process space with privileged UID system. You can verify this by running a location-enabled app, looking for GpsLocationProvider tags in the logcat and confirming that the logged PID is that of system_server. For example:
$ adb logcat | grep -i gps
...
D/GpsLocationProvider( 731): Reset GPS properties, previous size = 8
...
and
$ adb shell ps | grep system_server
system 731 441 1094884 89232 ffffffff b74d1d05 S system_server
$
Finally, I highly recommend the video tutorial Deep Dive Into Android IPC/Binder Framework to learn more about this. The talk's slides can be found here.
As we all know android doesn't unload *.so after close application. I had found the solve by adding "exit(0)" at the end, that is solved problem, but I wanna know exactly that all are OK.
The code is work fine as expected after solving the problem:
static int value = 0;
// In android_main
LOGI("value = %d", value); // always print 0, but not 1 after second run of
// application as it was without "exit(0)" at the end
value = 1;
I wanna to test that on class like:
class A {
A() {
LOGI("Constructor");
}
~A() {
LOGI("Destructor");
}
statis A a;
In such way prints only "Constructor".
Maybe because of destructor is calling after when LOGI isn't working more for application that will be closed ?
Question: why LOGI in destructor isn't working? According to first example on top destructor is calling really.
This is not only pointless, but quite possibly counterproductive. If android wants the memory utilized by your process, it will terminate the process to reclaim it; if it doesn't, it won't.
To specifically address your question, killing or exiting a process does not invoke destructors, it merely terminates execution and the kernel bulk-releases all memory and (conventional) resources.
Do not try to second guess the system, as that can frequently result in killing a process only to have android immediately restart it. Further, it can allegedly cause problems with a few Android IPC resources (like the camera) which may not be freed up when the process of a utilizing application unexpectedly dies.
I have an Android app that uses NDK - a regular Android Java app with regular UI and C++ core. There are places in the core where I need to call Java methods, which means I need a JNIEnv* for that thread, which in turn means that I need to call JavaVM->AttachCurrentThread() to get the valid env.
Previously, was just doing AttachCurrentThread and didn't bother to detach at all. It worked fine in Dalvik, but ART aborts the application as soon as a thread that has called AttachCurrentThread exits without calling DetachCurrentThread. So I've read the JNI reference, and indeed it says that I must call DetachCurrentThread. But when I do that, ART aborts the app with the following message:
attempting to detach while still running code
What's the problem here, and how to call DetachCurrentThread properly?
Dalvik will also abort if the thread exits without detaching. This is implemented through a pthread key -- see threadExitCheck() in Thread.cpp.
A thread may not detach unless its call stack is empty. The reasoning behind this is to ensure that any resources like monitor locks (i.e. synchronized statements) are properly released as the stack unwinds.
The second and subsequent attach calls are, as defined by the spec, low-cost no-ops. There's no reference counting, so detach always detaches, no matter how many attaches have happened. One solution is to add your own reference-counted wrapper.
Another approach is to attach and detach every time. This is used by the app framework on certain callbacks. This wasn't so much a deliberate choice as a side-effect of wrapping Java sources around code developed primarily in C++, and trying to shoe-horn the functionality in. If you look at SurfaceTexture.cpp, particularly JNISurfaceTextureContext::onFrameAvailable(), you can see that when SurfaceTexture needs to invoke a Java-language callback function, it will attach the thread, invoke the callback, and then if the thread was just attached it will immediately detach it. The "needsDetach" flag is set by calling GetEnv to see if the thread was previously attached.
This isn't a great thing performance-wise, as each attach needs to allocate a Thread object and do some internal VM housekeeping, but it does yield the correct behavior.
I'll try a direct and practical approach (with sample code, without use of classes) answering this question for the occasional developer that came up with this error in android, in cases where they had it working and after a OS or framework update (Qt?) it started to give problems with that error and message.
JNIEXPORT void Java_com_package_class_function(JNIEnv* env.... {
JavaVM* jvm;
env->GetJavaVM(&jvm);
JNIEnv* myNewEnv; // as the code to run might be in a different thread (connections to signals for example) we will have a 'new one'
JavaVMAttachArgs jvmArgs;
jvmArgs.version = JNI_VERSION_1_6;
int attachedHere = 0; // know if detaching at the end is necessary
jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
if (JNI_EDETACHED == res) {
// Supported but not attached yet, needs to call AttachCurrentThread
res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
if (JNI_OK == res) {
attachedHere = 1;
} else {
// Failed to attach, cancel
return;
}
} else if (JNI_OK == res) {
// Current thread already attached, do not attach 'again' (just to save the attachedHere flag)
// We make sure to keep attachedHere = 0
} else {
// JNI_EVERSION, specified version is not supported cancel this..
return;
}
// Execute code using myNewEnv
// ...
if (attachedHere) { // Key check
jvm->DetachCurrentThread(); // Done only when attachment was done here
}
}
Everything made sense after seeing the The Invocation API docs for GetEnv:
RETURNS:
If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.
Credits to:
- This question Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread that in its example made it clear that it was necessary to double check every time (even though before calling detach it doesn't do it).
- #Michael that in this question comments he notes it clearly about not calling detach.
- What #fadden said: "There's no reference counting, so detach always detaches, no matter how many attaches have happened."
In android native activity you can handle main commands from system in your own method. I know how to do this, but i dont know what all states i can handle. I know few states like APP_CMD_SAVE_STATE, APP_CMD_INIT_WINDOW... but that´s not all. I cant find list of states or android_native_app_glue.h header file anywhere. Can someone refer me or write list of events with their numebers and when they´r called?Thanks
void CMDMethod(struct android_app* app, int32_t state)
{
switch(state)
{
case APP_CMD_SAVE_STANE: //some code
break;
//what can be next cases?
}
}
void android_main(struct android_app* state)
{
state->onAppCmd = CMDMethod;
}
Heres the enum found in android_native_app_glue.h
enum {
APP_CMD_INPUT_CHANGED,
APP_CMD_INIT_WINDOW,
APP_CMD_TERM_WINDOW,
APP_CMD_WINDOW_RESIZED,
APP_CMD_WINDOW_REDRAW_NEEDED,
APP_CMD_CONTENT_RECT_CHANGED,
APP_CMD_GAINED_FOCUS,
APP_CMD_LOST_FOCUS,
APP_CMD_CONFIG_CHANGED,
APP_CMD_LOW_MEMORY,
APP_CMD_START,
APP_CMD_RESUME,
APP_CMD_SAVE_STATE,
APP_CMD_PAUSE,
APP_CMD_STOP,
APP_CMD_DESTROY,
};
APP_CMD_INPUT_CHANGED - Command from main thread: the AInputQueue has changed. Upon processing this command, android_app->inputQueue will be updated to the new queue (or NULL).
APP_CMD_INIT_WINDOW - Command from main thread: a new ANativeWindow is ready for use. Upon receiving this command, android_app->window will contain the new window surface.
APP_CMD_TERM_WINDOW - Command from main thread: the existing ANativeWindow needs to be terminated. Upon receiving this command, android_app->window still contains the existing window; after calling android_app_exec_cmd it will be set to NULL.
APP_CMD_WINDOW_RESIZED - Command from main thread: the current ANativeWindow has been resized. Please redraw with its new size.
APP_CMD_WINDOW_REDRAW_NEEDED - Command from main thread: the system needs that the current ANativeWindow be redrawn. You should redraw the window before handing this to android_app_exec_cmd() in order to avoid transient drawing glitches.
APP_CMD_CONTENT_RECT_CHANGED - Command from main thread: the content area of the window has changed, such as from the soft input window being shown or hidden. You can find the new content rect in android_app::contentRect.
APP_CMD_GAINED_FOCUS - Command from main thread: the app's activity window has gained input focus.
APP_CMD_LOST_FOCUS - Command from main thread: the app's activity window has lost input focus.
APP_CMD_CONFIG_CHANGED - Command from main thread: the current device configuration has changed.
APP_CMD_LOW_MEMORY - Command from main thread: the system is running low on memory. Try to reduce your memory use.
APP_CMD_START - Command from main thread: the app's activity has been started.
APP_CMD_RESUME - Command from main thread: the app's activity has been resumed.
APP_CMD_SAVE_STATE - Command from main thread: the app should generate a new saved state for itself, to restore from later if needed. If you have saved state, allocate it with malloc and place it in android_app.savedState with the size in android_app.savedStateSize. The will be freed for you later.
APP_CMD_PAUSE - Command from main thread: the app's activity has been paused.
APP_CMD_STOP - Command from main thread: the app's activity has been stopped.
APP_CMD_DESTROY - Command from main thread: the app's activity is being destroyed, and waiting for the app thread to clean up and exit before proceeding.
I think I saw something about that in this book http://www.packtpub.com/android-ndk-beginners-guide/book. But can be wrong. In there there definitely is a chapter about creating a completely native activity with that loop processing all those states.