Want to know startForeground() as user for multiuser - android

I am working on android multi-user. So I have to convert my existing project in to multi user supporting project.
My app will be running in owner. If I switch to user, any related UI actions should be shown on owner or user,
I am using Context.startActivityAsUser(intent, UserHandle.Current);
so the activity will be launched on corresponding user or owner.
the same way to launching broadcast events.
In my app, I am using notification as part of service as below
startForeground (int id, Notification notification);
as the service is running is owner, the notification is showing on owner only even though I switched to user.
When end user switched to other profile, the notification should be shown on current profile.
as per my knowledge, there is no startForeground(...) as user (i mean as startForegroundAsUser()) so I have converted notification stuff to
NotificationManager.notifyAsUser(null, appID, notification, UserHandle.CURRENT);
....
When I switch from owner to user, my app is getting crashed and logs also not clear for find the issue. Logcat just says as
I/ActivityManager(421): Process com.example.test (pid 5833) has died
W/ActivityManager(421): Scheduling restart of crashed service com.example.test/com.example.test.testservice in 1000ms
.....
.....
.....
but the service is not started as top profile is CURRENT.
Let me know the other approach to achieve this.

The short answer is you cannot do this. Each app package is installed on the device with a separate data area and process for each human user. They are purposely kept isolated in memory and filesystem space via Linux UID/GID and permissions. In Android 5.0 this is further enforced using SE Linux for Android. So when you are switching (human) users, your apps are being started as separate instances for that person.

Related

Avoid Screen Overlay Detected for service that uses SYSTEM_ALERT_WINDOW

My app main usage is overlay, the overlay is running from a service.
Android Security add the nice "Screen Overlay Detected"
I want to avoid "Screen Overlay Detected" when user tries to change permissions. so... I've add an AccessiblityService that detects:
if ( event.getPackageName().equals("com.google.android.packageinstaller") ){
stopService(myServiceIntent);
}
However, even now I see this message popping. (when my service is stopped...).
I saw Twilight does it without problem.
What am I missing?
p.s. - I've also tried building a signed apk but saw exact same behavior.
It seems I've been able to resolve this.
a) stopService isn't assured your service will be stopped.
as described here :
It will not be destroyed until all of these bindings are removed. See > the Service documentation for more details on a service's lifecycle.
b) I was able to kill my service by sending intent that called stopSelf().
However process killing/starting can be slow.
c) Best resolution: so it seems Android checks for view visibility. no need to kill services or do anything more complicated.
Current way I'm doing it:
- AccessibilityService (already used by my app) monitor "com.google.android.packageinstaller" though it can be refined to class: "com.android.packageinstaller.permission.ui.ManagePermissionsActivity"
Once detected in this class, we send Intent to "duck", and when we're out, we send another intent that we're back on.
The service handles those calls by:
[ourView].setVisibility(View.INVISIBLE); // when permission settings shown
[ourView].setVisibility(View.VISIBLE); // when normal flow
As long as Android 6.x is buggy on some devices where this "overlay alert" is displayed without any reason (on 2 to 5% of the devices according to my analytics data), the best solution is to avoid the whole permission process by defining the targetSdk to 22. Take care that you can't downgrade the target sdk for a new version or this will induce a INSTALL_FAILED_PERMISSION_DOWNGRADE error when the user updates requiring an unisntall/install of the app.

How can I intercept the Intent when the user open another application?

