/* * Tencent is pleased to support the open source community by making Tinker available. * * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * 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.tencent.tinker.lib.service; import android.app.IntentService; import android.app.Notification; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.IBinder; import android.os.SystemClock; import com.tencent.tinker.lib.patch.AbstractPatch; import com.tencent.tinker.lib.tinker.Tinker; import com.tencent.tinker.lib.util.TinkerLog; import com.tencent.tinker.loader.TinkerRuntimeException; import com.tencent.tinker.loader.shareutil.ShareConstants; import com.tencent.tinker.loader.shareutil.ShareIntentUtil; import java.io.File; /** * Created by zhangshaowen on 16/3/14. */ public class TinkerPatchService extends IntentService { private static final String TAG = "Tinker.TinkerPatchService"; private static final String PATCH_PATH_EXTRA = "patch_path_extra"; private static final String RESULT_CLASS_EXTRA = "patch_result_class"; private static AbstractPatch upgradePatchProcessor = null; private static int notificationId = ShareConstants.TINKER_PATCH_SERVICE_NOTIFICATION; private static Class<? extends AbstractResultService> resultServiceClass = null; /** * Creates an IntentService. Invoked by your subclass's constructor. */ public TinkerPatchService() { super(TinkerPatchService.class.getSimpleName()); } public static void runPatchService(Context context, String path) { try { Intent intent = new Intent(context, TinkerPatchService.class); intent.putExtra(PATCH_PATH_EXTRA, path); intent.putExtra(RESULT_CLASS_EXTRA, resultServiceClass.getName()); context.startService(intent); } catch (Throwable throwable) { TinkerLog.e(TAG, "start patch service fail, exception:" + throwable); } } public static void setPatchProcessor(AbstractPatch upgradePatch, Class<? extends AbstractResultService> serviceClass) { upgradePatchProcessor = upgradePatch; resultServiceClass = serviceClass; //try to load try { Class.forName(serviceClass.getName()); } catch (ClassNotFoundException e) { // e.printStackTrace(); } } public static String getPatchPathExtra(Intent intent) { if (intent == null) { throw new TinkerRuntimeException("getPatchPathExtra, but intent is null"); } return ShareIntentUtil.getStringExtra(intent, PATCH_PATH_EXTRA); } public static String getPatchResultExtra(Intent intent) { if (intent == null) { throw new TinkerRuntimeException("getPatchResultExtra, but intent is null"); } return ShareIntentUtil.getStringExtra(intent, RESULT_CLASS_EXTRA); } /** * set the tinker notification id you want * @param id */ public static void setTinkerNotificationId(int id) { notificationId = id; } @Override protected void onHandleIntent(Intent intent) { final Context context = getApplicationContext(); Tinker tinker = Tinker.with(context); tinker.getPatchReporter().onPatchServiceStart(intent); if (intent == null) { TinkerLog.e(TAG, "TinkerPatchService received a null intent, ignoring."); return; } String path = getPatchPathExtra(intent); if (path == null) { TinkerLog.e(TAG, "TinkerPatchService can't get the path extra, ignoring."); return; } File patchFile = new File(path); long begin = SystemClock.elapsedRealtime(); boolean result; long cost; Throwable e = null; increasingPriority(); PatchResult patchResult = new PatchResult(); try { if (upgradePatchProcessor == null) { throw new TinkerRuntimeException("upgradePatchProcessor is null."); } result = upgradePatchProcessor.tryPatch(context, path, patchResult); } catch (Throwable throwable) { e = throwable; result = false; tinker.getPatchReporter().onPatchException(patchFile, e); } cost = SystemClock.elapsedRealtime() - begin; tinker.getPatchReporter(). onPatchResult(patchFile, result, cost); patchResult.isSuccess = result; patchResult.rawPatchFilePath = path; patchResult.costTime = cost; patchResult.e = e; AbstractResultService.runResultService(context, patchResult, getPatchResultExtra(intent)); } private void increasingPriority() { // if (Build.VERSION.SDK_INT > 24) { // TinkerLog.i(TAG, "for Android 7.1, we just ignore increasingPriority job"); // return; // } TinkerLog.i(TAG, "try to increase patch process priority"); try { Notification notification = new Notification(); if (Build.VERSION.SDK_INT < 18) { startForeground(notificationId, notification); } else { startForeground(notificationId, notification); // start InnerService startService(new Intent(this, InnerService.class)); } } catch (Throwable e) { TinkerLog.i(TAG, "try to increase patch process priority error:" + e); } } /** * I don't want to do this, believe me */ //InnerService public static class InnerService extends Service { @Override public void onCreate() { super.onCreate(); try { startForeground(notificationId, new Notification()); } catch (Throwable e) { TinkerLog.e(TAG, "InnerService set service for push exception:%s.", e); } // kill stopSelf(); } @Override public void onDestroy() { stopForeground(true); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { return null; } } }