Using adb to broadcast intent with extras - android

background
i wish to send a broadcast intent (even with root permission) that an app was removed, and for this, i have to broadcast an intent with extras.
problem
i just can't figure out what am i missing, since i can't find the correct way to do it.
what i've done so far
i think I've found where on android the OS broadcasts the intent (the file is called "PackageManagerService.java" ). I've also found out how to get the correct permission using root (and it works) , and also how to put extra data into the intent of the broadcast (link here) , all using the "adb" tool.
now i have to put all of the pieces together.
the code so far is :
String packageOfCurrentApp=..., packageOfAppToReportAbout=... ;
try
{
final java.lang.Process p=
Runtime.getRuntime().exec(
String.format("su -c pm grant %s android.permission.BROADCAST_PACKAGE_REMOVED",packageOfCurrentApp));
final int res=p.waitFor();
Logger.log(LogLevel.DEBUG,"got permission:"+(res==0));
if(res==0)
{
final java.lang.Process p2=Runtime.getRuntime().exec(//
"am broadcast -a android.intent.action.PACKAGE_REMOVED "+//
"--ei android.intent.extra.UID -1 "+//
"-eez android.intent.extra.DATA_REMOVED true"+//
" -d com.syncme.syncmeapp ");
final int res2=p2.waitFor();
Logger.log(LogLevel.DEBUG,"broadcast?"+(res2==0));
}
}
catch(final Exception e)
{
Logger.log(LogLevel.DEBUG,"error:"+e);
}
the permission getting works, but the broadcasting doesn't.
question
what is wrong with the code? what is missing? how can i fix it?
i would also like to know how to do the same via the shell (of the PC).

Like for battery :-
we use below
m broadcast "intent:#Intent;action=android.intent.action.BATTERY_CHANGED;i.status=5;i.voltage=4155;i.level=100;end"

Please refer to the source code of PackageManagerService.java
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
extras, null, null);

Related

Android Pie (9.0) - Writing a Shutdown or Restart Function - Application is Privileged

I have a security system in schools, where my tablets are the consoles for each classroom. I've noticed teachers and admin are not restarting the tablets very often (or ever), which has caused issues. I would like to take the task from the clients and program a weekly reboot or shutdown. I have taken a few steps in the right direction:
I have:
Spoken with the Tablet Provider/Scheme Provider, and they have added my app as a privileged app.
Added a whitelist for (what I think are) all required permissions.
Confirmed the privileges exist.
Code to Check Permissions:
public void getGrantedPermissions(final String appPackage) {
List<String> granted = new ArrayList<String>();
try {
PackageInfo pi = getPackageManager().getPackageInfo(appPackage, PackageManager.GET_PERMISSIONS);
for (int i = 0; i < pi.requestedPermissions.length; i++) {
if ((pi.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
granted.add(pi.requestedPermissions[i]);
}
}
} catch (Exception e) {}
for(int i = 0; i < granted.size(); i++){
Log.e("Permissions", granted.get(i));
}
}
Below is what the log reported. The green permissions are all that I could get on my personal phone. The yellow permissions are what I was able to get, additionally, from the Tablet provider's whitelist. We can confirm by these permissions that I have a privileged app, as well as the shutdown and reboot permissions.
I was able to find a section of code to shutdown the app, but it seems that I can't quite figure out how to use it. Below is the code I have tried, and the error follows:
Intent intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
intent.putExtra("android.intent.extra.KEY_CONFIRM", false);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Error upon running code:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.ACTION_REQUEST_SHUTDOWN flg=0x10000000 (has extras) }
"This exception is thrown when a call to Context#startActivity or one of its variants fails because an Activity can not be found to execute the given Intent."
I am assuming that this may require me to modify my manifist.xml, is that correct? If so, I'm unsure how to do so. I feel that I may have to add an to my main activity, where the call is made. Though, I've tried this and it didn't work, or I wrote the code improperly.
Thank you in advance for any assistance!
Figured this one out. I didn't realize a PowerManager existed, but it does, and it works. My solution below. Also, if you didn't read the full question, my app is a privileged/System app, which gives me the authority to manage power. Normal apps will not be able to do this.
Currently running Android 9.0 (might matter, not sure)
try{
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
powerManager.reboot(null);
} catch (Exception e){
Toast.makeText(this, "Error performing this action", Toast.LENGTH_LONG).show();
e.printStackTrace();
}

Turn off device programmatically

