Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Google Play Application Silent Install Feature On Android

Tags:

android

Hi Experts / Expert Hackers,

I'm trying to implement the Google Play application silent install feature (similar to appbrain fast web installer) on android.

So far I was able achieve the following :

  1. Find out a method to retrieve the Google Play Auth Token (thus granting permission for my application to talk with Google Play application on the Phone). I've listed the code I've used for this below :

        Log.i(TAG,"Getting the Google Play Auth Token Using Account Manager : START");
        AccountManager accountManager = AccountManager.get(getApplicationContext());
        Account[] accArr = accountManager.getAccountsByType("com.google");
    
        for (Account acc : accArr) {
            Log.i(TAG, "For Account Name : " + acc.name + " - "+ "Account Type : " + acc.type);
            accountManager.getAuthToken(acc, "googleplay", null, this,new AccountManagerCallback<Bundle>() {
    
                        public void run(
                                AccountManagerFuture<Bundle> paramAccountManagerFuture) {
                            try {
                                Bundle localBundle = (Bundle) paramAccountManagerFuture.getResult();
                                String authToken = localBundle.get("authtoken") + "";
    
                                Log.i(TAG, "Got AuthToken : " + authToken);
    
                            } catch (Exception ex) {
                                StackTraceElement[] starray = ex.getStackTrace();
                                StringBuffer bf = new StringBuffer();
                                bf.append("Error : " + ex.getMessage()).append("\n");
                                for (StackTraceElement ste : starray) {
                                    bf.append(ste.toString()).append("\n");
                                }
                                Log.e(TAG, bf.toString());
                            }
    
                        }
    
                    }, null);
        }
        Log.i(TAG,"Getting the Google Play Auth Token Using Account Manager : END")
    
  2. Find out how to Retrieve the Android-Id of the Phone (This Id as I believe should be used when sending the appInstall request to the GPlay Servers or the Gplay/vending application on the android phone)

      Log.i(TAG, "Getting the Android ID Of the Phone : START");
    
        Uri localUri = Uri.parse("content://com.google.android.gsf.gservices");
        ContentResolver localContentResolver = getContentResolver();
        String[] arrayOfString = new String[1];
        arrayOfString[0] = "android_id";
        Cursor localCursor = localContentResolver.query(localUri, null,null, arrayOfString, null);
        Log.i(TAG, "Column Count : " + localCursor.getColumnCount());
        if ((localCursor != null) && (localCursor.moveToFirst())) {
            String androidId = Long.toHexString(Long.parseLong(localCursor.getString(1)));
            Log.i(TAG, "Received Android ID : " + androidId);
    
            Log.i(TAG,"Other Value in Column : " + localCursor.getString(0));
        }
    
        Log.i(TAG,"Getting the Android ID of the Phone : END");
    
  3. Find out the Protocol Buffer Request to be sent to the Google Play servers or the Gplay/vending application on the phone to Initiate the silent application download & install process.

    message InstallRequest {
    optional string appId = 1;
    }
    message RequestContext {
    required string authSubToken = 1;
    required bool isSecure = 2;
    required int32 version = 3;
    required string androidId = 4;
    optional string deviceAndSdkVersion = 5;
    optional string userLanguage = 6;
    optional string userCountry = 7;
    optional string operatorAlpha = 8;
    optional string simOperatorAlpha = 9;
    optional string operatorNumeric = 10;
    optional string simOperatorNumeric = 11;
    
    }
    message Request {
    optional RequestContext context = 1;
    repeated group RequestGroup = 2 {
    optional InstallRequest installRequest = 10;
    }
    }
    

