Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: I changed sharedUserId on an already-released app and some of my users can't update. What should I do now?

Tags:

android

My annotator generator was used to make Android Web browser apps that add pronunciation aids to Chinese text. Different kinds of pronunciation aid are available depending on which region's pronunciation you want (e.g. Mandarin Pinyin, Cantonese Sidney Lau, Wenzhou…) and to conserve storage space on old Android phones we released each aid as a separate app as the majority of users will not need more than one. But at the start of March 2018 by popular request I added a Bookmarks function, and stupidly put an android:sharedUserId attribute in my AndroidManifest.xml's <manifest tag to allow the different versions of the app to share their bookmarks for those few 'power users' who do switch between different types of pronunciation aid.

But we already had about 5,000 users, and some (but not all) users started reporting they were now unable to update the app. Of course Android did its usual thing and just told them there was a problem without giving any technical information that might have given me a clue what I'd done wrong, so I just replied to the reports saying to try uninstall and reinstall or clear the data of the Play Store app, and it was 5 weeks before I finally met someone in person whose old Samsung Galaxy S2 (Android 4.1) wasn't updating and I was able to connect it to my dev box and watch the adb logs and saw this:

04-04 21:54:58.653: W/PackageManager(2127): Package org.ucam.ssb22.pinyinwol shared user changed from <nothing> to org.ucam.ssb22.annogen; replacing with new
04-04 21:54:58.708: I/BootTime(2127): Fail Safe scanning for:/mnt/asec/org.ucam.ssb22.pinyinwol-1/pkg.apk
04-04 21:54:58.708: W/PackageManager(2127): Package couldn't be installed in /mnt/asec/org.ucam.ssb22.pinyinwol-2/pkg.apk

Further searching showed the general consensus is you should never add a sharedUserId attribute to an app that has already been released without one, or users will get INSTALL_FAILED_UID_CHANGED (although that string wasn't in these particular logs; I think it depends on Android version).

But I can't just remove the sharedUserId now, because some new users have installed the app afresh in the last 5 weeks and presumably some of them are also on versions of Android that can't cope with changing sharedUserId during an update.

I'd be happy to tell Play Store "if any user's device can't cope with updating this app, please uninstall the old version and give them a fresh install". (Or even "please make this update a fresh install unconditionally".) But there doesn't seem to be any way to say that in AndroidManifest or on the Play Store console. I've found solutions that involve code in the app itself, but my problem is my app won't install at all until the data is wiped, and I have no way to tell users to wipe the data other than by posting advice anywhere I can and hope they see it—most probably won't.

The only solution I can think of is to push out updates both with sharedUserId and without sharedUserId alternately, waiting a while between each, in the hope that the affected devices would at least install one of the two updates. That would of course sacrifice the shared-bookmark function (unless I first reimplement it using some mechanism other than sharedUserId) and it's not a very elegant solution. So I'm posting this question in the hope that somebody can suggest what I should do after having got myself into this mess.

like image 397
Silas S. Brown Avatar asked Oct 29 '22 15:10

Silas S. Brown


1 Answers

I tried the following workaround:

  1. Release a version with sharedUserId on a Monday, with extra startup code that checks the date and (a) if it's within 7 days of the release, it says next week's update might be a problem but don't worry and wait for the following week's, (b) if it's within 14 days of the release, it says this week's update might be a problem but don't worry and wait for next week's.

  2. The following Monday, release a version without sharedUserId, set to work for a couple of weeks and then stop working entirely, telling the user they must uninstall and reinstall the app.

  3. The Monday after that, release a version with sharedUserId that's back to normal.

My plan was that this would result in (a) users whose devices don't care about sharedUserId will auto upgrade through all 3 versions and not notice anything except version 1's messages (spurious in their case), (b) users whose devices are stuck on the pre-sharedUserId version will get version 2, and will subsequently be told to uninstall and reinstall once version 3 is current, (c) users whose devices are stuck on post-sharedUserId will get versions 1 and 3, and will notice only a "failed to update" message during version 2's week, which they were warned about by version 1.

What actually happened, according to Play Store statistics, was:

  • Toward the end of Week 1, over 55% of my active users were stuck on the last version I had released before setting sharedUserId, plus a good 20% on earlier versions (so over 75% were "left behind"). About 15% of my active users had downloaded the version that warns about the potential failure of Week 2's update.
  • Toward the end of Week 2, the number stuck on "last version before my sharedUserId mess-up" had dropped from 55% to 16% of my active users. About 45% of my active users had upgraded to the non-sharedUserId Week 2 version (the one that was set to tell them to reinstall if Week 3's version failed to automatically replace it), and another 12% were still on the Week 1 version and being told not to worry. And I had about 19% stuck on earlier versions (down from 20%). I began to suspect that 19% had mostly disabled their updates.
  • Half way through Week 3, 1 day after the Week 2 version starts telling users to reinstall, I had 44% on Week 2's version (and being told they have to reinstall to update, so at least now they know), 16% on Week 3, 13% on "last version before mess-up" and still the tail of older versions.

So it's not a perfect answer, but in my case it at least helped me inform over three-quarters of my affected users that they now need to reinstall, which is better than none of them knowing.

like image 79
Silas S. Brown Avatar answered Nov 15 '22 07:11

Silas S. Brown