My apps on the Google Play store are affected by the Intent Redirection Vulnerability (see article https://support.google.com/faqs/answer/9267555)
I implemented "Option 2" on the recommended solutions yet the warning is still being reported.
I've tried several different ways of verifying the calling activity, but nothing passes whatever check they're doing.
Here's their recommended solution:
// check if the originating Activity is from trusted package
if (getCallingActivity().getPackageName().equals(“known”)) {
Intent intent = getIntent();
// extract the nested Intent
Intent forward = (Intent) intent.getParcelableExtra(“key”);
// redirect the nested Intent
startActivity(forward);
}
And here's my code:
public void onFinish() {
finish();
// check if the originating Activity is from trusted package
if (getCallingActivity() != null &&
getCallingActivity().getPackageName().equals(
PerfectCommon.getAppContext().getPackageName())) {
Intent intent = null;
// extract the nested Intent
intent =
getIntent().getParcelableExtra(BaseActivity.ORIG_ACTIVITY);
if (intent != null){
// redirect the nested Intent
startActivity(intent);
return;
}
}
Intent newIntent;
SplashActivity context = SplashActivity.this;
boolean portrait = PerfectCommon.portraitMode;
ArrayList<Intent> intents = new ArrayList<>();
// Create intent stack for next activities to run, starting w/ last
newIntent = new Intent(context, portrait ? MainActivity.P.class : MainActivity.class);
newIntent.setData(getIntent().getData());
intents.add(newIntent);
startActivities(intents.toArray(new Intent[intents.size()]));
}
};
The code should check to see if the calling activity is a trusted source, then use the intent; if it isn't then a different intent is used.
However, when I publish the app on the Google Play store it says that the vulnerability still exists in this bit of code.
This is legacy code and has been working fine up to now, so I prefer not to make large change to get past this, rather just need to pass whatever static checker is being used.
I ran into this problem as well, and it seems that the confusion is caused by two separate problems, combined. First, their suggested implementation for Option 2 is incomplete due to that method being nullable. Second, they reject the entire app update, if ANY of the remaining APKs is considered vulnerable.
1.
Google confused us by continuing to reject our app updates, even though we believed we had solved the problem. However, you should pay attention to the versionCode specified in the rejection email -- because they might not be rejecting your latest app version!
In our case, we had an old (vulnerable) app version in production (say, versionCode=100) track, and a first-attempt at fixing the issue in the Beta track (versionCode=150) (see #2 below). When we released a second-attempt at fixing the issue (versionCode=200), Google still sent us the rejection email, but the email still specifically cited versionCode 150, NOT 200.
The reason is because the 150 version was in the beta track, and the 200 version went straight to Production, at 5% rollout (did not replace the Beta version). So technically the 150 version was still accessible in the play store to beta users, and that was the reason for rejecting our 200 update. Once they rejected the update due to the 150 APK being available still, the 200 update was also halted, and we had no choice but to make another updated versionCode.
Once we deactivated the 150 version in the beta track, and re-released the 200 app to production, the rejection went away and we confirmed that the newer version was being distributed to users.
2.
Separately, the reason that the first attempt (150) did not resolve the issue, is because of how we were implementing their Option 2 solution. Their solution (which you linked to above)[1]:
if (getCallingActivity().getPackageName().equals(“known”)) {
but they do not consider the fact that getCallingActivity() is nullable. So in our first attempt, we were using:
if (getCallingActivity() == null || getCallingActivity().getPackageName().equals(BuildConfig.APPLICATION_ID)
and that is still vulnerable, hence why our 150 update was rejected. The accepted solution (versionCode 200 in the above example) flipped that logic:
if (getCallingActivity() != null && getCallingActivity().getPackageName().equals(BuildConfig.APPLICATION_ID))
So once we made that change and replaced the app in the beta track, everything was accepted. You can see all currently accessible app versionCodes in the play console by going to Release Management -> App Releases. Every published version in each track will be listed there.
Related
So I am making an app that has to check for some information, but I need to be able to do that while the app is killed/not actively running. So basically like Youtube's notifications or something. I am a beginner and watched some tutorials on FCM, which can send a notification while the app is killed, which is fine. However, I need to be able to periodically make API calls, check if a certain condition is true and send the notification if so (all of that while app is not running). I tried googling that and found nothing that can help me. So... any ideas? (No code included since I don't think it's relevant.)
If this condition only affects the display of notifications, you can simply check the condition when you receive a notification through FCM. Here's an example :
class FCMService : FirebaseMessagingService()
{
override fun onMessageReceived(message: RemoteMessage)
{
val myCondition = getConditionFromAPI()
if (myCondition) {
showNotification(message)
}
}
}
Use AlarmManager to request periodic runs of your code. It may be set up to broadcast a message time to time to your receiver (declared in AndroidManifest.xml or in your code).
It will work while device is on. To continue after reboot, you have to set up a receiver for Intent.ACTION_BOOT_COMPLETED and register it in your code (not in AndroidManifest.xml, as it no longer works in latest versions of Android).
I am using a foreground service to track the live location of the user. it is working fine in stock android devices, but in brands like oppo, vivo, Mi etc, the app is killed when the device comes into doze mode. I also tried to use FCM notifications still of no use. I am just wondering has Uber or Ola been able to crack this, bcuz i have seen most of the drivers have been using these brands. How are the able to keep their app alive in doze mode?
you need enable auto start permission for apps in oppo , vivo and mi
try below code worked for me
private void keepServicesInChineseDevices() {
Intent intent = new Intent();
String manufacturer = android.os.Build.MANUFACTURER;
switch (manufacturer) {
case "xiaomi":
intent.setComponent(new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
break;
case "oppo":
intent.setComponent(new ComponentName("com.coloros.safecenter",
"com.coloros.safecenter.permission.startup.StartupAppListActivity"));
break;
case "vivo":
intent.setComponent(new ComponentName("com.vivo.permissionmanager",
"com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
break;
}
List<ResolveInfo> arrayList = getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (arrayList.size() > 0) {
AppDataHolder.getSession(MyApplication.getAppContext()).setPermissionForChineseDevices(true);
startActivity(intent);
}
}
this article is also helpful
Thank you so much guys, for your responses. I would like to tell you that I wrote an email to google support and highlighted the issue to google support, in reply they mentioned below reply:
"Thanks for reaching out.
It seems that you can’t receive a push notification on some Android devices. Upon checking the affected device, it is affected by a device specific (known) issue, and it's caused by OEM features for battery optimization. When the app is swiped away, in some of OEMs which has implemented such a feature, the application is treated similar to "force-stopped" mechanism and services registered with the app that's swiped, is stopped.
For now, I strongly recommend contacting the support team of those affected OEMs to help get it resolved from their end.
You can read more about this issue and a possible way of solving it in this blog post(https://www.freecodecamp.org/news/why-your-push-notifications-never-see-the-light-of-day-3fa297520793/).
I've got a very weird problem and is difficult to describe so please read carefully the assumptions before the answer to avoid jumping into something I already know isn't
1 - I've got an android app which login from my server
2 - after a successful login I instantiate a Singleton API which will be shared across the activities in order to make the requests to the server
3 - Isn't possible to use the app without login
4 - in my login activity I have a very clean condition
if(APIFacade.getInstance() != null){
startActivity(new Intent(this,MainActivity.class));
finish();
}else {/*error handling*/}
5 - there is just one call to startActivity method in the whole LoginActivityclass so isn't possible to start MainActivity without check if the facade is null
6 - it isn't possible to set APIFacade.INSTANCE to null after instantiating it
But even with all these conditions sometimes users get NullPointerException on MainActivity when the app tries to make the first call to API after login
String url = APIFacade.getInstance().getProfilePicUrl(); //throws nullpointerexception on 5% of the times
APIFacade class is like this:
public class APIFacade {
private static APIFacade INSTANCE = null;
#WorkerThread
public APIFacade(Object i, final boolean preLoad) {
INSTANCE = this;
//other stuff
}
public static APIFacade getInstance() {
return INSTANCE;
}
}
I'm not able to reproduce the problem in the development environment so I just know it happens due to the crashlytics dashboard on firebase...
I believe my code has no leak to lead this situation, so the only theory I got is: Android is cleaning some variables from memory when my app goes background...
I know android naturally does it for activities, but singletons?
and if yes what can I do to solve it?
Well I found the answer myself thanks to a great article: https://medium.com/#davethomas_9528/please-dont-use-singletons-to-persist-state-on-android-7bac9bc78b29
Briefly:
Everybody says that singleston on android are attached to the application life, so will only be released if the application is killed
THIS IS TRUE
what you dont hear, is that the application can be killed by the SO without user interaction (to release memory for foreground apps) and in this scenario when the user tries to come back to your app it will restart from the last used activity and not from the launcher activity.
I'm making an android app that test if certain security features on your phone are enabled. For example, if you have password log in enabled or if your data is encrypted on your phone.
For some reason, the app has to be ran twice to test and see if these security features are enabled on the phone or not, and this is the problem I'm trying to solve. I'd like it to test and see if the security features are enabled when the app is created and the first time the app is run, not the second time it is run.
I test if these features are enabled in the onStart() function in my MainActivity file. I included the functions code below:
#Override
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
#SuppressLint("NewApi")
public void onStart()
{
super.onStart();
//determine if phone uses lock pattern
//It returns 1 if pattern lock enabled and 0 if pin/password password enabled
ContentResolver cr = getBaseContext().getContentResolver();
lockPatternEnable = Settings.Secure.getInt(cr, Settings.Secure.LOCK_PATTERN_ENABLED, 0);//Settings.System
//returns 1 if pin/password protected. 0 if not
KeyguardManager keyguardManager = (KeyguardManager) getBaseContext().getSystemService(Context.KEYGUARD_SERVICE);
if( keyguardManager.isKeyguardSecure())
{
//it is pin or password protected
pinPasswordEnable=1;
}
else
{
//it is not pin or password protected
pinPasswordEnable=0;
}//http://stackoverflow.com/questions/6588969/device-password-in-android-is-existing-or-not/18716253#18716253
//determine if adb is enabled. works
adb=Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0);
//determine if bluetooth is enabled.works
bluetooth=Settings.Global.getInt(cr, Settings.Global.BLUETOOTH_ON, 0);
//Settings.System BLUETOOTH_DISCOVERABILITY
//determine if wifi is enabled. works
WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
if (wifi.isWifiEnabled())
{
//wifi is enabled
wifiInt=1;
}
else
wifiInt=0;
//determine if data is encrypted
getDeviceEncryptionencryption();
//determine if gps enabled
}//end of onStart() function
If any more code needs to be posted to answer this question, just let me know, and thanks for your help. Maybe the issue has something to do with the super.onStart();
Does anyone think that a splash loading screen might help solve the issue?
super.onStart(); is fine. Splash screen will not help.
From your code I do not see how you determine how many times it ran.
You also mention testing - is it manual testing or you use any framework? Maybe your framework has some init method which runs before each run and it makes this extra call for onStart().
Issues is not in this code. Use debugger or logcat and figure out who calls you twice and, as #nasch had asked, what happens at first run.
Still, real question to help you remains - what do you mean "call twice". Is it you manually clicking app icon twice or is it some testing framework calls your app twice. Both cases are clear to solve.
I have an application that allows the user to send a picture. This picture can be sent via a number of different ways, like g-mail, facebook, flickr, and the one I am interested in, text messaging. When the following code is run, a dialog box pops up with a number of these options available.
Uri uri = Uri.fromFile(new File(externalDirectory + FILE_DIRECTORY + fileName));
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType("image/png");
startActivity(intent);
On my Droid X, the text messaging option is shown, and this code adds the picture to the MMS perfectly.
On the emulator, text messaging is chosen automatically (since there are no other options) and once again it works great.
On my Droid Incredible, there is no text messaging option. However, I can manually bring up the built-in text messaging utility, add the picture and then send it. I also downloaded an SMS/MMS app from the market, and afterward the option to use this 3rd party program to send the picture was available from the list.
So, why isn't text messaging an available option on the Droid Incredible? What do I need to do to make it an option, and how do I evaluate this problem (OR UNKNOWN PROBLEMS) with phone types I have no access to?
So, why isn't text messaging an available option on the Droid Incredible?
Because they chose not to offer it.
What do I need to do to make it an option
In the abstract, you can't.
Quoting the Android Compatibility Definition Document:
The Android upstream project defines a number of core applications, such as a phone dialer, calendar, contacts book, music player, and so on. Device
implementers MAY replace these applications with alternative versions.
However, any such alternative versions MUST honor the same Intent patterns provided by the upstream project. For example, if a device contains an
alternative music player, it must still honor the Intent pattern issued by third-party applications to pick a song.
The catch is, the Messenger app is not considered a "core application" by Google. Hence, device manufacturers are welcome to include their own SMS clients, with their own Intent filters. In the case of the HTC Incredible, apparently they did not include support for MMS via an image/png ACTION_SEND Intent.
Now, IMHO, Messenger probably should be a core application. However, your opinion and mine do not change reality as it stands today.
how do I evaluate this problem (OR UNKNOWN PROBLEMS) with phone types I have no access to
You redefine your application such that it is not a "problem". You have no guarantee that you can send an MMS that way, just as you have no guarantee that a user has a Facebook app installed.
I don't know much about MMS and am uncertain if there is a way other than ACTION_SEND to send an MMS. You might consider poking through the source code to the Messenger app to see how it does it. Then, bake the capability directly into your app. This will require a few extra permissions (SEND_SMS, and probably READ_CONTACTS) and will be annoying to write, but it will be more likely to work across devices.
I did manage to come up with a work around for this, thanks to some help from some other questions on SO.
Basically the key was determining the intent used by HTC, which appears to be the only company (currently) that's modified the android.intent.action.SEND Intent. Here is the code to add the option to the list.
Uri uri = Uri.fromFile(new File(mFile));
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType("image/png");
Intent htcIntent = new Intent("android.intent.action.SEND_MSG");
htcIntent.setType("image/png");
htcIntent.putExtra(Intent.EXTRA_STREAM, uri);
Intent chooser = Intent.createChooser(intent, "Send Method");
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { htcIntent });
startActivity(chooser);