1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/** \file
18  This file consists of implementation of a class AdbObjectHandle that
19  encapsulates an internal API object that is visible to the outside
20  of the API through a handle.
21*/
22
23#include "stdafx.h"
24#include "adb_api.h"
25#include "adb_object_handle.h"
26
27/// Global ADBAPIHANDLE -> AdbObjectHandle* map
28AdbObjectHandleMap      the_map;
29
30/// Locker for the AdbObjectHandleMap instance
31CComAutoCriticalSection the_map_locker;
32
33/// Next adb handle value generator
34ULONG_PTR               next_adb_handle_value = 0;
35
36AdbObjectHandle::AdbObjectHandle(AdbObjectType obj_type)
37    : adb_handle_(NULL),
38      object_type_(obj_type),
39      ref_count_(1) {
40  ATLASSERT(obj_type < AdbObjectTypeMax);
41}
42
43AdbObjectHandle::~AdbObjectHandle() {
44  ATLASSERT(0 == ref_count_);
45  ATLASSERT(NULL == adb_handle_);
46}
47
48LONG AdbObjectHandle::AddRef() {
49  ATLASSERT(ref_count_ > 0);
50  return InterlockedIncrement(&ref_count_);
51}
52
53LONG AdbObjectHandle::Release() {
54  ATLASSERT(ref_count_ > 0);
55  LONG ret = InterlockedDecrement(&ref_count_);
56  ATLASSERT(ret >= 0);
57  if (0 == ret) {
58    LastReferenceReleased();
59    delete this;
60  }
61  return ret;
62}
63
64ADBAPIHANDLE AdbObjectHandle::CreateHandle() {
65  ADBAPIHANDLE ret = NULL;
66
67  // We have to hold this lock while we're dealing with the handle
68  // and the table
69  the_map_locker.Lock();
70
71  ATLASSERT(!IsOpened());
72
73  if (!IsOpened()) {
74    try {
75      // Generate next handle value
76      next_adb_handle_value++;
77      ret = reinterpret_cast<ADBAPIHANDLE>(next_adb_handle_value);
78
79      // Add ourselves to the map
80      the_map[ret] = this;
81
82      // Save handle, addref and return
83      adb_handle_ = ret;
84      AddRef();
85    } catch (...) {
86      ret = NULL;
87      SetLastError(ERROR_OUTOFMEMORY);
88    }
89  } else {
90    // Signaling that this object is already opened
91    SetLastError(ERROR_GEN_FAILURE);
92  }
93
94  the_map_locker.Unlock();
95
96  return ret;
97}
98
99bool AdbObjectHandle::CloseHandle() {
100  bool ret = false;
101
102  // Addref just in case that last reference to this object is being
103  // held in the map
104  AddRef();
105
106  the_map_locker.Lock();
107
108  ATLASSERT(IsOpened());
109
110  if (IsOpened()) {
111    try {
112      // Look us up in the map.
113      AdbObjectHandleMap::iterator found = the_map.find(adb_handle());
114      ATLASSERT((found != the_map.end()) && (this == found->second));
115
116      if ((found != the_map.end()) && (this == found->second)) {
117        // Remove ourselves from the map, close and release the object
118        the_map.erase(found);
119        adb_handle_ = NULL;
120        Release();
121        ret = true;
122      } else {
123        SetLastError(ERROR_INVALID_HANDLE);
124      }
125    } catch (...) {
126      ret = false;
127      SetLastError(ERROR_OUTOFMEMORY);
128    }
129  } else {
130    SetLastError(ERROR_INVALID_HANDLE);
131  }
132
133  the_map_locker.Unlock();
134
135  Release();
136
137  return ret;
138}
139
140bool AdbObjectHandle::IsObjectOfType(AdbObjectType obj_type) const {
141  return (obj_type == object_type());
142}
143
144void AdbObjectHandle::LastReferenceReleased() {
145  ATLASSERT(!IsOpened());
146}
147
148AdbObjectHandle* AdbObjectHandle::Lookup(ADBAPIHANDLE adb_hndl) {
149  AdbObjectHandle* ret = NULL;
150
151  the_map_locker.Lock();
152
153  try {
154    // Look us up in the map.
155    AdbObjectHandleMap::iterator found = the_map.find(adb_hndl);
156    if (found != the_map.end()) {
157      ret = found->second;
158      ret->AddRef();
159    }
160  } catch (...) {
161    SetLastError(ERROR_OUTOFMEMORY);
162  }
163
164  the_map_locker.Unlock();
165
166  return ret;
167}
168