Let's say the user open "Settings" application, is there a way to "intercept" this intent, from my app's service, in order to detect that "Settings" app is going to be openned?
For instance, in SOTI MobiControl app you can manage (from a web dashboard) the permissions of the user with the app installed (and enrolled to your server). If you don't allow one user to open Settings app, when he tries to open it, a toast appears saying "Unauthorized". How do they that?
Doing so is against Google Play Developer Program Policy, as it states in its System Interference section:
An app downloaded from Google Play (or its components or derivative
elements) must not make changes to the user’s device outside of the
app without the user’s knowledge and consent.
This includes behavior such as replacing or reordering the default
presentation of apps, widgets, or the settings on the device. If an
app makes such changes with the user’s knowledge and consent, it must
be clear to the user which app has made the change and the user must
be able to reverse the change easily, or by uninstalling the app
altogether.
Apps and their ads must not modify or add browser settings or
bookmarks, add homescreen shortcuts, or icons on the user’s device as
a service to third parties or for advertising purposes.
Apps and their ads must not display advertisements through system
level notifications on the user’s device, unless the notifications
derive from an integral feature provided by the installed app (e.g.,
an airline app that notifies users of special deals, or a game that
notifies users of in-game promotions).
Apps must not encourage, incentivize, or mislead users into removing
or disabling third-party apps except as part of a security service
provided by the app.
https://play.google.com/intl/ALL_us/about/developer-content-policy.html
Is there a way to "intercept" this intent, from my app's service, in
order to detect that "Settings" app is going to be opened?
As other mentioned before it's not possible to intercept a launch intent.
For instance, in SOTI MobiControl app you can manage (from a web
dashboard) the permissions of the user with the app installed (and
enrolled to your server). If you don't allow one user to open Settings
app, when he tries to open it, a toast appears saying "Unauthorized".
How do they that?
It's however possible to determine if an app is opened and "intercept" that call. By intercept I mean draw over the starting app's screen and present a login screen or a not authorized screen.
I haven't worked out a full sample that would work an any Android version but from my research with AppLocks, I'd say it works more or less like this:
On pre-Lollipop Android you'd use this to retrieve the running processes:
ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo info : manager.getRunningAppProcesses()) {
Log.e("TAG", "Running process: " + info.processName);
if ("com.mycompany.mycoolapp".equals(info.processName)) {
// do stuff...
}
}
requires:
<uses-permission android:name="android.permission.GET_TASKS"/>
or alternatively:
for (ActivityManager.RunningTaskInfo recentTaskInfo : manager.getRunningTasks(100)) {
Log.e("TAG", "Recent tasks: " + recentTaskInfo.baseActivity.getPackageName());
}
On Lollipop and higher you'd use UsageStats to determine if an app is running:
UsageStatsManager usageStatsManager = (UsageStatsManager)getSystemService(USAGE_STATS_SERVICE);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -1);
long start = cal.getTimeInMillis();
long end = System.currentTimeMillis();
List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, start, end);
for (UsageStats stats : queryUsageStats) {
Log.e("TAG", "Usage stats for: " + stats.getPackageName());
}
requires:
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
I would probably run both using the AlarmManager to perform that recurring task.
I'm fairly certain these are the two ways to get the list of running apps. If the permission for usage stats is denied to AppLock it's not working any more an Android 6.0 devices. On pre-M devices it however still works which is an indicator that the app has an alternative way to get the list of running apps (the first option described above).
Once it's determined an app has been started (it's running and hasn't been running the last time we checked), we can "take over" the screen. And that's how I'd do it: http://www.piwai.info/chatheads-basics/
Of course that's just the basic idea and I'm sure there are a couple of pitfalls when implementing a reliable solution but this should give you something to start with.
Let's say the user open "Settings" application, is there a way to "intercept" this intent, from my app's service, in order to detect that "Settings" app is going to be openned?
No, unless you are the one that is calling startActivity() to launch the application in the first place.

Why do we need a UserHandle in many API declarations

