Digging Into Android System Services

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
thank you so much for coming today my name is Dave I'm a freelance Android developer based in Denver I'm very happy to be with you all today today what I've come here to talk to you about is digging into Android system services so hopefully everybody's in the right room if not I won't be offended if you get up and leave and if you happen to take a nap I'll just throw something at you no problem okay so why are you here well let me ask you a question first how many of you in the room are Android developers okay pretty much all of you good so either part-time full-time or at some capacity you've written Android code or you've written an Android app either for yourself or professionally you've played around with the framework a little bit okay or maybe you're just curious those are all good reasons why you might be here right so you might just want to learn the platform internals so what we're going to talk about today is we're gonna talk about primarily what does Android look like just below the surface of those api's that you touch everyday okay so we're gonna see kind of how they're architected how do they function and some things along those lines so to some degree maybe you're just curious how things work and that's a good thing you know those of you who are Android developers one of the best ways to master the platform you use every day is to understand a little bit about the mechanics of how it works so that's a good thing to do you might want to figure out how to trace AOSP code AOSP stands for Android open source project Android is open source which means you as Android developers can freely go in and look at the source code associated with the framework that you interact with in your apps and if you aren't doing that you should be because one of the best ways to again understand how that platform works why are things doing what you may not expect them to do or maybe what they aren't documented to do those types of things you can figure out by looking at the framework code okay but there are some issues associated with navigating the source if you're not familiar with it so hopefully some of the basics that we're gonna go through here today will give you an idea of how to walk your way through the source code if you need to do that okay and in addition to that as we're going through this discussion where there may be some interesting pieces that might actually affect how you write your once you understand better how the framework actually works so we'll kind of hit those along the way as we go through sound good all right let's do it so this is a overly simplified diagram of the Android software stack there are many diagrams like this but this one is mine okay so this basically just describes all of the the primary levels of software involved in the overall operating system from the kernel that really gets real close to the hardware all the way up to the applications that you and I are most often going to be writing okay and there's some glue code in between for talking to different pieces of hardware and services etc and then we have that secondary layer in there that we call the application framework right the framework is essentially the api's that you touch in your apps when you're writing these excuse me when you're writing these applications okay so that's the piece I want to focus on here today okay we're gonna be looking at how is that piece structured and going again just below that layer of the surface of the API to get a sense for how these things work and just get a better understanding of how this all is put together so we're gonna focus on the framework today all right so inside of the android framework those of you who are Android developers which is most of you you've interacted with a large variety of system services over the period of time that you've written your apps right you go into the API framework and you have things for system services for accessing notifications dealing with alarms you know all these different types of situations and in the case of the API the class or the the interface that you interact with is something called a manager right so there's alarm manager notification manager power manager etc etc right it turns out the way that the API or the system is actually structured that class that you touch in your application doesn't do a whole lot if you were to go look at the code of that particular class you would see very little in it and we're gonna look at an example of it here in just a minute the majority of the interesting stuff that things like alarm service or the notification service do lives inside of a separate service object that lives in another process okay so they think about this as two separate processes on the system you have your application which is where that manager class that you interact with lives and then you have the actual service that does all the interesting work that lives somewhere else on the system okay now for most system services the name of that processes system server not all system services live here there are a few kind of spread throughout different places but the majority of them live in one place called system server okay and that is the housing for the actual services that do the real grunt work of talking to Hardware interacting with drivers etc etc whatever the service is that you're interacting with so in terms of bringing this out sort of system-wide if you look at this from a multiple applications perspective there is exactly one instance of any given service so an alarm service notification service there is one of those things living in one of those processes will stick with system server for now every application that wants to interact with that service has its own instance of a manager running inside so the alarm manager the notification manager there's at least one of those in every application okay so there may be multiples of those running on the device but there's always only one service okay now that doesn't necessarily mean that there's only one manager per process either there can be more than one in a given application but we'll talk about that in just a minute okay all right so where do these managers come from so I mentioned that the manager that you touch as part of the framework lives inside of your process and those of you who are Android developers are probably quite familiar with this API right context good system service you've probably called it a hundred times with a variety of different service names to get access to these individual managers they always come back to this one instance so how does this thing actually work how is it put together if you look underneath the hood the construction of the framework that lives in your process actually looks something like this okay so in Android pretty much everything that you interact with as far as the top-level component either is a context or has access to a context context is everywhere in android okay so activities are context services are a context content providers and broadcast receivers are given access to a context so it's always there available for you so that you can access things like the system service but what you may not know is that top-level context like an activity for example is actually an implementation of something called a context wrapper the functionality associated with the core context is not implemented in those classes those classes wrap something underneath call the core context imple okay and that is actually the same across all contexts it's not the same instance but it's the same implementation there's one of those defined for every activity every service etc etc that context imple has a reference to something called a system service registry and that registry is where all of the individual manager classes that you interact with come from now the way that these are created is they are loaded lazily and cached so the first time that say the alarm manager is created in your process is the first time that you go to try and access it so when you call get system service alarm service if it's the first time you've done that the framework will create an instance of the alarm manager and then hold on to it then the next time you ask for it you'll get the same one back so this registry basically is just a lazy loaded cache of those manager objects but these things are primarily cached per context not per process there are a few services that you'll only ever have one instance of them but generally speaking you can have one alarm manager or one notification manager per context in your app so for every activity every service they'll each get their own instance of that particular manager something that's interesting to note probably not necessarily having a heavy performance impact on your but it's good to know that if you call get system service from a large variety of different places you're actually creating different instances of the same manager whereas if you can sort of localize those to a single place you can create fewer objects okay again managers because they're not that heavy-duty they don't do a lot of work this is probably not a significant issue but it is a mobile device it is a constrained environment the fewer things you can do the better so it's kind of probably not a an early-stage optimization but something you might look at being able to do is coalescing those accesses to different system services to reduce the number of managers you're actually creating inside of your application ok all right so this is just a little bit of snippet of source code from the framework this is what's inside of system service registry and I just want to give you an idea of how these things are all put together so we're gonna bring out some code here for just a minute because I want you to focus on those outer elements there but basically what happens is when your application process launches when it's very first created this list of services is statically created inside of the registry but notice that the objects themselves aren't created what are registered is basically a callback called a fetcher that tells the framework how to create a given manager the first time you ask for it and then it is bound to the service name that you would pass to get system service to ask for that particular service so on boot or not on on launch of the application you would get all of these individual elements created but no actual managers exist only when you try to access individual services well that callback code run which we'll look at a little bit later on which will be responsible for creating the actual instance itself ok so we'll come back to this example and look a little bit more deep at the other piece in just a minute but for now just sort of keep that in your mind that this is sort of how the registry works and there's one of these for every context in your application every activity every service etc etc ok all right so we go back to this diagram for a minute so I mentioned that your application and the system services live in different processes so that means that this diagram is a heavy oversimplification of what's going on I can't just take a manager have it talk directly to a service without something in between because they're in two different processes on the system so that means that I have to have some form of IPC or inter process communication to talk between the two okay in Android that thing is called binder now we're not going to talk real deeply about what binder is and how it works but I want you to understand the terminology at least so there's this thing called binder that is a system-wide driver that's responsible for all i pc and android so when applications talk to other apps when they talk to services etc etc those are always happening over processed boundaries and so that communication is facilitated by something called binder okay now binder is a very low-level API and the average software developer if they had to talk to the binder driver directly would probably poop themselves right it's not a friendly API it's a lot of low-level I octal system calls it's Linux level programming that's just not fun okay so in Android what they've done is they abstract interacting with the actual binder functionality to using something called proxies and stubs okay these are generated interfaces that simplify and basically buffer the developer from having to deal with the core concerns of IPC into a more friendly API that looks more like function calls on a particular object okay now these two terms are going to come up quite a few more times but the basic idea here is from a single interface definition to the tools and the build tools will generate these two components the proxy lives on the application side and the stub is part of the service okay that is always true all right now in terms of the android framework these two components are generated using something called a idea who's heard of a idea before oh good okay quite a few so a IDL just stands for Android interface definition language it's actually part of the SDK you can use AI to generate interfaces that you can use to create your own services from a remote process but it's also used very heavily in the framework that's how all the system service interfaces are defined for your application okay and then they use that functionality and system server so a IDL is basically a single interface definition that declares a series of functions or methods that one process should be able to call on another and then that abstraction through the tools generates these two Java classes known as a proxy and stub that facilitate that communication between the two okay so that you don't have to go all the way down to your native code into the binder driver which is not fun for anyone okay so to sort of give you a more concrete example of this let's look at say the alarm manager so the alarm manager functionality if we sort of break those pieces out would look something like this the class that your application actually touches is the alarm manager but if we were to go look at the source code for alarm manager and we will in just a minute you'll see that just like in real life managers don't really do a whole lot they just delegate that job to something else okay and so there's not going to be a whole lot of code in here instead you're gonna see it calling into this thing called an eye alarm manager which is a proxy okay and then on the other side of all this IPC magic the alarm manager service is where all of the interesting work of actually setting an alarm triggering a callback when the alarm fires all of that is actually going on you won't find that in alarm manager and in order to facilitate the IPC there's this other class called an alarm manager stub that basically receives these function calls as they go over the process boundary okay so if you were to look at it in terms of a concrete example that's what you would see now this is important if you're trying to trace through AOSP code which again I recommend you try to do as often as you can because let's say we're working with the alarm manager we're trying to set an alarm and the behavior we're seeing doesn't quite make sense I would recommend you go look at the implementation of the set method or the set time method to see what's really going on okay but if you were to just jump into alarmmanager which is the natural entry point for that you wouldn't get very far so let's take a look at why so I'll bring both of these pieces up here so basically what we have here is the alarmmanager source code and if we were to jump into this and look at say the set time method how to set time actually work what we would see is that this method is pretty thin it's really doing nothing other than delegating that same function call to another object in this case this nebulous thing called an eye alarm manager okay now okay so I don't know too much about how the framework is structured but I know how to use search so from alarm manager the next thing that I would go look for is well is there a file called eye alarm manager yes there is but it's useless it's this thing the eye alarm manager is an interface definition it really means nothing to you from a tracing perspective it's just interesting to know that it's there this interface defines all of the methods that applications can call but it has no concrete implementation it this is just input to the a IDL tool that spits out proxy and stuff okay the proxy and stub might be interesting but it's mostly binder code anyway so it's not worth really digging through instead you want to find where those things are used so you've already found in the first part that I alarmmanager is a proxy it was generated from this interface but the two are not the same okay so if I am tracing code and I hit this thing right here the next thing that I should be interested in looking for is the other side of that equation which is the stub so now if I know how to use search instead of hunting for a file called AI alarmmanager I should be looking for a file somewhere else in the source tree that's just has the service there that extends from that I alarmmanager stub so if I can trace from that proxy to find this object then I can actually discover what is the real functionality that's happening when I call that method only manager okay now this may be in a couple different places which is why it's important that you pay attention to where that stub is and not just assume that you'll be able to find a class that has a similar name with service tacked on the end because that's not necessarily true but you will always be able to find a stub in implementation of that matching interface in the corresponding service now sometimes it's embedded in the service like this one is sometimes the service itself actually extends that stub there's not really a clear concrete pattern around doing that but eventually you will find that class and when you call the remote set method on your manager the implementation that's invoked is that set time or a set time zone method right there okay and then inside of the service is where you'll find the interesting work you'll see it actually setting the alarm actually caching the callback to wait for the event enforcing permissions all those things happen service side and that's probably what you were looking for when you wanted to see how the alarm manager behaves okay so understanding these proxies and stubs in the interface in between is a helpful way for you to be able to get from those managers to their particular services so that you can follow that path of execution and understand how a particular service that's giving you problems or maybe that you're just curious about is actually behaving make sense okay all right so there's some interesting features of binder that can affect your application and if you use a IDL directly these might affect you more than you would otherwise but it turns out that because this same mechanism is being used in the framework there are some issues to consider when you're dealing even with system services so one of the nice things from a developer perspective about binder IPC is it allows you from one process to another to pass objects okay so I can pass an object to one of these manager methods and the binder IPC can deconstruct that object send it over the process to the other and then reconstruct it back into something useful okay that's all part of binder IPC but that convenience comes at an interesting cost so because you're able to do that the binder driver in order to protect consistency between the two processes anytime you pass an object forward to another process and in this context we're really saying when an app sends something forward to a service as soon as that object crosses the boundary the binder driver is going to grab a strong reference to that object and it will not let go there is nothing you can do to break that reference it comes from native code it's called a GC root you can't touch it okay what that effectively means is while the services has access to your object over here your process can't garbage collected over here okay that could be a problem and might cause a memory leak depending on what it is you passed forward okay now whenever possible the framework does a pretty good job of making sure that it's not leaking objects that you pass forward and these things are cleaned up in a fairly good way but anytime that you have to pass forward a long-running instance like sale listener callback there's a pretty high potential of this happening to you perhaps not in large scale but definitely in small scale and so I'll give you an example but first let me just finish this walkthrough so in this case how am I able to get rid of this object so it turns out that until the the receiving process or the service finally destroys its instance and what I mean by that is not that the code in there releases its reference it's that the garbage collector in this process finally destroyed the object okay and that's important it'll tell you why a minute once that happens then the binder driver will finally release the reference it has to its own instance so that you can garbage collected over here okay so you're actually relying on a system services garbage collector to run in order for you to be able to clear up any objects on your side that you may have passed forward and I'll tell you system services don't run their GC very often they're quite efficient okay so when would you ever write code that might cause this problem well perhaps more often than you think this is an example which you've probably written before or something similar to it where you might run into this issue so this is just some simple code where I want to use the location manager to get location updates inside of my process and I'm being a good developer and in the foreground of my activity I request those updates and then I think I'm doing good clean up here and on pause by removing those updates so that I don't get them delivered when the activity is not actually visible to the user okay this is all good practice but the instance that I pass as the listener is a reference to the activity okay now this listener is an object that has passed forward to the service and the location manager service is going to hold on to that reference while those updates are active so that they can send callback events to you okay now in theory when you call remove updates it's going to delete that reference from its internal cache that is true but that doesn't automatically mean that the object will be garbage collected and that the binder driver will let you have it back okay so in cases like this another simple example is if you were to pass a sensor event listener to the sensor manager a similar process occurs here where temporarily until the service finally does destroy that object you're actually leaking this entire activity okay and you can see this I I would encourage you to try this out take this exact code throw it into an activity jump into Android studio give yourself a quick heap dump butt and then just take a look at it initially then either pause or even destroy that activity take another heap dump and you'll see the activity is still there and it's there because of an incoming reference known as that they basically call it a native trace from the binder driver coming from the incoming location listener from the other service okay so it's important to note that this might happen to you and if you see something like this causing weird memory leaks you might want to reduce the scope of the object you actually pass forward maybe the activity itself doesn't have to be the thing implementing the listener maybe it can be an object that's separate from that that's not necessarily dependent on or bound to that activity so that if that object lives around for a long time after you lose control of it so well you're not leaking a large amount of memory like you would if you did that on the activity okay so in general if you're passing objects forward to a service that that service is going to hold on to for a while maybe think about limiting that as much as you can so that these types of issues when they do crop up don't come up against you okay all right so just an interesting side note about the way binder IPC actually functions alright so coming back to our architecture discussion for a little bit so we talked a little bit about where does a manager come from where do you typically find the service but how do these things actually find each other so when I call get system service how do I know where to get a reference of that proxy that talks to that particular service like how does all that connection happen inside of the android framework there's another component that sits in between these elements called the service manager Service Manager is effectively androids DNS lookup okay every service that exists in the framework regardless of what process it originated from is registered with this one process called service manager and they register it just using a name just a string value okay so every every service has to be registered with a unique name that's typically defined either by the framework constants or by the service itself and it simply passes that instance off to service manager so that other applications can find it so if we kind of walk through this when system server starts up and system server is a system process so this happens when you boot your device ok so when the device is booted system server starts and it goes through and it creates instances of all the primary services the single instance of the service that's going to live on the device and as part of that process it's going to generate these little stubs and pass them off to service manager which where they'll be converted into something called an eye binder I don't worry too much about that basically an eye binder is just an opaque handle to that service okay so it registers every service with service manager and then service manager now has a large collection of services registered by name okay then when your application starts and the first time you go to ask for the alarm manager for example the alarm manager when it gets created goes and asks service manager for the eye binder that matches the alarm service name so if you ever ever wondered why get system service takes a string as a parameter it's the name of the service which is the same name that's used to register it with service manager just gets passed down okay so service manager then returns that handle back to the client which can convert it then into a proxy so that I alarm manager you saw in there is that proxy converted from what it gets from service manager okay and that proof that I binder object was registered with service manager by the service itself when it was started up and was first created okay in terms of Android applications this part typically happens on boot this part typically happens either when the application launches or when the manager or services access the first time okay okay so you can actually see this for every service running on your device so using the service list shell command over ADB you can dump out the contents of service manager on any device okay and what you're seeing here is effectively a list of names and service handles for every service registered on this particular system okay the names are on the left there and then those long class names on the right are essentially the instances of that particular service okay so all of that information is managed by this one component called service manager and that's where all the apps go to get access to the particular services that one communicate with alright so we go back to this example here for a minute from system service registry because now we have a little bit more information about what's going on under the hood and if I now look at those the implementation of those fetchers so this is the code that's going to be called when I try to access alarm manager or the account manager or any of those other services the first time that's encountered and that service needs to be created the first thing that it's going to do is call this service manager get service API which is just an abstraction that allows the client to pass a name and notice it's the same name that was passed in to service manager and get that token back and then using some magic also known as casting it basically takes that I binder and converts it into the proxy object that the application can then call these particular methods on ok so you can see that pick your service and it's pretty much happening exactly the same way ok and then that service instance or that proxy instance can be passed to the actual manager when it's created and handed back to the application so again this process will only happen once once per context so I may have a manager in my activity I may have a manager in my service and they will be different they will actually point back to the same proxy instance but you'll end up with more than one instance of that manager depending on how many contexts you have ok on the opposite side of things this is a small snippet from system server code so this is the code that actually lives in the system server process in the framework where all of these services are created and added ok so I cut out quite a bit of it just to get to the interesting pieces but basically throughout this code if you just look through system server Java you will see for however many hundred in this case hundred and sixteen services you'll see instances of each one of those services created and then those services registered explicitly with service manager using this at service API again and registered with the same name so that string name that at least for the framework are all names defined on the context API that name is very important because that's how the two processes are able to find the same instance or the same handle to the service so it's registered by name and then on the client side it's accessed by name and that allows them to convert it into those two binder objects that I showed you before the proxy and stub and then that facilitates that communication so that the application can then talk to the service make sense okay all right it was a bit of a whirlwind but if you have any questions I'm happy to take them now well thank you for your time if you do have any other questions you just afraid to ask it in the group feel free to come up and I'd be happy to discuss that with you thanks guys
Info
Channel: Dave Smith
Views: 15,188
Rating: 4.9465241 out of 5
Keywords: Android, Android Internals, System Services
Id: M6extgmQQNw
Channel Id: undefined
Length: 31min 57sec (1917 seconds)
Published: Fri Sep 16 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.