I am writing an App that is designed to run on one specific device model (an Android set-top device that runs Amlogic based firmware). I have both root capability and my App is signed with the firmware certificate.
My App is the main focus of the device, and it would be helpful to be able to initiate a complete power-off.
I do not have the shutdown command. I do have the reboot command.
reboot -p does not help. It simply freezes the device while remaining powered on.
The PowerManager is one step better, but it sets the device into sleep mode, instead of a complete shutdown:
PowerManager pm = (PowerManager)getSystemService(Service.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
I am open to all suggestions - hacky or otherwise. The version of Android is expected to remain at 4.2.2.
Intents
This command will cause the device to reboot. Intent.ACTION_SHUTDOWN does not appear to do anything. Is this Intent perhaps only to report a shutdown, and not to initiate one?
Intent i = new Intent(Intent.ACTION_REBOOT);
i.putExtra("nowait", 1);
i.putExtra("interval", 1);
i.putExtra("window", 0);
sendBroadcast(i);
The most luck I had with this was to request a shutdown by Intent:
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);
Shutdown Thread
That is a bit closer. Definitely interesting. Can you find an example of using it?
So far I have come up with this:
Class<?> sdClass = Class.forName("com.android.server.power.ShutdownThread");
Constructor<?> con = sdClass.getDeclaredConstructors()[0];
con.setAccessible(true);
for (Method m : sdClass.getDeclaredMethods()) {
if (m.getName().matches("shutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("rebootOrShutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("beginShutdownSequence")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
}
}
shutdown and beginShutdownSequence create NullPointerExceptions (do you see why?) and rebootOrShutdown creates an InvocationTargetException due to an UnsatisfiedLinkError... It cannot find a native method:
java.lang.UnsatisfiedLinkError: Native method not found:
com.android.server.power.PowerManagerService.nativeShutdown:()V at
com.android.server.power.PowerManagerService.nativeShutdown(Native
Method) at
com.android.server.power.PowerManagerService.lowLevelShutdown(PowerManagerService.java:2163)
at
com.android.server.power.ShutdownThread.rebootOrShutdown(ShutdownThread.java:543)
at
com.android.server.power.ShutdownThread.run(ShutdownThread.java:393)
lowLevelShutdown is the function that all the functions eventually reach, when configured to shutdown (and not reboot). So figuring out how to avoid this link error may be key.
In my case, I do not think it is possible to shut the device down how I would like to.
The closest that I managed to get to my target was using:
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);
That brings up a dialog to turn the device off. This is the perfect solution, but in my case, using it causes the device to crash. It may be that my device is somewhat special, and other devices will not have these restrictions.
In any case, I hope that my testing will help others in their quest.
It work for me on rooted device.
If your device is rooted then you can use below approach
Shutdown:
try {
Process proc = Runtime.getRuntime()
.exec(new String[]{ "su", "-c", "reboot -p" });
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
Restart:
Same code, just use "reboot" instead of "reboot -p".
Runtime.getRuntime().exec(new String[]{ "su", "-c", "reboot -p" });
it works, just with rooted devices!!
To use this code, you need Super User! Works on 4.0 and above!
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", false);
i.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
and put this permission on manifest:
<uses-permission android:name="android.permission.SHUTDOWN" />
An update: for newer Android version, in my case is Android 8.1, they changed the action name. See below:
Intent i = new Intent("com.android.internal.intent.action.REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", false);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Good luck!
In newer android versions you aren't allowed to shut down the device from the nonSystem app.

Android - not all logs appear in a logcat output

I am using windows cmd terminal to output logs of my application using following command:
adb.exe logcat | find "%part_of_my_apps_name%"
however, not all logs appear in the output. Only messages like this one:
I/AppService(10597): Received start id 1: Intent { cmp=package_name/.AppService(has extras) }
And in my AppService I have the following code:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Received start id " + startId + ": " + intent);
Log.i(TAG, "Test");
So what am I doing wrong?
UPD: I asked a bit wrong question. I actually used part of my app's name, not package, so it MUST appear in the log output.
Depending on what your TAG variable is, you use the command
adb.exe logcat -s "[tagname]"
For example if in my code, my TAG was declared as:
public static final String TAG = "com.myapp";
my LogCat would be
adb.exe logcat -s "com.myapp"
It also appears the quotes are optional.
Logcat output is not associated with the package name, but with the string TAG you are using in your code. You could change all your tags to be your package name, or you could explicitly add your package name to the message in each Log.i/w/e/v() line, and then you will get the behavior you want. However, I would actually for with #A--C suggestion instead, as it allows you to have more granular filtering of the output of specific classes only.
I used a part of app's name, however, because "find" is basically case sensitive it did show me only that particular output ( name appeared in package name ) , so I came up with the following command:
adb.exe logcat -v time | find "%part_of_my_apps_name%" /I

Unauthorized Caller Error

I am stuck writing some code that uses reflection that calls IConnectivityManager.startLegacyVpn
The error I get is java.lang.SecurityException: Unauthorized Caller
Looking through the android source I see this is the code hanging me up:
if (Binder.getCallingUid() != Process.SYSTEM_UID) { raise the above exception }
My question is if I root my AVD and install my app in system/app will this be sufficient to get around this error?
If so, any tips on how to do this (every time I try to move my apk to the system/app folder it says the app is not installed when I click on the app icon.
Thanks!
I have the same problem, following android 4.01 open source, i see somethings like this:
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Only system user can call this method.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
}
Or,
// Only system user can revoke a package.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
Or,
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
if (Binder.getCallingUid() != app.uid) {
throw new SecurityException("Unauthorized Caller");
}
jniProtect(socket.getFd(), interfaze);
}
However, these block of code above is belongs to com.android.server.connectivity.Vpn
(class Vpn), which is not defined in interface IConnectivityManager.
I also find in startLegacyVpnInfo() function but i can't see anything involve exception
"Unauthorized Caller", so i wonder why startLegacyVpnInfo() function throws this exception?
Any solutions for this?
I am trying to make the same calls. So far I can confirm that rooting the device and copying the apk to /system/app does not work, it does not start under the system uid.
Also, this does not work:
Field uidField = Process.class.getDeclaredField("SYSTEM_UID");
uidField.setAccessible(true);
uidField.set(null, Process.myUid());
Those calls succeed, but they don't seem to affect the SYSTEM_UID field, the field is probably optimized out at compile time.
If you include android: sharedUserId="android.uid.system" into your manifest tag (not just the manifest), this should then run the application as system. This should now let you run the code.
As for pushing to /system/app, you need to run adb root followed by adb remount. This will now let you push to /system/app.