In Android Open Source Project, a lot of core API declarations have an integer parameter userId in the end. I traced back and figured out the integer comes from a class called "UserHandle.java". There is a simple comments saying this class represents a user on the device. It still confuses me. Why do we need such a class? What's the difference between different values of the class, such as "USER_OWNER", "USER_CURRENT", "USER_CURRENT_OR_SELF"?
Thanks in advance!!!
Ever since Jelly Bean, Android platform has supported multiple users. This means that multiple users may be able to use one device, yet not be able to access other user's files or communicate with another user's app.
The first user on the device is user 0. The rest start their numbering from 10,11,... (In JB the numbering was 1,2...).
USER_OWNER is user 0.
He has some extra privileges over the other users (mostly access certain settings that others can't or uninstall an app for all users).
Multiple users on one device requires that only one user can be active in a specific point in time, this user is referred to as USER_CURRENT (since Kitkat().
In general one user's application can't send a broadcast message or an Intent to other user's apps.
Only apps with system permissions can do that (for example when the battery is running low, an intent will be sent to all).
Whenever you send an Intent from your app, the system service verifies whether this is a valid Intent i.e. if its supposed to reach all users then it's not.
This means that even if you were to use a certain api with the wrong userId (for example you force userId=0 even though this is user 10), then your call will receive a SecurityException.
To avoid such exceptions, there is also the option to send an Intent with USER_CURRENT_OR_SELF.
This means you're trying to send to the current user, but if he's not allowed to receive the Intent, let the same user who sent the Intent receive it.

Android : can native code get broadcast intent from android system? [duplicate]

This question already has answers here:
Listen to own application uninstall event on Android
(3 answers)
Closed 7 years ago.
Recently i've seen a funny app - Photo Wonder.
When this app is uninstalled, it shows a web survey page asking for the reason of app uninstall. Now, here is the problem.
As far as I know, after an app has been removed, the system broadcasts ACTION_PAKAGE_REMOVED intent.
But this funny app was able to show my the web page although the official doc says
"The package that is being installed does not receive this Intent."
Anyhow, I could find a process checking some kind of status of the app.
Now here is the question. Can the native app catch the broadcasted intent from android system?
If it is possible, please let me know how! :-(
I believe I've got the main idea of how they did it. Here is the pieces of the puzzle.
Any Android application can start a process by calling Runtime.exec() function.
Runtime.getRuntime().exec("chmod 755 '/data/data/my.app/files'/native_code");
After this line of code gets executed there is another process spawned. This process runs under the same linux user as the application itself.
When a user opens Settings -> Apps -> My App and presses "Force stop" button, main application process gets killed, but the process hosting native program (see above) still runs. I personally believe this is a security issue and I am going to report it back to AOSP.
Such native program can run infinitely and do nothing - just sleeping. But before going to sleep, it registers a termination signal handler which will be called when process is about to be terminated by the system.
int main(void) {
signal(SIGTERM, termination_handler);
while(1) {
sleep(10);
}
}
void termination_handler(int sig) {
// handle termination signal here
}
Now you should already know what the last piece is, right? My native termination_handler should be able to launch a browser. I didn't try this in code, but I assume this is possible, because I can do it using adb shell as following
adb shell am start -a android.intent.action.VIEW -d http://www.google.com
Now back to the question about how Dolphin Browser does it. Install the app and launch it at least once. Once started, it registers a native uninstall watcher using the principles described above. To see it, connect to the device and open adb shell. Then call ps to see list of processes. You will see two processes similar to following
u0_a109 315 ... mobi.mgeek.TunnyBrowser
u0_a109 371 ... /data/data/mobi.mgeek.TunnyBrowser/files/watch_server
As you can see it starts a watch_server native program, which is a part of its apk-file. Now open App info page of Dolphin Browser and press "Force Stop". Switch back to terminal and call ps again. You will see there is no mobi.mgeek.TunnyBrowser process anymore, but watch_server still runs.
By the way this approach will only work, if watcher server runs all the time. To
make sure it is always up, both apps require "run at startup"
permission, where they start their watchers.
Now, when you uninstall the app, Android stops all processes belonging to this application. Watcher receives termination signal and opens browser with predefined URL and then shuts down.
I might look a bit different in some details, but the main concept behind this hack must be as described.
There could be a tricky thing like that application is also having watcher service.
You can check the permission used by that app may contain INSTALL and UNINSTALL permissions.
HOW IT WORKS:
instead of single app that may have 2 app bundle.
as and when you install it, this app is also installing some service that is watching your app status
When you try to uninstall that app the system broadcast is called which is handled by that service and will check that if your package is exist in installed application or not.
as soon as this service finds that your package is not in the list it calls an intent with action view with the web url to open the brawser.

Samsung Chord as a Backgorund Process

I am going to enter the Samsung 2013 app contest, and one of the requirements is that you use their Chord API http://developer.samsung.com/chord.
I plan on allowing users to send messages to all phones that have my app installed. From what I gathered from the information in the previous link, this means that I will need to have a constantly running background process for users to receive the messages when they are not looking at the app at the time.
I want to know if this is true, and if so, is this viable? I am considering using the method detailed here: Android: keeping a background service alive (preventing process death) if I go ahead with this.
I'm trying to use Samsung Chord too. I thing you don't need to do this. Samsung's API Chord already provides this control.
According Chord's API:
"If a Chord node doesn’t receive a UDP signal within a specified amount of time, it considers the “missing”
node to no longer be part of the network."
And, the only thing you have to do is:
"A node cannot receive a UDP broadcast if it is in LCD-off status. Therefore, if developers want the node to discover other nodes while the application is running, the node’s status should be set to LCD-on. To do this, use Android’s PowerManager.WakeLock."
Best regards,
Adriano

Categories

Resources