am 40e665a0: cleanup
Merge commit '40e665a015c67a8dd21838894a1634a3e101b760' into eclair-plus-aosp * commit '40e665a015c67a8dd21838894a1634a3e101b760': cleanup
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
oneway interface ILicenseResultListener {
|
||||
void verifyLicense(int responseCode, String signedData, String signature);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
import com.android.vending.licensing.ILicenseResultListener;
|
||||
|
||||
oneway interface ILicensingService {
|
||||
void checkLicense(long nonce, String packageName, in ILicenseResultListener listener);
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.vending.licensing.LicenseCheckerCallback.ApplicationErrorCode;
|
||||
import com.android.vending.licensing.Policy.LicenseResponse;
|
||||
|
||||
/**
|
||||
* Client library for Android Market license verifications.
|
||||
*
|
||||
* The LicenseChecker is configured via a {@link Policy} which contains the
|
||||
* logic to determine whether a user should have access to the application.
|
||||
* For example, the Policy can define a threshold for allowable number of
|
||||
* server or client failures before the library reports the user as not having
|
||||
* access.
|
||||
*
|
||||
* This library is not thread-safe. Multiple, concurrent checks will result in
|
||||
* an error.
|
||||
*/
|
||||
public class LicenseChecker implements ServiceConnection {
|
||||
private static final String TAG = "LicenseChecker";
|
||||
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
|
||||
private ILicensingService mService;
|
||||
|
||||
/** Validator for the request in progress. */
|
||||
private LicenseValidator mValidator;
|
||||
|
||||
private final Context mContext;
|
||||
private final Policy mPolicy;
|
||||
/** Listener for service (IPC) calls. */
|
||||
private final ResultListener mListener;
|
||||
private final String mPackageName;
|
||||
private final String mVersionCode;
|
||||
|
||||
public LicenseChecker(Context context, Policy policy) {
|
||||
mContext = context;
|
||||
mPolicy = policy;
|
||||
mListener = new ResultListener();
|
||||
mPackageName = mContext.getPackageName();
|
||||
mVersionCode = getVersionCode(context, mPackageName);
|
||||
}
|
||||
|
||||
private boolean isInProgress() {
|
||||
return mValidator != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user should have access to the app.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
public synchronized void checkAccess(LicenseCheckerCallback callback) {
|
||||
if (isInProgress()) {
|
||||
callback.applicationError(ApplicationErrorCode.CHECK_IN_PROGRESS);
|
||||
}
|
||||
|
||||
mValidator = new LicenseValidator(mPolicy, callback, generateNonce(), mPackageName,
|
||||
mVersionCode);
|
||||
|
||||
Log.i(TAG, "Binding to licensing service.");
|
||||
boolean bindResult = mContext.bindService(new Intent(ILicensingService.class.getName()),
|
||||
this, // ServiceConnection.
|
||||
Context.BIND_AUTO_CREATE);
|
||||
|
||||
if (!bindResult) {
|
||||
Log.e(TAG, "Could not bind to service.");
|
||||
callback.dontAllow();
|
||||
// No need to unbind at this point.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private class ResultListener extends ILicenseResultListener.Stub {
|
||||
public void verifyLicense(int responseCode, String signedData, String signature) {
|
||||
mValidator.verify(responseCode, signedData, signature);
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
mService = ILicensingService.Stub.asInterface(service);
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Calling checkLicense on service for " + mValidator.getPackageName());
|
||||
mService.checkLicense(mValidator.getNonce(), mValidator.getPackageName(), mListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in checkLicense call.", e);
|
||||
handleServiceConnectionError();
|
||||
// cleanup unbinds service.
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
// Called when the connection with the service has been
|
||||
// unexpectedly disconnected. That is, Market crashed.
|
||||
Log.w(TAG, "Service unexpectedly disconnected.");
|
||||
handleServiceConnectionError();
|
||||
// cleanup unbinds service.
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private void handleServiceConnectionError() {
|
||||
if (mPolicy.allowAccess(LicenseResponse.CLIENT_RETRY)) {
|
||||
mValidator.getCallback().allow();
|
||||
} else {
|
||||
mValidator.getCallback().dontAllow();
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets request state. */
|
||||
private synchronized void cleanup() {
|
||||
mContext.unbindService(this);
|
||||
mValidator = null;
|
||||
}
|
||||
|
||||
/** Generates a nonce (number used once). */
|
||||
private int generateNonce() {
|
||||
return RANDOM.nextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get version code for the application package name.
|
||||
*
|
||||
* @param context
|
||||
* @param packageName application package name
|
||||
* @return the version code or empty string if package not found
|
||||
*/
|
||||
private static String getVersionCode(Context context, String packageName) {
|
||||
try {
|
||||
return String.valueOf(context.getPackageManager().getPackageInfo(packageName, 0).
|
||||
versionCode);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(TAG, "Package not found. could not get version code.");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
/**
|
||||
* Callback for the license checker library.
|
||||
*
|
||||
* Upon checking with the Market server and conferring with the policy, the
|
||||
* library calls a appropriate callback method to communicate the result.
|
||||
*/
|
||||
public interface LicenseCheckerCallback {
|
||||
|
||||
/**
|
||||
* Allow use. App should proceed as normal.
|
||||
*/
|
||||
public void allow();
|
||||
|
||||
/**
|
||||
* Don't allow use. App should inform user and take appropriate action.
|
||||
*/
|
||||
public void dontAllow();
|
||||
|
||||
/** Application error codes. */
|
||||
public enum ApplicationErrorCode {
|
||||
/** Package is not installed. */
|
||||
INVALID_PACKAGE_NAME,
|
||||
/** Requested for a package that is not the current app. */
|
||||
NON_MATCHING_UID,
|
||||
/** Market does not know about the package. */
|
||||
NOT_MARKET_MANAGED,
|
||||
/** A previous check request is already in progress.
|
||||
* Only one check is allowed at a time. */
|
||||
CHECK_IN_PROGRESS
|
||||
}
|
||||
|
||||
/**
|
||||
* Error in application code. Caller did not call or set up license
|
||||
* checker correctly. Should be considered fatal.
|
||||
*/
|
||||
public void applicationError(ApplicationErrorCode errorCode);
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.vending.licensing.LicenseCheckerCallback.ApplicationErrorCode;
|
||||
import com.android.vending.licensing.Policy.LicenseResponse;
|
||||
|
||||
/**
|
||||
* Contains data related to a licensing request and methods to verify
|
||||
* and process the response.
|
||||
*/
|
||||
class LicenseValidator {
|
||||
private static final String TAG = "LicenseValidator";
|
||||
|
||||
// Server response codes.
|
||||
private static final int LICENSED = 0x0;
|
||||
private static final int NOT_LICENSED = 0x1;
|
||||
private static final int LICENSED_OLD_KEY = 0x2;
|
||||
private static final int ERROR_NOT_MARKET_MANAGED = 0x3;
|
||||
private static final int ERROR_INVALID_KEYS = 0x4;
|
||||
private static final int ERROR_OVER_QUOTA = 0x5;
|
||||
|
||||
private static final int ERROR_CONTACTING_SERVER = 0x101;
|
||||
private static final int ERROR_INVALID_PACKAGE_NAME = 0x102;
|
||||
private static final int ERROR_NON_MATCHING_UID = 0x103;
|
||||
|
||||
private final Policy mPolicy;
|
||||
private final LicenseCheckerCallback mCallback;
|
||||
private final int mNonce;
|
||||
private final String mPackageName;
|
||||
private final String mVersionCode;
|
||||
|
||||
LicenseValidator(Policy policy, LicenseCheckerCallback callback, int nonce, String packageName,
|
||||
String versionCode) {
|
||||
mPolicy = policy;
|
||||
mCallback = callback;
|
||||
mNonce = nonce;
|
||||
mPackageName = packageName;
|
||||
mVersionCode = versionCode;
|
||||
}
|
||||
|
||||
public LicenseCheckerCallback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
public int getNonce() {
|
||||
return mNonce;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the response from server and calls appropriate callback method.
|
||||
*
|
||||
* @param responseCode server response code
|
||||
* @param signedData signed data from server
|
||||
* @param signature server signature
|
||||
*/
|
||||
public void verify(int responseCode, String signedData, String signature) {
|
||||
// Parse and validate response.
|
||||
// TODO(jyum): decode data with signature.
|
||||
// TODO(jyum): verify timestamp is within reason. However, relying
|
||||
// on device clock may lead to problems?
|
||||
ResponseData data;
|
||||
try {
|
||||
data = ResponseData.parse(signedData);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "Could not parse response.");
|
||||
handleInvalidResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.responseCode != responseCode) {
|
||||
Log.e(TAG, "Response codes don't match.");
|
||||
handleInvalidResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.nonce != mNonce) {
|
||||
Log.e(TAG, "Nonce doesn't match.");
|
||||
handleInvalidResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.packageName.equals(mPackageName)) {
|
||||
Log.e(TAG, "Package name doesn't match.");
|
||||
handleInvalidResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.versionCode.equals(mVersionCode)) {
|
||||
Log.e(TAG, "Version codes don't match.");
|
||||
handleInvalidResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (responseCode) {
|
||||
case LICENSED:
|
||||
case LICENSED_OLD_KEY:
|
||||
handleResponse(LicenseResponse.LICENSED);
|
||||
break;
|
||||
case NOT_LICENSED:
|
||||
handleResponse(LicenseResponse.NOT_LICENSED);
|
||||
break;
|
||||
case ERROR_CONTACTING_SERVER:
|
||||
handleResponse(LicenseResponse.CLIENT_RETRY);
|
||||
break;
|
||||
case ERROR_INVALID_KEYS:
|
||||
case ERROR_OVER_QUOTA:
|
||||
handleResponse(LicenseResponse.SERVER_RETRY);
|
||||
break;
|
||||
case ERROR_INVALID_PACKAGE_NAME:
|
||||
handleApplicationError(ApplicationErrorCode.INVALID_PACKAGE_NAME);
|
||||
break;
|
||||
case ERROR_NON_MATCHING_UID:
|
||||
handleApplicationError(ApplicationErrorCode.NON_MATCHING_UID);
|
||||
break;
|
||||
case ERROR_NOT_MARKET_MANAGED:
|
||||
handleApplicationError(ApplicationErrorCode.NOT_MARKET_MANAGED);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown response code for license check.");
|
||||
handleInvalidResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confers with policy and calls appropriate callback method.
|
||||
*
|
||||
* @param response
|
||||
*/
|
||||
private void handleResponse(LicenseResponse response) {
|
||||
if (mPolicy.allowAccess(response)) {
|
||||
mCallback.allow();
|
||||
} else {
|
||||
mCallback.dontAllow();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleApplicationError(ApplicationErrorCode code) {
|
||||
mCallback.applicationError(code);
|
||||
}
|
||||
|
||||
private void handleInvalidResponse() {
|
||||
mCallback.dontAllow();
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
/**
|
||||
* Policy used by {@link LicenseChecker} to determine whether a user should
|
||||
* have access to the application.
|
||||
*/
|
||||
public interface Policy {
|
||||
|
||||
/**
|
||||
* Result of a license check.
|
||||
*/
|
||||
public enum LicenseResponse {
|
||||
/**
|
||||
* User is licensed to use the app.
|
||||
*/
|
||||
LICENSED,
|
||||
/**
|
||||
* User is not licensed to use the app.
|
||||
*/
|
||||
NOT_LICENSED,
|
||||
/**
|
||||
* Retryable error on the client side e.g. no network.
|
||||
*/
|
||||
CLIENT_RETRY,
|
||||
/**
|
||||
* Retryable error on the server side e.g. application is over request
|
||||
* quota.
|
||||
*/
|
||||
SERVER_RETRY,
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the user should be allowed access.
|
||||
*
|
||||
* @param response result of the license check request
|
||||
* @return true iff access should be allowed
|
||||
*/
|
||||
boolean allowAccess(LicenseResponse response);
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* ResponseData from licensing server.
|
||||
*/
|
||||
class ResponseData {
|
||||
|
||||
public int responseCode;
|
||||
public int nonce;
|
||||
public String packageName;
|
||||
public String versionCode;
|
||||
public String userId;
|
||||
public long timestamp;
|
||||
/** Response-specific data. */
|
||||
public String extra;
|
||||
|
||||
/**
|
||||
* Parses response string into ResponseData.
|
||||
*
|
||||
* @param responseData response data string
|
||||
* @throws IllegalArgumentException upon parsing error
|
||||
* @return ResponseData object
|
||||
*/
|
||||
public static ResponseData parse(String responseData) {
|
||||
// Must parse out main response data and response-specific data.
|
||||
TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(':');
|
||||
splitter.setString(responseData);
|
||||
Iterator<String> it = splitter.iterator();
|
||||
if (!it.hasNext()) {
|
||||
throw new IllegalArgumentException("Blank response.");
|
||||
}
|
||||
final String mainData = it.next();
|
||||
|
||||
// Response-specific (extra) data is optional.
|
||||
String extraData = "";
|
||||
if (it.hasNext()) {
|
||||
extraData = it.next();
|
||||
}
|
||||
|
||||
String [] fields = TextUtils.split(mainData, Pattern.quote("|"));
|
||||
if (fields.length < 5) {
|
||||
throw new IllegalArgumentException("Wrong number of fields.");
|
||||
}
|
||||
|
||||
ResponseData data = new ResponseData();
|
||||
data.extra = extraData;
|
||||
data.responseCode = Integer.parseInt(fields[0]);
|
||||
data.nonce = Integer.parseInt(fields[1]);
|
||||
data.packageName = fields[2];
|
||||
data.versionCode = fields[3];
|
||||
// TODO(jyum): userId is not there yet.
|
||||
// data.userId = fields[4];
|
||||
data.timestamp = Long.parseLong(fields[4]);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TextUtils.join("|", new Object [] { responseCode, nonce, packageName, versionCode,
|
||||
userId, timestamp });
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.vending.licensing;
|
||||
|
||||
/**
|
||||
* Strict policy.
|
||||
*
|
||||
* Should never be used in a real application as it strictly disallows access
|
||||
* upon retryable errors such as no connection present.
|
||||
*/
|
||||
public class StrictPolicy implements Policy {
|
||||
|
||||
public boolean allowAccess(LicenseResponse response) {
|
||||
return LicenseResponse.LICENSED == response;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user