4.I even used the protobuf compiler and generated the java class for manipulating the above protocol buffer request and filled the above protocol buffer fields with some sample data. See the code below :

    public void buildAndSendSilentInstallProtoBuffMessage(String gplayAuthToken, String deviceAndroidId){

    try{
    /*
     * The Root Request Object Assumed to be Holding the Silent Install Request
     */
    Request.Builder request = Request.newBuilder(); 

    //Populating the ReequestContext Object
    RequestContext.Builder context = RequestContext.newBuilder();

    context.setAndroidId(deviceAndroidId);
    context.setAuthSubToken(gplayAuthToken);

    context.setIsSecure(true);
    context.setVersion(1002);
    context.setDeviceAndSdkVersion("dream:4");
    context.setUserLanguage("en");
    context.setUserCountry("us");
    context.setOperatorAlpha("Android");
    context.setOperatorNumeric("310260");
    context.setSimOperatorNumeric("310260");

    //Building the Install Request
    InstallRequest.Builder installRequest = InstallRequest.newBuilder();
    installRequest.setAppId("-2564446724934482383");

    //Setting the Install Request to the Request Group
    RequestGroup.Builder requestGroup = RequestGroup.newBuilder();
    requestGroup.setInstallRequest(installRequest);

    //Setting the Request Context to the Main Request Object
    request.setContext(context);

    //Setting the Request Group to the Request Object
            request.addRequestGroup(requestGroup);

The Sample Data for GPlay Token and the Android Id are as follows :

  1. Android_ID :

3a0f901831a0f402

  1. Google Play AuthToken :

DQAAAMgAAACpOyPf6apRbb0i4qhTVaf0yYoikTAb4TYlHCRLrW 4mu5f14j-H35KGmO9TQKUDYCfj3-b-QIH5chfXT3bS02Uxljg7vYt4I-kgXLEJwPcynjugDcJ9fYPOh1c2FnOnywFXXxXw6hcqs5sVnJEt 5zW2ditoB5VeeXG9Zfodj9dXKobObi50-XnHoGfWi2b64Uf3EHGdQTsDCMzfZrE4mb22fr9LCW1oZG5tkzw S4KhPBHWMN2fO7w-1IZ4UK5LOI80vPBLjxBaavKAXHoVUHSNV

  1. I also did some sniffing using my rooted galaxy nexus phone during Gplay application silent install and found only two HTTP GET Requests.

I tried reproducing the those two Http GET requests captured using Shark for root(using my rooted android galaxy nexus phone) and the 1st Request just downloads the Market File itself (which I was able to save to the SD card of the Phone. But then it has to be installed like any unknown sources application) while the second request returns nothing.

The two get requests captured are shown below :

  1. GET REQUEST ONE :

    21 0.827240 192.168.135.102 173.194.36.4 HTTP 535 GET /market/download/Download?                                                                     packageName=com.gau.go.launcherex.theme.appwidget.gopowermaster.futureworld&versionCode=1&token=AOTCm0QRnH3rmypWtCGoAL_SU1BSt311wpyz-_LZTodkUSAlc-             f5SrdMiz5WDRDUKMMm6S3plBI9Jbh1tukT1jyCYXLgP4QhVvZvn5JLtZQ&downloadId=-165214892049282883 HTTP/1.1
    
     Which has the following http headers :
    
    Cookie: MarketDA=17214805622679635526\r\n
    Host: android.clients.google.com\r\n
    Connection: Keep-Alive\r\n
    User-Agent: AndroidDownloadManager/4.1.1 (Linux; U; Android 4.1.1; Galaxy Nexus Build/JRO03C)\r\n
    
  2. GET REQUEST TWO :

    44    6.595093    192.168.135.102    222.165.163.15    HTTP    608    GET /market/GetBinary/com.gau.go.launcherex.theme.appwidget.gopowermaster.futureworld/1?expire=1346838270&ipbits=0&ip=0.0.0.0&cp=SnpybWlzSFk6OTYzMzg0MTE2NzA1ODEwOTYxMjE&sparams=expire,ipbits,ip,q:,cp&signature=2C0778C4635F6F8AE1DA8479FB08DCB9BC04C2E9.60202D8D4D2FDDA70609A3862A25852F0BAA2766&key=am2 HTTP/1.1
    
    Which has the following http headers :
    
    Cookie: MarketDA=17214805622679635526\r\n
    Host: o-o.preferred.slt-cmb2.v12.lscache4.c.android.clients.google.com\r\n
    Connection: Keep-Alive\r\n
    User-Agent: AndroidDownloadManager/4.1.1 (Linux; U; Android 4.1.1; Galaxy Nexus  Build/JRO03C)\r\n
    

I've been looking into this for about two weeks now but I still couldn't find the following :

  1. Whether the AppBrain fast Web Installer uses the protocol buffer to invoke the Gplay (vending application) on the phone or the Gplay servers ?. If so is the above Protocol Buffer Request format correct ??.

  2. If the Above Protocol Buffer Request format is correct then to Where in the Phone or Gplay server should I send the Protocol buffer request to to invoke the Silent Application download and installing procedure ?.

I also have a C2DM (now GCM) server and client setup around this task as well. Could anyone point me in the correct direction or give me any clues for solving this ?. Any help is much appreciated .

like image 210
msrameshp Avatar asked Sep 05 '12 12:09

msrameshp


People also ask

What is silent app installation?

Answer: The 'silent installation' of apps means that the user of the device does not receive any prompts to update or install the app. Instead, the app updates or installs itself automatically in the background.

What is play AUto installs in Android?

Google created the functionality called PAI (Play AUto Install) on Android that automatically downloads apks from Play Store after factory reset if connected to network.


2 Answers

Silent install on Google Experience devices is only possible by Google Play. More generally, only stores that come preloaded on your hardware can accomplish this, since they need to use the operating system's signing key.

This is for security reasons. Users need to be able to accept permissions for new installations. The OS has no way to verify whether non-official stores have properly done this.

Third-party applications must use PackageManager to install new apps, which will display permissions on your behalf and require an explicit user approval.

Attempting to circumvent this may fall under the "prohibited actions" clause of the Google Play DDA, which puts your developer account at risk for suspension. Don't do it.

like image 102
Trevor Johns Avatar answered Sep 18 '22 12:09

Trevor Johns


There are several actions that the O.S. will not allow anyone but it's trusted applications to do.

The applications that are signed with platform keys are trusted by the O.S., so those applications can do more things with the phone, like silent installs. I tend to see a platform-signed application more powerful than having root functionality just because it allow you more easy access to intents and android API.

You don't need to sniff the messages that Google Play are sending/receiving from the HTTP Server... You need to sign your application with platform keys. The problem is that each carrier/manufacturer/phone/version could potentially have different platform keys... So, to achieve this you would need to build several versions of your application for each specific device...

Some carriers sign all phones of the same manufacturer with the same keys, but others use different keys for each phone.

You will have to do a big effort and negotiation with carriers to allow this functionality, or rely on ROOT users. Or just release your application signed with test-keys (the ones that come with the android SDK) and it will work with all users that have a custom rom with test-keys.

like image 23
Muy Matón Avatar answered Sep 20 '22 12:09

Muy Matón