Programmatically starting the 'Add Account' activity in Android 2.2

I've been experimenting with the Android SDK over the past few days, in readiness to write an App for the store, however I've run across a bit of a problem.
The App I'll be writing requires that the user has a Google account associated with the phone. Retrieving and making use of the Auth token etc was not a problem, however I would like to be able to show the activity that a user would normal reach by going through the menus Settings->Accounts->Add Account.
Now through experimentation I've been able to launch this activity from the shell using the following command.
am start -n com.google.android.gsf/.login.AccountIntroActivity
I'm having trouble performing the same action in JAVA using the Intent class.
Would anyone be able to tell me firstly whether or not this can be done via JAVA, and secondly how I could go about it please?
If I have to settle for the Sync Settings screen then I will (this can be achieved through the Settings.ACTION_SYNC_SETTINGS intent), however it'd be quite nice to be able to direct the user straight to the required screen.
Check out the ACTION_ADD_ACCOUNT
startActivity(new Intent(Settings.ACTION_ADD_ACCOUNT));
Try the following:
public static void addGoogleAccount(final Activity activity) {
final AccountManager accountMgr = AccountManager.get(activity);
accountMgr.addAccount("com.google", "my_auth_token", null, null, activity, null, null);
}
Android Account Manager provides an API to add account. (google or other account types)
public AccountManagerFuture addAccount (String accountType, String authTokenType, String[] requiredFeatures, Bundle addAccountOptions, Activity activity, AccountManagerCallback callback, Handler handler)
http://developer.android.com/reference/android/accounts/AccountManager.html
the answer for the above question by providing EXTRA_ACCOUNT_TYPES in the intent extra data. and set the value to "com.google" in order to alert the activity:
public static void startAddGoogleAccountIntent(Context context){
Intent addAccountIntent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
addAccountIntent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, new String[] {"com.google"});
context.startActivity(addAccountIntent); }
For recent Androids using adb you can do:
adb shell am start -a android.settings.ADD_ACCOUNT_SETTINGS \
-n com.android.settings/.accounts.AddAccountSettings
(You’ll still have to select what account type you’d like though)
The clue is in your shell command:
Intent intent = new Intent();
intent.setClassName( "com.google.android.gsf", "com.google.android.gsf.login.AccountIntroActivity" );
context.startActivity( intent );

Categories

Resources